import type { AsrPluginInstance, AsrPluginOption, AudioChunk, RuntimeFactory, RuntimeOption, RuntimeResult } from 'artplayer-plugin-asr' import type { AudioChunk as EntryChunk, RuntimeFactory as EntryFactory, RuntimeOption as EntryOption, RuntimeResult as EntryResult } from 'artplayer-plugin-asr/runtime' import Artplayer from 'artplayer' import legacy from 'artplayer-plugin-asr' import * as namespace from 'artplayer-plugin-asr' import legacyEntry from 'artplayer-plugin-asr/legacy' import runtime from 'artplayer-plugin-asr/runtime' type Equal = (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? true : false type Assert = T type RuntimeEntryTypes = Assert> interface HistoricalOption { length?: number interval?: number sampleRate?: number autoHideTimeout?: number onAudioChunk?: (chunk: { pcm: ArrayBuffer, wav: ArrayBuffer }) => void | Promise } interface HistoricalResult { name: 'artplayerPluginAsr' stop: () => void hide: () => void append: (subtitle: string) => void } type HistoricalFactory = (option?: HistoricalOption) => (art: Artplayer) => HistoricalResult type RootArguments = Assert, [option?: AsrPluginOption]>> type RootOption = Assert> type RootResult = Assert>, AsrPluginInstance>> type RootShape = Assert> type RootFactory = Assert> type RootStop = Assert, void>> type ChunkShape = Assert> type PreciseArguments = Assert, [option?: RuntimeOption]>> type PreciseResult = Assert>, RuntimeResult>> type PreciseStop = Assert, Promise>> type PreciseFactory = Assert> type PreciseCallback = Assert, (chunk: AudioChunk) => string | void | null | Promise>> type PreciseAudioInput = Assert> type RootAudioInputAbsent = Assert, never>> const replacement: HistoricalFactory = (_option?: HistoricalOption) => (_art: Artplayer) => ({ name: 'artplayerPluginAsr', stop() {}, hide() {}, append(_subtitle: string) {}, }) const assignToOld: HistoricalFactory = legacy const assignFromOld: typeof legacy = replacement const namespaceFactory: HistoricalFactory = namespace.default const explicitLegacy: HistoricalFactory = legacyEntry const option: AsrPluginOption = { onAudioChunk: async (_chunk: AudioChunk): Promise => {} } const absent: Parameters[0] = undefined const art = new Artplayer({ container: '#player', url: '/video.mp4', plugins: [legacy(option), runtime(), legacyEntry(absent)] }) const old = legacy(option)(art) const oldReturns: void[] = [old.stop(), old.hide(), old.append('Subtitle.')] const bareRoot: typeof legacy = replacement const runtimeOption: RuntimeOption = { length: 2, interval: 250, sampleRate: 48000, autoHideTimeout: 3000, onAudioChunk: async (chunk) => { const pcm: ArrayBuffer = chunk.pcm const wav: ArrayBuffer = chunk.wav void [pcm, wav] return 'Recognized subtitle.' } } const correct: RuntimeResult = runtime(runtimeOption)(art) const stopped: Promise = correct.stop() const alias: RuntimeFactory = runtime.default.default const aliasResult: RuntimeResult = alias(undefined)(art) runtime({ onAudioChunk: () => 'Synchronous subtitle.' }) runtime({ onAudioChunk: () => null }) runtime({ onAudioChunk: () => undefined }) runtime({ onAudioChunk: async () => {} }) runtime({ onAudioChunk: async () => null }) runtime(option) const captureOption: RuntimeOption = { audioInput: { type: 'capture' } } const captureEntryOption: EntryOption = captureOption runtime(captureOption) runtime(captureEntryOption) runtime({ audioInput: { type: 'capture' }, onAudioChunk: async () => 'Captured main media.' }) // @ts-expect-error Only the explicit capture strategy is public. runtime({ audioInput: { type: 'direct' } }) // @ts-expect-error The strategy discriminator is required when audioInput is provided. runtime({ audioInput: {} }) // @ts-expect-error Audio input is a descriptor, not a string shorthand. runtime({ audioInput: 'capture' }) // @ts-expect-error Root options retain their historical fields without the runtime-only strategy. const rootCaptureOption: AsrPluginOption = { audioInput: { type: 'capture' } } // @ts-expect-error The historical factory does not expose runtime-only options. legacy({ audioInput: { type: 'capture' } }) // @ts-expect-error The explicit legacy entry also retains the historical option shape. legacyEntry({ audioInput: { type: 'capture' } }) // @ts-expect-error Root options preserve the historical void/Promise callback shape. legacy({ onAudioChunk: () => 'Only the precise entry describes returned subtitles.' }) // @ts-expect-error Root stop extraction remains void for historical replacement factories. const rootPromise: Promise = old.stop() // @ts-expect-error The legacy factory type must not demand or expose a self default alias. bareRoot.default() // @ts-expect-error Accurate stop is asynchronous. const synchronous: void = correct.stop() // @ts-expect-error Accurate result replacements cannot return void from stop. const wrongStop: RuntimeResult = { name: 'artplayerPluginAsr', stop() {}, hide() {}, append(_text: string) {} } // @ts-expect-error Callback results do not include booleans. runtime({ onAudioChunk: () => true }) // @ts-expect-error Async callback results do not include booleans. runtime({ onAudioChunk: async () => true }) // @ts-expect-error Options use numeric sample rates. runtime({ sampleRate: '16000' }) // @ts-expect-error Unknown options remain rejected. runtime({ unknown: true }) // @ts-expect-error Registration requires an Artplayer instance. runtime()() // @ts-expect-error Append accepts a string. correct.append(123) // @ts-expect-error PCM is an ArrayBuffer rather than encoded text. const invalidChunk: AudioChunk = { pcm: 'raw audio', wav: new ArrayBuffer(4) } void [assignToOld, assignFromOld, namespaceFactory, explicitLegacy, oldReturns, stopped, aliasResult, rootCaptureOption, rootPromise, synchronous, wrongStop, invalidChunk] export type { ChunkShape, PreciseArguments, PreciseAudioInput, PreciseCallback, PreciseFactory, PreciseResult, PreciseStop, RootArguments, RootAudioInputAbsent, RootFactory, RootOption, RootResult, RootShape, RootStop, RuntimeEntryTypes }