feat: add artplayer-plugin-audio-track for audio synchronization with video

- Implemented the audio track plugin for ArtPlayer, allowing audio to be synchronized with video playback.
- Added main functionality in `src/index.js` to handle audio playback, synchronization, and event listeners for play, pause, seek, and volume changes.
- Created TypeScript definitions for the plugin in `types/artplayer-plugin-audio-track.d.ts`.
- Included necessary build files in `dist/` for various module formats (CommonJS, ES Module, and legacy).
- Updated package metadata in `package.json` and added a README for documentation.
- Added `.npmignore` to exclude unnecessary files from the package.
This commit is contained in:
Harvey Zhao committed 2026-01-03 13:42:11 +08:00
1 parent ae03670f9a
commit a8d36a38ad
85 files changed
+702 -124

No files matched your search

@@ -0,0 +1,6 @@
node_modules
.DS_Store
.parcel-cache
yarn.lock
package-lock.json
src
@@ -0,0 +1,11 @@
# artplayer-plugin-audio-track
audio-track plugin for ArtPlayer
## Demo
[https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-audio-track/index.js&example=audio-track)
## License
MIT © Harvey Zack
@@ -0,0 +1,8 @@
/*!
* artplayer-plugin-audio-track.js v1.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zack
* Released under the MIT License.
*/
!function(e,r,t,o,n,u,i,a){var l="u">typeof globalThis?globalThis:"u">typeof self?self:"u">typeof window?window:"u">typeof global?global:{},f="function"==typeof l[o]&&l[o],c=f.i||{},d=f.cache||{},p="u">typeof module&&"function"==typeof module.require&&module.require.bind(module);function s(r,t){if(!d[r]){if(!e[r]){if(n[r])return n[r];var u="function"==typeof l[o]&&l[o];if(!t&&u)return u(r,!0);if(f)return f(r,!0);if(p&&"string"==typeof r)return p(r);var i=Error("Cannot find module '"+r+"'");throw i.code="MODULE_NOT_FOUND",i}c.resolve=function(t){var o=e[r][1][t];return null!=o?o:t},c.cache={};var a=d[r]=new s.Module(r);e[r][0].call(a.exports,c,a,a.exports,l)}return d[r].exports;function c(e){var r=c.resolve(e);if(!1===r)return{};if(Array.isArray(r)){var t={__esModule:!0};return r.forEach(function(e){var r=e[0],o=e[1],n=e[2]||e[0],u=s(o);"*"===r?Object.keys(u).forEach(function(e){"default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:function(){return u[e]}})}):"*"===n?Object.defineProperty(t,r,{enumerable:!0,value:u}):Object.defineProperty(t,r,{enumerable:!0,get:function(){return"default"===n?u.__esModule?u.default:u:u[n]}})}),t}return s(r)}}s.isParcelRequire=!0,s.Module=function(e){this.id=e,this.bundle=s,this.require=p,this.exports={}},s.modules=e,s.cache=d,s.parent=f,s.distDir=void 0,s.publicUrl=void 0,s.devServer=void 0,s.i=c,s.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]},Object.defineProperty(s,"root",{get:function(){return l[o]}}),l[o]=s;for(var y=0;y<r.length;y++)s(r[y]);if(t){var b=s(t);"object"==typeof exports&&"u">typeof module?module.exports=b:"function"==typeof define&&define.amd&&define(function(){return b})}}({b4T6O:[function(e,r,t,o){var n=e("@parcel/transformer-js/src/esmodule-helpers.js");function u(e){return r=>{let{url:t,offset:o=0,sync:n=.3}=e;if(!t)return{name:"artplayerPluginAudioTrack"};let u=new Audio;function i(){if(!r.video)return;let e=r.currentTime+o;Math.abs(u.currentTime-e)>n&&(u.currentTime=e)}return u.src=t,u.preload="auto",r.on("play",()=>{i(),u.play().catch(e=>{console.warn(e)})}),r.on("pause",()=>{u.pause()}),r.on("seek",()=>{i()}),r.on("video:timeupdate",()=>{r.playing&&i()}),r.on("video:ratechange",()=>{u.playbackRate=r.video.playbackRate}),r.on("video:volumechange",()=>{u.volume=r.volume,u.muted=r.muted}),r.on("destroy",()=>{u.pause(),u.src="",u.load()}),u.volume=r.volume,u.muted=r.muted,u.playbackRate=r.video?.playbackRate||1,{name:"artplayerPluginAudioTrack",audio:u}}}n.defineInteropFlag(t),n.export(t,"default",()=>u),"u">typeof window&&(window.artplayerPluginAudioTrack=u)},{"@parcel/transformer-js/src/esmodule-helpers.js":"6ykb1"}],"6ykb1":[function(e,r,t,o){t.interopDefault=function(e){return e&&e.__esModule?e:{default:e}},t.defineInteropFlag=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.exportAll=function(e,r){return Object.keys(e).forEach(function(t){"default"===t||"__esModule"===t||Object.prototype.hasOwnProperty.call(r,t)||Object.defineProperty(r,t,{enumerable:!0,get:function(){return e[t]}})}),r},t.export=function(e,r,t){Object.defineProperty(e,r,{enumerable:!0,get:t})}},{}]},["b4T6O"],"b4T6O","parcelRequire4dc0",{});
@@ -0,0 +1,8 @@
/*!
* artplayer-plugin-audio-track.js v1.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zack
* Released under the MIT License.
*/
!function(e,r,t,n,o,u,i,a){var f="u">typeof globalThis?globalThis:"u">typeof self?self:"u">typeof window?window:"u">typeof global?global:{},l="function"==typeof f[n]&&f[n],c=l.i||{},d=l.cache||{},p="u">typeof module&&"function"==typeof module.require&&module.require.bind(module);function s(r,t){if(!d[r]){if(!e[r]){if(o[r])return o[r];var u="function"==typeof f[n]&&f[n];if(!t&&u)return u(r,!0);if(l)return l(r,!0);if(p&&"string"==typeof r)return p(r);var i=Error("Cannot find module '"+r+"'");throw i.code="MODULE_NOT_FOUND",i}c.resolve=function(t){var n=e[r][1][t];return null!=n?n:t},c.cache={};var a=d[r]=new s.Module(r);e[r][0].call(a.exports,c,a,a.exports,f)}return d[r].exports;function c(e){var r=c.resolve(e);if(!1===r)return{};if(Array.isArray(r)){var t={__esModule:!0};return r.forEach(function(e){var r=e[0],n=e[1],o=e[2]||e[0],u=s(n);"*"===r?Object.keys(u).forEach(function(e){"default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:function(){return u[e]}})}):"*"===o?Object.defineProperty(t,r,{enumerable:!0,value:u}):Object.defineProperty(t,r,{enumerable:!0,get:function(){return"default"===o?u.__esModule?u.default:u:u[o]}})}),t}return s(r)}}s.isParcelRequire=!0,s.Module=function(e){this.id=e,this.bundle=s,this.require=p,this.exports={}},s.modules=e,s.cache=d,s.parent=l,s.distDir=void 0,s.publicUrl=void 0,s.devServer=void 0,s.i=c,s.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]},Object.defineProperty(s,"root",{get:function(){return f[n]}}),f[n]=s;for(var y=0;y<r.length;y++)s(r[y]);if(t){var v=s(t);"object"==typeof exports&&"u">typeof module?module.exports=v:"function"==typeof define&&define.amd&&define(function(){return v})}}({"8tkGC":[function(e,r,t,n){var o=e("@parcel/transformer-js/src/esmodule-helpers.js");function u(e){return function(r){var t,n=e.url,o=e.offset,u=void 0===o?0:o,i=e.sync,a=void 0===i?.3:i;if(!n)return{name:"artplayerPluginAudioTrack"};var f=new Audio;function l(){if(r.video){var e=r.currentTime+u;Math.abs(f.currentTime-e)>a&&(f.currentTime=e)}}return f.src=n,f.preload="auto",r.on("play",function(){l(),f.play().catch(function(e){console.warn(e)})}),r.on("pause",function(){f.pause()}),r.on("seek",function(){l()}),r.on("video:timeupdate",function(){r.playing&&l()}),r.on("video:ratechange",function(){f.playbackRate=r.video.playbackRate}),r.on("video:volumechange",function(){f.volume=r.volume,f.muted=r.muted}),r.on("destroy",function(){f.pause(),f.src="",f.load()}),f.volume=r.volume,f.muted=r.muted,f.playbackRate=(null==(t=r.video)?void 0:t.playbackRate)||1,{name:"artplayerPluginAudioTrack",audio:f}}}o.defineInteropFlag(t),o.export(t,"default",function(){return u}),"u">typeof window&&(window.artplayerPluginAudioTrack=u)},{"@parcel/transformer-js/src/esmodule-helpers.js":"qpMMf"}],qpMMf:[function(e,r,t,n){t.interopDefault=function(e){return e&&e.__esModule?e:{default:e}},t.defineInteropFlag=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.exportAll=function(e,r){return Object.keys(e).forEach(function(t){"default"===t||"__esModule"===t||Object.prototype.hasOwnProperty.call(r,t)||Object.defineProperty(r,t,{enumerable:!0,get:function(){return e[t]}})}),r},t.export=function(e,r,t){Object.defineProperty(e,r,{enumerable:!0,get:t})}},{}]},["8tkGC"],"8tkGC","parcelRequire4dc0",{});
@@ -0,0 +1,8 @@
/*!
* artplayer-plugin-audio-track.js v1.0.0
* Github: https://github.com/zhw2590582/ArtPlayer
* (c) 2017-2026 Harvey Zack
* Released under the MIT License.
*/
!function(e,r,t,o,n,u,i,a){var l="u">typeof globalThis?globalThis:"u">typeof self?self:"u">typeof window?window:"u">typeof global?global:{},f="function"==typeof l[o]&&l[o],c=f.i||{},d=f.cache||{},p="u">typeof module&&"function"==typeof module.require&&module.require.bind(module);function s(r,t){if(!d[r]){if(!e[r]){if(n[r])return n[r];var u="function"==typeof l[o]&&l[o];if(!t&&u)return u(r,!0);if(f)return f(r,!0);if(p&&"string"==typeof r)return p(r);var i=Error("Cannot find module '"+r+"'");throw i.code="MODULE_NOT_FOUND",i}c.resolve=function(t){var o=e[r][1][t];return null!=o?o:t},c.cache={};var a=d[r]=new s.Module(r);e[r][0].call(a.exports,c,a,a.exports,l)}return d[r].exports;function c(e){var r=c.resolve(e);if(!1===r)return{};if(Array.isArray(r)){var t={__esModule:!0};return r.forEach(function(e){var r=e[0],o=e[1],n=e[2]||e[0],u=s(o);"*"===r?Object.keys(u).forEach(function(e){"default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:function(){return u[e]}})}):"*"===n?Object.defineProperty(t,r,{enumerable:!0,value:u}):Object.defineProperty(t,r,{enumerable:!0,get:function(){return"default"===n?u.__esModule?u.default:u:u[n]}})}),t}return s(r)}}s.isParcelRequire=!0,s.Module=function(e){this.id=e,this.bundle=s,this.require=p,this.exports={}},s.modules=e,s.cache=d,s.parent=f,s.distDir=void 0,s.publicUrl=void 0,s.devServer=void 0,s.i=c,s.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]},Object.defineProperty(s,"root",{get:function(){return l[o]}}),l[o]=s;for(var y=0;y<r.length;y++)s(r[y]);if(t){var m=s(t);"object"==typeof exports&&"u">typeof module?module.exports=m:"function"==typeof define&&define.amd&&define(function(){return m})}}({fHO26:[function(e,r,t,o){var n=e("@parcel/transformer-js/src/esmodule-helpers.js");function u(e){return r=>{let{url:t,offset:o=0,sync:n=.3}=e;if(!t)return{name:"artplayerPluginAudioTrack"};let u=new Audio;function i(){if(!r.video)return;let e=r.currentTime+o;Math.abs(u.currentTime-e)>n&&(u.currentTime=e)}return u.src=t,u.preload="auto",r.on("play",()=>{i(),u.play().catch(e=>{console.warn(e)})}),r.on("pause",()=>{u.pause()}),r.on("seek",()=>{i()}),r.on("video:timeupdate",()=>{r.playing&&i()}),r.on("video:ratechange",()=>{u.playbackRate=r.video.playbackRate}),r.on("video:volumechange",()=>{u.volume=r.volume,u.muted=r.muted}),r.on("destroy",()=>{u.pause(),u.src="",u.load()}),u.volume=r.volume,u.muted=r.muted,u.playbackRate=r.video?.playbackRate||1,{name:"artplayerPluginAudioTrack",audio:u}}}n.defineInteropFlag(t),n.export(t,"default",()=>u),"u">typeof window&&(window.artplayerPluginAudioTrack=u)},{"@parcel/transformer-js/src/esmodule-helpers.js":"loqXi"}],loqXi:[function(e,r,t,o){t.interopDefault=function(e){return e&&e.__esModule?e:{default:e}},t.defineInteropFlag=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.exportAll=function(e,r){return Object.keys(e).forEach(function(t){"default"===t||"__esModule"===t||Object.prototype.hasOwnProperty.call(r,t)||Object.defineProperty(r,t,{enumerable:!0,get:function(){return e[t]}})}),r},t.export=function(e,r,t){Object.defineProperty(e,r,{enumerable:!0,get:t})}},{}]},["fHO26"],"fHO26","parcelRequire4dc0",{});let{default:e}=parcelRequire4dc0("fHO26");export{e as default};
@@ -0,0 +1,38 @@
{
"name": "artplayer-plugin-audio-track",
"version": "1.0.0",
"description": "audio-track plugin for ArtPlayer",
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
"license": "MIT",
"homepage": "https://artplayer.org",
"repository": {
"type": "git",
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
},
"bugs": {
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
},
"keywords": [
"html5",
"video",
"player"
],
"exports": {
".": {
"types": "./types/artplayer-plugin-audio-track.d.ts",
"import": "./dist/artplayer-plugin-audio-track.mjs",
"require": "./dist/artplayer-plugin-audio-track.js"
},
"./legacy": {
"types": "./types/artplayer-plugin-audio-track.d.ts",
"import": "./dist/artplayer-plugin-audio-track.legacy.js",
"require": "./dist/artplayer-plugin-audio-track.legacy.js"
}
},
"main": "dist/artplayer-plugin-audio-track.js",
"module": "./dist/artplayer-plugin-audio-track.mjs",
"types": "types/artplayer-plugin-audio-track.d.ts",
"legacy": "dist/artplayer-plugin-audio-track.legacy.js",
"browserslist": "last 1 Chrome version"
}
@@ -0,0 +1,76 @@
export default function artplayerPluginAudioTrack(option) {
return (art) => {
const { url, offset = 0, sync = 0.3 } = option
if (!url) {
return {
name: 'artplayerPluginAudioTrack',
}
}
const audio = new Audio()
audio.src = url
audio.preload = 'auto'
function syncAudio() {
if (!art.video)
return
const videoTime = art.currentTime
const targetTime = videoTime + offset
if (Math.abs(audio.currentTime - targetTime) > sync) {
audio.currentTime = targetTime
}
}
art.on('play', () => {
syncAudio()
audio.play().catch((err) => {
console.warn(err)
})
})
art.on('pause', () => {
audio.pause()
})
art.on('seek', () => {
syncAudio()
})
art.on('video:timeupdate', () => {
if (art.playing) {
syncAudio()
}
})
art.on('video:ratechange', () => {
audio.playbackRate = art.video.playbackRate
})
art.on('video:volumechange', () => {
audio.volume = art.volume
audio.muted = art.muted
})
art.on('destroy', () => {
audio.pause()
audio.src = ''
audio.load()
})
audio.volume = art.volume
audio.muted = art.muted
audio.playbackRate = art.video?.playbackRate || 1
return {
name: 'artplayerPluginAudioTrack',
audio,
}
}
}
if (typeof window !== 'undefined') {
window.artplayerPluginAudioTrack = artplayerPluginAudioTrack
}
@@ -0,0 +1,34 @@
import type Artplayer from 'artplayer'
interface Option {
/**
* Audio track URL
*/
url: string
/**
* Time offset in seconds between video and audio
* Positive value means audio plays ahead of video
* Negative value means audio plays behind video
* @default 0
*/
offset?: number
/**
* Synchronization threshold in seconds
* @default 0.3
*/
sync?: number
}
interface Result {
name: 'artplayerPluginAudioTrack'
/**
* The audio element
*/
audio: HTMLAudioElement
}
declare const artplayerPluginAudioTrack: (option: Option) => (art: Artplayer) => Result
export default artplayerPluginAudioTrack