mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-22 21:31:20 -08:00
refactor(audio): [PKG-AUDIO-04] migrate strict source and compatible type entries
This commit is contained in:
1 parent
9c07ea830c
commit
13c898c149
31 files changed
+18923
-90
No files matched your search
@@ -2,4 +2,5 @@ node_modules
|
||||
.DS_Store
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
src
|
||||
src
|
||||
tsconfig.json
|
||||
@@ -1,16 +1,17 @@
|
||||
# Audio Track maintenance
|
||||
|
||||
The default factory in src/index.js keeps the public `(option) => (art) => result`
|
||||
The default factory in src/index.ts keeps the public `(option) => (art) => result`
|
||||
contract. The result exposes the same HTMLAudioElement for its entire lifetime, a
|
||||
literal name, and synchronous update. Public declarations remain authored in types/
|
||||
until the separate type migration; do not infer new public methods from internal helpers.
|
||||
literal name, and synchronous update. Public declarations are authored in types/ and checked
|
||||
against the strict source by test/types/audio-track-source.ts. Do not infer public methods
|
||||
from internal helpers. Both source files are strict TS without ambient Node types or any escapes.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
- src/index.js owns ArtPlayer subscriptions, reads host media/volume/rate, adapts public
|
||||
- src/index.ts owns ArtPlayer subscriptions, reads host media/volume/rate, adapts public
|
||||
update, and rolls back partial installation. It uses only on/off and existing media
|
||||
properties, so it does not require new core lifecycle utilities.
|
||||
- src/track.js creates the Audio element and owns URL/offset/threshold and closed state.
|
||||
- src/track.ts creates the Audio element and owns URL/offset/threshold and closed state.
|
||||
It handles synchronization, play rejection and source updates. It does not import ArtPlayer,
|
||||
inspect DOM registries or install listeners. Dependencies flow from the entry to the track.
|
||||
|
||||
@@ -39,7 +40,7 @@ change; their remaining media validation is tracked in refactor/audio-validation
|
||||
|
||||
## Change and verify
|
||||
|
||||
Edit track.js for URL/sync/media ownership and index.js for host event handling. Keep
|
||||
Edit track.ts for URL/sync/media ownership and index.ts for host event handling. Keep
|
||||
published-only defect observations in the tests when adding candidate regressions.
|
||||
|
||||
```sh
|
||||
@@ -55,4 +56,29 @@ source. These are explicit local artifacts, not isolated installed npm packages.
|
||||
The browser suite includes frozen old core/plugin combinations, real AAC/decoded video,
|
||||
source failure recovery, and old/native pause/end plus corrected candidate cleanup.
|
||||
See refactor/audio-validation.md for failed baseline probes, Windows WebKit WAV/size limits,
|
||||
physical-device gaps and the separate 04/05/06 type/combination/distribution gates.
|
||||
physical-device gaps and the remaining 05/06 combination/distribution gates.
|
||||
|
||||
## Public type compatibility
|
||||
|
||||
The default and /legacy entries preserve the original Result.update(Option) signature,
|
||||
including required URL inference in Parameters and contextual mock implementations.
|
||||
Simply widening that argument or adding overloads broke verified old consumers, even though
|
||||
ordinary old calls still compiled. Do not reintroduce that change without these fixtures.
|
||||
|
||||
The additive /runtime entry points to the exact same JS/mjs files and exposes RuntimeFactory
|
||||
and RuntimeResult.update(UpdateOption), where UpdateOption is Partial<Option>. It does not
|
||||
add a second player/plugin implementation. Result remains the legacy result type; RuntimeResult
|
||||
is the opt-in precise update contract. Both keep factory options required and update synchronous.
|
||||
The .d.cts/.d.mts bridges describe actual CJS/ESM identities; typesVersions keeps old Node10
|
||||
resolution for /legacy and /runtime. TS 4.3 and 5.9 consumers exercise both paths.
|
||||
|
||||
The editor global keeps legacy inference, with an explicit RuntimeFactory type assertion for
|
||||
scripts opting into partial-update inference. The assertion selects a contract checked against
|
||||
the same implementation; it does not bypass the plugin's strict source checks. build:ts uses
|
||||
the shared AST generator for this package and rejects standalone declaration diagnostics in
|
||||
both compilers. Do not manually edit docs/assets/ts output.
|
||||
|
||||
The package .npmignore excludes the implementation tsconfig along with src. Yarn pack must
|
||||
retain all six declaration files and every historical dist/type path. Audio-04 verified these
|
||||
files and identical JavaScript bytes to Audio-03; isolated installed consumers and the 8082
|
||||
demo still belong to Audio-06. See refactor/baselines/audio-types-validation.json for evidence.
|
||||
@@ -4,7 +4,40 @@ audio-track plugin for ArtPlayer
|
||||
|
||||
## Demo
|
||||
|
||||
[https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-audio-track/index.js&example=audio-track)
|
||||
[https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-audio-track/index.js&example=audio.track)
|
||||
|
||||
## TypeScript
|
||||
|
||||
The default import and `/legacy` preserve existing TypeScript behavior, including the
|
||||
historical required `url` in the `update` parameter type. JavaScript still supports updating
|
||||
only selected fields. Use `/runtime` for precise partial-update types; it loads the same
|
||||
implementation and adds no runtime dependency:
|
||||
|
||||
```ts
|
||||
import Artplayer from 'artplayer'
|
||||
import audioTrack from 'artplayer-plugin-audio-track/runtime'
|
||||
|
||||
const installTrack = audioTrack({ url: '/assets/sample/sprite-fight.aac' })
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/sprite-fight.mp4',
|
||||
plugins: [(art) => {
|
||||
const track = installTrack(art)
|
||||
track.update({ offset: 0.25 })
|
||||
return track
|
||||
}],
|
||||
})
|
||||
```
|
||||
|
||||
Named types include `Option`, `UpdateOption`, `Result` (legacy), `RuntimeResult`, and
|
||||
`RuntimeFactory`. `update` returns `void`; `audio` remains the same `HTMLAudioElement`.
|
||||
For global scripts in the online editor, explicitly opt into the same precise typing with
|
||||
`artplayerPluginAudioTrack as artplayerPluginAudioTrack.RuntimeFactory`.
|
||||
|
||||
The plugin follows the main video's playback, volume and rate, but does not automatically
|
||||
mute the main video. Destroying ArtPlayer releases the plugin's audio and subscriptions;
|
||||
retained plugin updates become inert. See [ARCHITECTURE.md](ARCHITECTURE.md) for module
|
||||
ownership, compatibility decisions and regression commands.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -19,19 +19,49 @@
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/artplayer-plugin-audio-track.d.ts",
|
||||
"import": "./dist/artplayer-plugin-audio-track.mjs",
|
||||
"require": "./dist/artplayer-plugin-audio-track.js"
|
||||
"import": {
|
||||
"types": "./types/artplayer-plugin-audio-track.d.mts",
|
||||
"default": "./dist/artplayer-plugin-audio-track.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-plugin-audio-track.d.cts",
|
||||
"default": "./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"
|
||||
"import": {
|
||||
"types": "./types/artplayer-plugin-audio-track.d.cts",
|
||||
"default": "./dist/artplayer-plugin-audio-track.legacy.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-plugin-audio-track.d.cts",
|
||||
"default": "./dist/artplayer-plugin-audio-track.legacy.js"
|
||||
}
|
||||
},
|
||||
"./runtime": {
|
||||
"import": {
|
||||
"types": "./types/runtime/index.d.mts",
|
||||
"default": "./dist/artplayer-plugin-audio-track.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/runtime/index.d.cts",
|
||||
"default": "./dist/artplayer-plugin-audio-track.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"
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"legacy": [
|
||||
"types/artplayer-plugin-audio-track.d.ts"
|
||||
],
|
||||
"runtime": [
|
||||
"types/runtime/index.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-7
@@ -1,10 +1,14 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Option, RuntimeResult, UpdateOption } from '../types/artplayer-plugin-audio-track'
|
||||
import { createAudioTrack } from './track'
|
||||
|
||||
export default function artplayerPluginAudioTrack(option) {
|
||||
return (art) => {
|
||||
type AudioEvent = 'play' | 'pause' | 'seek' | 'destroy' | 'video:pause' | 'video:ended' | 'video:waiting' | 'video:emptied' | 'video:seeking' | 'video:seeked' | 'video:timeupdate' | 'video:ratechange' | 'video:volumechange' | 'video:playing'
|
||||
|
||||
export default function artplayerPluginAudioTrack(option: Option) {
|
||||
return (art: Artplayer): RuntimeResult => {
|
||||
const track = createAudioTrack(option)
|
||||
const { audio } = track
|
||||
const subscriptions = []
|
||||
const subscriptions: [AudioEvent, () => void][] = []
|
||||
let active = true
|
||||
|
||||
function syncAudio() {
|
||||
@@ -12,7 +16,7 @@ export default function artplayerPluginAudioTrack(option) {
|
||||
track.sync(art.currentTime)
|
||||
}
|
||||
|
||||
function listen(event, callback) {
|
||||
function listen(event: AudioEvent, callback: () => void) {
|
||||
const listener = () => {
|
||||
if (active)
|
||||
callback()
|
||||
@@ -25,7 +29,7 @@ export default function artplayerPluginAudioTrack(option) {
|
||||
if (!active)
|
||||
return
|
||||
active = false
|
||||
const failures = []
|
||||
const failures: unknown[] = []
|
||||
for (const [event, listener] of subscriptions.splice(0)) {
|
||||
try {
|
||||
art.off(event, listener)
|
||||
@@ -45,7 +49,7 @@ export default function artplayerPluginAudioTrack(option) {
|
||||
syncAudio()
|
||||
track.play()
|
||||
})
|
||||
for (const event of ['pause', 'video:pause', 'video:ended', 'video:waiting', 'video:emptied', 'video:seeking'])
|
||||
for (const event of ['pause', 'video:pause', 'video:ended', 'video:waiting', 'video:emptied', 'video:seeking'] as const)
|
||||
listen(event, track.pause)
|
||||
listen('seek', syncAudio)
|
||||
listen('video:seeked', () => {
|
||||
@@ -86,7 +90,7 @@ export default function artplayerPluginAudioTrack(option) {
|
||||
return {
|
||||
name: 'artplayerPluginAudioTrack',
|
||||
audio,
|
||||
update(newOption) {
|
||||
update(newOption: UpdateOption) {
|
||||
if (active)
|
||||
track.update(newOption, art.playing)
|
||||
},
|
||||
+7
-5
@@ -1,4 +1,6 @@
|
||||
export function createAudioTrack(option) {
|
||||
import type { Option, UpdateOption } from '../types/artplayer-plugin-audio-track'
|
||||
|
||||
export function createAudioTrack(option: Option) {
|
||||
let { url, offset = 0, sync = 0.3 } = option
|
||||
const audio = new Audio()
|
||||
let closed = false
|
||||
@@ -6,7 +8,7 @@ export function createAudioTrack(option) {
|
||||
function play() {
|
||||
if (closed || !url)
|
||||
return
|
||||
audio.play().catch((error) => {
|
||||
audio.play().catch((error: unknown) => {
|
||||
if (!closed)
|
||||
console.warn(error)
|
||||
})
|
||||
@@ -21,7 +23,7 @@ export function createAudioTrack(option) {
|
||||
if (closed)
|
||||
return
|
||||
closed = true
|
||||
const failures = []
|
||||
const failures: unknown[] = []
|
||||
for (const release of [() => audio.pause(), () => audio.removeAttribute('src'), () => audio.load()]) {
|
||||
try {
|
||||
release()
|
||||
@@ -50,14 +52,14 @@ export function createAudioTrack(option) {
|
||||
play,
|
||||
pause,
|
||||
destroy,
|
||||
sync(time) {
|
||||
sync(time: number) {
|
||||
if (closed || !url)
|
||||
return
|
||||
const target = time + offset
|
||||
if (Math.abs(audio.currentTime - target) > sync)
|
||||
audio.currentTime = target
|
||||
},
|
||||
update(newOption, playing) {
|
||||
update(newOption: UpdateOption, playing: boolean) {
|
||||
if (closed)
|
||||
return
|
||||
if (newOption.url && newOption.url !== url) {
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": { "allowJs": false },
|
||||
"include": ["src/**/*.ts", "types/**/*.d.ts", "types/**/*.d.mts", "types/**/*.d.cts"]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/* eslint-disable ts/no-redeclare -- CommonJS callable export and named-type namespace intentionally merge. */
|
||||
import type * as Definition from './artplayer-plugin-audio-track.js'
|
||||
|
||||
declare const artplayerPluginAudioTrack: typeof Definition.default
|
||||
|
||||
declare namespace artplayerPluginAudioTrack {
|
||||
type Option = Definition.Option
|
||||
type UpdateOption = Definition.UpdateOption
|
||||
type Result = Definition.Result
|
||||
type RuntimeResult = Definition.RuntimeResult
|
||||
type RuntimeFactory = Definition.RuntimeFactory
|
||||
}
|
||||
|
||||
export = artplayerPluginAudioTrack
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default } from './artplayer-plugin-audio-track.cjs'
|
||||
export type { Option, Result, RuntimeFactory, RuntimeResult, UpdateOption } from './artplayer-plugin-audio-track.js'
|
||||
+15
-4
@@ -1,6 +1,6 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
|
||||
interface Option {
|
||||
export interface Option {
|
||||
/**
|
||||
* Audio track URL
|
||||
*/
|
||||
@@ -21,7 +21,9 @@ interface Option {
|
||||
sync?: number
|
||||
}
|
||||
|
||||
interface Result {
|
||||
export type UpdateOption = Partial<Option>
|
||||
|
||||
export interface Result {
|
||||
name: 'artplayerPluginAudioTrack'
|
||||
/**
|
||||
* The audio element
|
||||
@@ -29,11 +31,20 @@ interface Result {
|
||||
audio: HTMLAudioElement
|
||||
|
||||
/**
|
||||
* Update option
|
||||
* Historical update signature. Runtime also accepts partial options.
|
||||
* Import the /runtime entry for the precise partial-update signature.
|
||||
*/
|
||||
update: (option: Option) => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginAudioTrack: (option: Option) => (art: Artplayer) => Result
|
||||
export interface RuntimeResult extends Result {
|
||||
/** Update selected fields without replacing the audio element. */
|
||||
update: (option: UpdateOption) => void
|
||||
}
|
||||
|
||||
/** Precise typing for the same runtime factory, without changing legacy inference. */
|
||||
export type RuntimeFactory = (option: Option) => (art: Artplayer) => RuntimeResult
|
||||
|
||||
declare function artplayerPluginAudioTrack(option: Option): (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginAudioTrack
|
||||
@@ -0,0 +1,14 @@
|
||||
/* eslint-disable ts/no-redeclare -- CommonJS callable export and named-type namespace intentionally merge. */
|
||||
import type * as Definition from '../artplayer-plugin-audio-track.js'
|
||||
|
||||
declare const artplayerPluginAudioTrack: Definition.RuntimeFactory
|
||||
|
||||
declare namespace artplayerPluginAudioTrack {
|
||||
type Option = Definition.Option
|
||||
type UpdateOption = Definition.UpdateOption
|
||||
type Result = Definition.Result
|
||||
type RuntimeResult = Definition.RuntimeResult
|
||||
type RuntimeFactory = Definition.RuntimeFactory
|
||||
}
|
||||
|
||||
export = artplayerPluginAudioTrack
|
||||
@@ -0,0 +1,2 @@
|
||||
export type { Option, Result, RuntimeFactory, RuntimeResult, UpdateOption } from '../artplayer-plugin-audio-track.js'
|
||||
export { default } from './index.cjs'
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { RuntimeFactory } from '../artplayer-plugin-audio-track'
|
||||
|
||||
declare const artplayerPluginAudioTrack: RuntimeFactory
|
||||
export default artplayerPluginAudioTrack
|
||||
export type { Option, Result, RuntimeFactory, RuntimeResult, UpdateOption } from '../artplayer-plugin-audio-track'
|
||||
Reference in new issue
Block a user