mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
- Created a new documentation file for the danmuku plugin with interactive code execution. - Added comprehensive i18n setup instructions, including default language settings, language imports, and examples for adding and modifying languages. - Introduced a test file to verify the integration of the danmuku plugin.
1 line
34 KiB
Plaintext
1 line
34 KiB
Plaintext
{"mappings":"C,A,S,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,E,I,E,A,a,O,W,W,A,a,O,K,K,A,a,O,O,O,A,a,O,O,O,C,E,E,A,Y,O,C,C,E,E,C,C,E,C,E,E,C,E,C,E,E,E,K,E,C,E,E,A,a,O,Q,A,Y,O,O,O,E,O,O,C,I,C,Q,S,E,C,C,C,E,G,C,C,C,E,C,C,G,C,C,C,E,C,C,G,C,C,E,C,O,C,C,E,C,I,E,A,Y,O,C,C,E,E,C,C,E,C,G,C,G,E,O,E,E,C,G,G,E,O,E,E,C,G,G,G,A,U,O,E,O,E,G,I,E,A,M,uB,E,I,O,E,I,C,mB,C,C,E,O,C,S,C,E,I,E,C,C,E,C,E,C,E,C,O,A,M,E,E,C,E,E,K,C,C,E,I,E,C,C,E,C,I,E,M,C,G,C,C,E,C,E,C,I,C,E,O,C,E,E,E,O,C,E,C,O,C,C,E,C,O,C,S,E,C,E,I,E,E,O,C,G,M,A,C,I,E,C,E,E,E,C,C,E,e,C,C,E,E,M,C,S,C,E,I,C,E,C,E,I,C,M,C,E,I,C,O,C,E,I,C,O,C,C,C,E,E,O,C,E,E,K,C,E,E,M,C,E,E,O,C,K,E,E,S,C,K,E,E,S,C,K,E,E,C,C,E,E,Q,C,S,C,C,C,E,C,C,E,C,C,S,C,C,C,E,E,O,C,C,E,C,E,A,E,O,c,C,E,O,C,I,W,O,C,C,E,A,C,G,C,C,E,C,E,I,I,E,E,E,E,M,C,I,E,C,C,E,E,G,E,C,I,E,E,E,A,C,U,O,S,A,a,O,O,O,O,C,E,A,Y,O,Q,O,G,E,O,W,O,C,E,C,E,C,Q,C,S,C,C,C,C,C,C,C,E,I,E,E,kD,E,iB,C,GCEwB,EAAA,MAAA,CAAA,EAAA,UAAA,IAAA,GAFxB,IAAA,EAAA,EAAA,4B,E,E,c,C,GAEe,SAAS,EAAmB,EAAS,CAAC,CAAC,EACpD,GAAM,CACJ,OAAA,EAAS,CAAC,CACV,SAAA,EAAW,GAAG,CACd,WAAA,EAAa,IAAK,CAClB,gBAAA,EAAkB,GAAK,CACvB,aAAA,EAAe,IAAM,IAAI,CAC1B,CAAG,EAEJ,OAAO,AAAC,IACN,IAAI,EAAU,CAAA,EACV,EAAW,KACX,EAAa,KACb,EAAe,KACf,EAAW,KACX,EAAe,EAAE,CACjB,EAAQ,KACR,EAAgB,CAAA,EAChB,EAAY,KACZ,EAAc,KACd,EAAoB,KAElB,EAAO,EAAI,MAAM,CAAC,GAAG,CAAC,CAC1B,KAAM,MACN,KAAM,EACR,GAaA,SAAS,IACP,EAAK,KAAK,CAAC,OAAO,CAAG,MACvB,CAEA,SAAS,EAAO,CAAQ,EAClB,AAAoB,UAApB,OAAO,IAEX,aAAa,GACb,EAAY,WAAW,EAAM,GAC7B,EAAK,KAAK,CAAC,OAAO,CAAG,GACrB,EAAK,SAAS,CAAG,AAnBf,AAmBkC,EAjB/B,KAAK,CAAC,sBACN,GAAG,CAAC,AAAA,GAAK,EAAE,IAAI,IACf,MAAM,CAAC,SACP,KAAK,CAAC,CAAC,GAeT,GAAG,CAAC,AAAA,GAAQ,CAAC,0BAA0B,EAAE,EAAK,MAAM,CAAC,EACrD,IAAI,CAAC,IACV,CAEA,IAAM,EAAwB;A;A;A;A;A;A;A;A;A;A;AAW1B,QAAA,CAAC,CAgDL,eAAe,WACT,GAGA,AAAmB,cAAnB,AADJ,CAAA,EAAW,GAAK,CAAA,OAAO,YAAY,EAAI,OAAO,kBAAkB,AAAlB,EAAoB,CAAE,WAAA,CAAW,EAAA,EAClE,KAAK,EAChB,MAAM,EAAS,MAAM,GAHd,CAKX,CAEA,eAAe,IACb,GAAI,CAAC,GAAc,EAAI,KAAK,CAC1B,GAAI,CAEF,OADA,EAAa,EAAS,wBAAwB,CAAC,EAAI,KAAK,CAE1D,CACA,MAAO,EAAK,CACV,QAAQ,IAAI,CAAC,iDAAkD,EACjE,CAGF,GAAI,CAIF,GAHI,AAAC,GACH,CAAA,EAAc,MAAM,EAAsB,EAAI,KAAK,CAAA,EAEjD,EAEF,OADA,EAAoB,EAAS,uBAAuB,CAAC,EAGzD,CACA,MAAO,EAAK,CACV,QAAQ,IAAI,CAAC,oDAAqD,EACpE,CAEA,OAAO,IACT,CAEA,eAAe,EAAsB,CAAY,EAC/C,GAAI,CACF,GAAI,EAAa,aAAa,CAC5B,OAAO,EAAa,aAAa,GACnC,GAAI,EAAa,gBAAgB,CAC/B,OAAO,EAAa,gBAAgB,GAEtC,OADA,QAAQ,IAAI,CAAC,oDACN,IACT,CACA,MAAO,EAAK,CAEV,OADA,QAAQ,IAAI,CAAC,+CAAgD,GACtD,IACT,CACF,CAEA,eAAe,IACb,IAAI,EAGJ,GAAI,CACF,MAAM,IACN,IAAM,EAAc,MAAM,IAC1B,GAAI,CAAC,EACH,MAAM,AAAI,MAAM,oCAElB,GAAI,CAAC,EAAe,CAClB,IAAM,EAAU,AA5GO,CAAA,KAC3B,IAAM,EAAO,IAAI,KAAK,CAAC,EAAsB,CAAE,CAAE,KAAM,wBAAyB,GAChF,OAAO,IAAI,eAAe,CAAC,EAC7B,CAAA,GA0GM,OAAM,EAAS,YAAY,CAAC,SAAS,CAAC,GACtC,IAAI,eAAe,CAAC,GACpB,EAAgB,CAAA,CAClB,CAGA,AADA,CAAA,EAAW,EAAS,UAAU,EAA9B,EACS,IAAI,CAAC,KAAK,CAAG,EAEtB,AADA,CAAA,EAAe,IAAI,iBAAiB,EAAU,qBAA9C,EACa,IAAI,CAAC,SAAS,CAAG,AAAC,IAC7B,EAAa,IAAI,CAAC,IAAI,aAAa,EAAM,IAAI,EAC/C,EACA,EAAY,OAAO,CAAC,GACpB,EAAY,OAAO,CAAC,GACpB,EAAS,OAAO,CAAC,EAAS,WAAW,EAErC,IAAM,EAAgB,AAAc,EAAW,IAAzB,EACtB,EAAQ,YAAY,UAClB,GAAI,AAAwB,IAAxB,EAAa,MAAM,CACrB,OAEF,IAAI,EAAc,IAAI,aAAa,GACnC,KAAO,EAAY,MAAM,CAAG,GAAiB,EAAa,MAAM,EAAE,CAChE,IAAM,EAAO,EAAa,KAAK,GACzB,EAAM,IAAI,aAAa,EAAY,MAAM,CAAG,EAAK,MAAM,EAC7D,EAAI,GAAG,CAAC,EAAa,GACrB,EAAI,GAAG,CAAC,EAAM,EAAY,MAAM,EAChC,EAAc,CAChB,CAEA,GAAI,EAAY,MAAM,CAAG,EACvB,OAEF,IAAM,EAAc,EAAY,KAAK,CAAC,EAAG,GACnC,EAAM,AAzIlB,SAAyB,CAAY,EACnC,IAAM,EAAM,EAAa,MAAM,CACzB,EAAS,IAAI,YAAY,AAAM,EAAN,GACzB,EAAO,IAAI,SAAS,GAC1B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,IAAK,CAC5B,IAAM,EAAI,KAAK,GAAG,CAAC,GAAI,KAAK,GAAG,CAAC,EAAG,CAAY,CAAC,EAAE,GAClD,EAAK,QAAQ,CAAC,AAAI,EAAJ,EAAO,EAAI,EAAI,AAAI,MAAJ,EAAa,AAAI,MAAJ,EAAY,CAAA,EACxD,CACA,OAAO,CACT,EAgIkC,GACtB,EAAM,AA/HlB,SAAkB,CAAS,CAAE,CAAU,EACrC,IAAM,EAAY,EAAU,UAAU,CAChC,EAAY,IAAI,YAAY,GAAK,GACjC,EAAO,IAAI,SAAS,GAEpB,EAAc,CAAC,EAAQ,KAC3B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAI,MAAM,CAAE,IAC9B,EAAK,QAAQ,CAAC,EAAS,EAAG,EAAI,UAAU,CAAC,GAE7C,EAkBA,OAhBA,EAAY,EAAG,QACf,EAAK,SAAS,CAAC,EAAG,GAAK,EAAW,CAAA,GAClC,EAAY,EAAG,QACf,EAAY,GAAI,QAChB,EAAK,SAAS,CAAC,GAAI,GAAI,CAAA,GACvB,EAAK,SAAS,CAAC,GAAI,EAAG,CAAA,GACtB,EAAK,SAAS,CAAC,GAAI,EAAG,CAAA,GACtB,EAAK,SAAS,CAAC,GAAI,EAAY,CAAA,GAC/B,EAAK,SAAS,CAAC,GAAI,AAAa,EAAb,EAAgB,CAAA,GACnC,EAAK,SAAS,CAAC,GAAI,EAAG,CAAA,GACtB,EAAK,SAAS,CAAC,GAAI,GAAI,CAAA,GACvB,EAAY,GAAI,QAChB,EAAK,SAAS,CAAC,GAAI,EAAW,CAAA,GAE9B,IAAI,WAAW,GAAW,GAAG,CAAC,IAAI,WAAW,GAAY,IAElD,CACT,EAmG2B,EAAK,GACpB,EAAW,MAAM,EAAa,CAAE,IAAA,EAAK,IAAA,CAAI,GAC/C,EAAO,EACT,EAAG,GAEH,EAAU,CAAA,CACZ,CACA,MAAO,EAAK,CACV,QAAQ,KAAK,CAAC,8CAA+C,GAC7D,MAAM,GACR,CACF,CAEA,eAAe,IACR,IAEL,EAAU,CAAA,EAEV,cAAc,GACd,EAAQ,KAEJ,IACF,EAAa,UAAU,GACvB,EAAa,IAAI,CAAC,SAAS,CAAG,KAC9B,EAAe,MAGb,IACF,EAAS,UAAU,GACnB,EAAW,MAGb,EAAe,EAAE,CACnB,CAEA,eAAe,IACb,MAAM,IAEF,IACF,EAAkB,UAAU,GAC5B,EAAoB,MAGlB,IACF,EAAW,UAAU,GACrB,EAAa,MAGX,IACF,EAAY,SAAS,GAAG,OAAO,CAAC,AAAA,GAAS,EAAM,IAAI,IACnD,EAAc,MAGZ,IACF,MAAM,EAAS,KAAK,GACpB,EAAW,MAGb,EAAgB,CAAA,CAClB,CAYA,OAVA,EAAI,EAAE,CAAC,qBAAsB,KACvB,GACF,CAAA,EAAS,IAAI,CAAC,KAAK,CAAG,EAAI,MAAM,AAAN,CAE9B,GAEA,EAAI,EAAE,CAAC,OAAQ,GACf,EAAI,EAAE,CAAC,QAAS,GAChB,EAAI,EAAE,CAAC,UAAW,GAEX,CACL,KAAM,qBACN,KAAM,EACN,KAAA,EACA,OAAA,CACF,CACF,CACF,CAEA,GAAI,AAAoB,aAApB,OAAO,UACL,CAAC,SAAS,cAAc,CAAC,wBAAyB,CACpD,IAAM,EAAS,SAAS,aAAa,CAAC,QACtC,CAAA,EAAO,EAAE,CAAG,uBACZ,EAAO,WAAW,CAAG,EAAA,OAAK,CAC1B,SAAS,IAAI,CAAC,WAAW,CAAC,EAC5B,CAGE,AAAkB,aAAlB,OAAO,QACT,CAAA,OAAO,kBAAkB,CAAG,CAD9B,C,E,C,2B,Q,iD,O,E,C,M,C,S,C,C,C,C,C,C,C,EC5SA,EAAO,OAAO,CAAG,qvB,E,C,E,C,Q,C,S,C,C,C,C,C,C,C,ECAjB,EAAQ,cAAc,CAAG,SAAU,CAAC,EAClC,OAAO,GAAK,EAAE,UAAU,CAAG,EAAI,CAAC,QAAS,CAAC,CAC5C,EAEA,EAAQ,iBAAiB,CAAG,SAAU,CAAC,EACrC,OAAO,cAAc,CAAC,EAAG,aAAc,CAAC,MAAO,CAAA,CAAI,EACrD,EAEA,EAAQ,SAAS,CAAG,SAAU,CAAM,CAAE,CAAI,EAkBxC,OAjBA,OAAO,IAAI,CAAC,GAAQ,OAAO,CAAC,SAAU,CAAG,EAE7B,YAAR,GACA,AAAQ,eAAR,GACA,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,EAAM,IAK7C,OAAO,cAAc,CAAC,EAAM,EAAK,CAC/B,WAAY,CAAA,EACZ,IAAK,WACH,OAAO,CAAM,CAAC,EAAI,AACpB,CACF,EACF,GAEO,CACT,EAEA,EAAQ,MAAM,CAAG,SAAU,CAAI,CAAE,CAAQ,CAAE,CAAG,EAC5C,OAAO,cAAc,CAAC,EAAM,EAAU,CACpC,WAAY,CAAA,EACZ,IAAK,CACP,EACF,C,E,C,E,E,C,Q,C,Q,oB,C,G,G,C,Q,C,C,C,kB,gB,K,O","sources":["<anon>","packages/artplayer-plugin-asr/src/index.js","node_modules/@parcel/runtime-js/lib/bundles/runtime-8d01a8f56d551fc8.js","node_modules/@parcel/transformer-js/src/esmodule-helpers.js"],"sourcesContent":["// modules are defined as an array\n// [ module function, map of requires ]\n//\n// map of requires is short require name -> numeric require\n//\n// anything defined in a previous bundle is accessed via the\n// orig method which is the require for previous bundles\n\n(function (\n modules,\n entry,\n mainEntry,\n parcelRequireName,\n externals,\n distDir,\n publicUrl,\n devServer\n) {\n /* eslint-disable no-undef */\n var globalObject =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n /* eslint-enable no-undef */\n\n // Save the require from previous bundle to this closure if any\n var previousRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n\n var importMap = previousRequire.i || {};\n var cache = previousRequire.cache || {};\n // Do not use `require` to prevent Webpack from trying to bundle this call\n var nodeRequire =\n typeof module !== 'undefined' &&\n typeof module.require === 'function' &&\n module.require.bind(module);\n\n function newRequire(name, jumped) {\n if (!cache[name]) {\n if (!modules[name]) {\n if (externals[name]) {\n return externals[name];\n }\n // if we cannot find the module within our internal map or\n // cache jump to the current global require ie. the last bundle\n // that was added to the page.\n var currentRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n if (!jumped && currentRequire) {\n return currentRequire(name, true);\n }\n\n // If there are other bundles on this page the require from the\n // previous one is saved to 'previousRequire'. Repeat this as\n // many times as there are bundles until the module is found or\n // we exhaust the require chain.\n if (previousRequire) {\n return previousRequire(name, true);\n }\n\n // Try the node require function if it exists.\n if (nodeRequire && typeof name === 'string') {\n return nodeRequire(name);\n }\n\n var err = new Error(\"Cannot find module '\" + name + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n }\n\n localRequire.resolve = resolve;\n localRequire.cache = {};\n\n var module = (cache[name] = new newRequire.Module(name));\n\n modules[name][0].call(\n module.exports,\n localRequire,\n module,\n module.exports,\n globalObject\n );\n }\n\n return cache[name].exports;\n\n function localRequire(x) {\n var res = localRequire.resolve(x);\n return res === false ? {} : newRequire(res);\n }\n\n function resolve(x) {\n var id = modules[name][1][x];\n return id != null ? id : x;\n }\n }\n\n function Module(moduleName) {\n this.id = moduleName;\n this.bundle = newRequire;\n this.require = nodeRequire;\n this.exports = {};\n }\n\n newRequire.isParcelRequire = true;\n newRequire.Module = Module;\n newRequire.modules = modules;\n newRequire.cache = cache;\n newRequire.parent = previousRequire;\n newRequire.distDir = distDir;\n newRequire.publicUrl = publicUrl;\n newRequire.devServer = devServer;\n newRequire.i = importMap;\n newRequire.register = function (id, exports) {\n modules[id] = [\n function (require, module) {\n module.exports = exports;\n },\n {},\n ];\n };\n\n // Only insert newRequire.load when it is actually used.\n // The code in this file is linted against ES5, so dynamic import is not allowed.\n // INSERT_LOAD_HERE\n\n Object.defineProperty(newRequire, 'root', {\n get: function () {\n return globalObject[parcelRequireName];\n },\n });\n\n globalObject[parcelRequireName] = newRequire;\n\n for (var i = 0; i < entry.length; i++) {\n newRequire(entry[i]);\n }\n\n if (mainEntry) {\n // Expose entry point to Node, AMD or browser globals\n // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js\n var mainExports = newRequire(mainEntry);\n\n // CommonJS\n if (typeof exports === 'object' && typeof module !== 'undefined') {\n module.exports = mainExports;\n\n // RequireJS\n } else if (typeof define === 'function' && define.amd) {\n define(function () {\n return mainExports;\n });\n }\n }\n})({\"40eeC\":[function(require,module,exports,__globalThis) {\nvar parcelHelpers = require(\"@parcel/transformer-js/src/esmodule-helpers.js\");\nparcelHelpers.defineInteropFlag(exports);\nparcelHelpers.export(exports, \"default\", ()=>artplayerPluginAsr);\nvar _styleLess = require(\"bundle-text:./style.less\");\nvar _styleLessDefault = parcelHelpers.interopDefault(_styleLess);\nfunction artplayerPluginAsr(option = {}) {\n const { length = 3, interval = 100, sampleRate = 16000, autoHideTimeout = 10000, onAudioChunk = ()=>null } = option;\n return (art)=>{\n let started = false;\n let audioCtx = null;\n let sourceNode = null;\n let recorderNode = null;\n let gainNode = null;\n let bufferChunks = [];\n let timer = null;\n let workletLoaded = false;\n let hideTimer = null;\n let mediaStream = null;\n let mediaStreamSource = null;\n const $asr = art.layers.add({\n name: 'asr',\n html: ''\n });\n function splitByPunctuation(text) {\n return text.split(/(?<=[、。!?!?.])\\s*/u).map((s)=>s.trim()).filter(Boolean).slice(-length);\n }\n function hide() {\n $asr.style.display = 'none';\n }\n function append(subtitle) {\n if (typeof subtitle !== 'string') return;\n clearTimeout(hideTimer);\n hideTimer = setTimeout(hide, autoHideTimeout);\n $asr.style.display = '';\n $asr.innerHTML = splitByPunctuation(subtitle).map((line)=>`<div class=\"art-asr-line\">${line}</div>`).join('');\n }\n const recorderProcessorCode = `\n class RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n }\n registerProcessor('recorder-processor', RecorderProcessor);\n `;\n const createWorkletBlobUrl = ()=>{\n const blob = new Blob([\n recorderProcessorCode\n ], {\n type: 'application/javascript'\n });\n return URL.createObjectURL(blob);\n };\n function floatTo16BitPCM(float32Array) {\n const len = float32Array.length;\n const buffer = new ArrayBuffer(len * 2);\n const view = new DataView(buffer);\n for(let i = 0; i < len; i++){\n const s = Math.max(-1, Math.min(1, float32Array[i]));\n view.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7FFF, true);\n }\n return buffer;\n }\n function pcmToWav(pcmBuffer, sampleRate) {\n const pcmLength = pcmBuffer.byteLength;\n const wavBuffer = new ArrayBuffer(44 + pcmLength);\n const view = new DataView(wavBuffer);\n const writeString = (offset, str)=>{\n for(let i = 0; i < str.length; i++)view.setUint8(offset + i, str.charCodeAt(i));\n };\n writeString(0, 'RIFF');\n view.setUint32(4, 36 + pcmLength, true);\n writeString(8, 'WAVE');\n writeString(12, 'fmt ');\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, 1, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, sampleRate * 2, true);\n view.setUint16(32, 2, true);\n view.setUint16(34, 16, true);\n writeString(36, 'data');\n view.setUint32(40, pcmLength, true);\n new Uint8Array(wavBuffer).set(new Uint8Array(pcmBuffer), 44);\n return wavBuffer;\n }\n async function setupAudioContext() {\n if (audioCtx) return audioCtx;\n audioCtx = new (window.AudioContext || window.webkitAudioContext)({\n sampleRate\n });\n if (audioCtx.state === 'suspended') await audioCtx.resume();\n return audioCtx;\n }\n async function setupAudioSource() {\n if (!sourceNode && art.video) try {\n sourceNode = audioCtx.createMediaElementSource(art.video);\n return sourceNode;\n } catch (err) {\n console.warn('[artplayerPluginAsr] Direct connection failed:', err);\n }\n try {\n if (!mediaStream) mediaStream = await captureAudioFromVideo(art.video);\n if (mediaStream) {\n mediaStreamSource = audioCtx.createMediaStreamSource(mediaStream);\n return mediaStreamSource;\n }\n } catch (err) {\n console.warn('[artplayerPluginAsr] MediaStream fallback failed:', err);\n }\n return null;\n }\n async function captureAudioFromVideo(videoElement) {\n try {\n if (videoElement.captureStream) return videoElement.captureStream();\n if (videoElement.mozCaptureStream) return videoElement.mozCaptureStream();\n console.warn('[artplayerPluginAsr] captureStream not supported');\n return null;\n } catch (err) {\n console.warn('[artplayerPluginAsr] Error capturing stream:', err);\n return null;\n }\n }\n async function startCapture() {\n if (started) return;\n try {\n await setupAudioContext();\n const audioSource = await setupAudioSource();\n if (!audioSource) throw new Error('Could not establish audio source');\n if (!workletLoaded) {\n const blobUrl = createWorkletBlobUrl();\n await audioCtx.audioWorklet.addModule(blobUrl);\n URL.revokeObjectURL(blobUrl);\n workletLoaded = true;\n }\n gainNode = audioCtx.createGain();\n gainNode.gain.value = 1;\n recorderNode = new AudioWorkletNode(audioCtx, 'recorder-processor');\n recorderNode.port.onmessage = (event)=>{\n bufferChunks.push(new Float32Array(event.data));\n };\n audioSource.connect(recorderNode);\n audioSource.connect(gainNode);\n gainNode.connect(audioCtx.destination);\n const CHUNK_SAMPLES = sampleRate * (interval / 1000);\n timer = setInterval(async ()=>{\n if (bufferChunks.length === 0) return;\n let accumulated = new Float32Array(0);\n while(accumulated.length < CHUNK_SAMPLES && bufferChunks.length){\n const next = bufferChunks.shift();\n const tmp = new Float32Array(accumulated.length + next.length);\n tmp.set(accumulated, 0);\n tmp.set(next, accumulated.length);\n accumulated = tmp;\n }\n if (accumulated.length < CHUNK_SAMPLES) return;\n const chunkToSend = accumulated.slice(0, CHUNK_SAMPLES);\n const pcm = floatTo16BitPCM(chunkToSend);\n const wav = pcmToWav(pcm, sampleRate);\n const subtitle = await onAudioChunk({\n pcm,\n wav\n });\n append(subtitle);\n }, interval);\n started = true;\n } catch (err) {\n console.error('[artplayerPluginAsr] Initialization failed:', err);\n await stopCapture();\n }\n }\n async function stopCapture() {\n if (!started) return;\n started = false;\n clearInterval(timer);\n timer = null;\n if (recorderNode) {\n recorderNode.disconnect();\n recorderNode.port.onmessage = null;\n recorderNode = null;\n }\n if (gainNode) {\n gainNode.disconnect();\n gainNode = null;\n }\n bufferChunks = [];\n }\n async function destroy() {\n await stopCapture();\n if (mediaStreamSource) {\n mediaStreamSource.disconnect();\n mediaStreamSource = null;\n }\n if (sourceNode) {\n sourceNode.disconnect();\n sourceNode = null;\n }\n if (mediaStream) {\n mediaStream.getTracks().forEach((track)=>track.stop());\n mediaStream = null;\n }\n if (audioCtx) {\n await audioCtx.close();\n audioCtx = null;\n }\n workletLoaded = false;\n }\n art.on('video:volumechange', ()=>{\n if (gainNode) gainNode.gain.value = art.volume;\n });\n art.on('play', startCapture);\n art.on('pause', stopCapture);\n art.on('destroy', destroy);\n return {\n name: 'artplayerPluginAsr',\n stop: destroy,\n hide,\n append\n };\n };\n}\nif (typeof document !== 'undefined') {\n if (!document.getElementById('artplayer-plugin-asr')) {\n const $style = document.createElement('style');\n $style.id = 'artplayer-plugin-asr';\n $style.textContent = (0, _styleLessDefault.default);\n document.head.appendChild($style);\n }\n}\nif (typeof window !== 'undefined') window.artplayerPluginAsr = artplayerPluginAsr;\n\n},{\"bundle-text:./style.less\":\"dKHY3\",\"@parcel/transformer-js/src/esmodule-helpers.js\":\"5lQoW\"}],\"dKHY3\":[function(require,module,exports,__globalThis) {\nmodule.exports = \".art-video-player .art-layer-asr{z-index:150;justify-content:end;gap:var(--art-subtitle-gap);padding:0 2%;padding-bottom:var(--art-subtitle-bottom);transition:padding-bottom var(--art-transition-duration)ease;text-shadow:var(--art-subtitle-border)1px 0 1px,var(--art-subtitle-border)0 1px 1px,var(--art-subtitle-border)-1px 0 1px,var(--art-subtitle-border)0 -1px 1px,var(--art-subtitle-border)1px 1px 1px,var(--art-subtitle-border)-1px -1px 1px,var(--art-subtitle-border)1px -1px 1px,var(--art-subtitle-border)-1px 1px 1px;flex-direction:column;font-size:1rem;display:flex;position:absolute;inset:0;pointer-events:none!important}.art-video-player.art-control-show .art-layer-asr{padding-bottom:calc(var(--art-control-height) + var(--art-subtitle-bottom))}\";\n\n},{}],\"5lQoW\":[function(require,module,exports,__globalThis) {\nexports.interopDefault = function(a) {\n return a && a.__esModule ? a : {\n default: a\n };\n};\nexports.defineInteropFlag = function(a) {\n Object.defineProperty(a, '__esModule', {\n value: true\n });\n};\nexports.exportAll = function(source, dest) {\n Object.keys(source).forEach(function(key) {\n if (key === 'default' || key === '__esModule' || Object.prototype.hasOwnProperty.call(dest, key)) return;\n Object.defineProperty(dest, key, {\n enumerable: true,\n get: function() {\n return source[key];\n }\n });\n });\n return dest;\n};\nexports.export = function(dest, destName, get) {\n Object.defineProperty(dest, destName, {\n enumerable: true,\n get: get\n });\n};\n\n},{}]},[\"40eeC\"], \"40eeC\", \"parcelRequire4dc0\", {})\nlet {default: _default, } = parcelRequire4dc0(\"40eeC\");\nexport {_default as default, };\n\n//# sourceMappingURL=index.js.map\n","import style from 'bundle-text:./style.less'\n\nexport default function artplayerPluginAsr(option = {}) {\n const {\n length = 3,\n interval = 100,\n sampleRate = 16000,\n autoHideTimeout = 10000,\n onAudioChunk = () => null,\n } = option\n\n return (art) => {\n let started = false\n let audioCtx = null\n let sourceNode = null\n let recorderNode = null\n let gainNode = null\n let bufferChunks = []\n let timer = null\n let workletLoaded = false\n let hideTimer = null\n let mediaStream = null\n let mediaStreamSource = null\n\n const $asr = art.layers.add({\n name: 'asr',\n html: '',\n })\n\n function splitByPunctuation(text) {\n return (\n text\n\n .split(/(?<=[、。!?!?.])\\s*/u)\n .map(s => s.trim())\n .filter(Boolean)\n .slice(-length)\n )\n }\n\n function hide() {\n $asr.style.display = 'none'\n }\n\n function append(subtitle) {\n if (typeof subtitle !== 'string')\n return\n clearTimeout(hideTimer)\n hideTimer = setTimeout(hide, autoHideTimeout)\n $asr.style.display = ''\n $asr.innerHTML = splitByPunctuation(subtitle)\n .map(line => `<div class=\"art-asr-line\">${line}</div>`)\n .join('')\n }\n\n const recorderProcessorCode = `\n class RecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n const input = inputs[0];\n if (input && input[0]) {\n this.port.postMessage(input[0]);\n }\n return true;\n }\n }\n registerProcessor('recorder-processor', RecorderProcessor);\n `\n\n const createWorkletBlobUrl = () => {\n const blob = new Blob([recorderProcessorCode], { type: 'application/javascript' })\n return URL.createObjectURL(blob)\n }\n\n function floatTo16BitPCM(float32Array) {\n const len = float32Array.length\n const buffer = new ArrayBuffer(len * 2)\n const view = new DataView(buffer)\n for (let i = 0; i < len; i++) {\n const s = Math.max(-1, Math.min(1, float32Array[i]))\n view.setInt16(i * 2, s < 0 ? s * 0x8000 : s * 0x7FFF, true)\n }\n return buffer\n }\n\n function pcmToWav(pcmBuffer, sampleRate) {\n const pcmLength = pcmBuffer.byteLength\n const wavBuffer = new ArrayBuffer(44 + pcmLength)\n const view = new DataView(wavBuffer)\n\n const writeString = (offset, str) => {\n for (let i = 0; i < str.length; i++) {\n view.setUint8(offset + i, str.charCodeAt(i))\n }\n }\n\n writeString(0, 'RIFF')\n view.setUint32(4, 36 + pcmLength, true)\n writeString(8, 'WAVE')\n writeString(12, 'fmt ')\n view.setUint32(16, 16, true)\n view.setUint16(20, 1, true)\n view.setUint16(22, 1, true)\n view.setUint32(24, sampleRate, true)\n view.setUint32(28, sampleRate * 2, true)\n view.setUint16(32, 2, true)\n view.setUint16(34, 16, true)\n writeString(36, 'data')\n view.setUint32(40, pcmLength, true)\n\n new Uint8Array(wavBuffer).set(new Uint8Array(pcmBuffer), 44)\n\n return wavBuffer\n }\n\n async function setupAudioContext() {\n if (audioCtx)\n return audioCtx\n audioCtx = new (window.AudioContext || window.webkitAudioContext)({ sampleRate })\n if (audioCtx.state === 'suspended')\n await audioCtx.resume()\n return audioCtx\n }\n\n async function setupAudioSource() {\n if (!sourceNode && art.video) {\n try {\n sourceNode = audioCtx.createMediaElementSource(art.video)\n return sourceNode\n }\n catch (err) {\n console.warn('[artplayerPluginAsr] Direct connection failed:', err)\n }\n }\n\n try {\n if (!mediaStream) {\n mediaStream = await captureAudioFromVideo(art.video)\n }\n if (mediaStream) {\n mediaStreamSource = audioCtx.createMediaStreamSource(mediaStream)\n return mediaStreamSource\n }\n }\n catch (err) {\n console.warn('[artplayerPluginAsr] MediaStream fallback failed:', err)\n }\n\n return null\n }\n\n async function captureAudioFromVideo(videoElement) {\n try {\n if (videoElement.captureStream)\n return videoElement.captureStream()\n if (videoElement.mozCaptureStream)\n return videoElement.mozCaptureStream()\n console.warn('[artplayerPluginAsr] captureStream not supported')\n return null\n }\n catch (err) {\n console.warn('[artplayerPluginAsr] Error capturing stream:', err)\n return null\n }\n }\n\n async function startCapture() {\n if (started)\n return\n\n try {\n await setupAudioContext()\n const audioSource = await setupAudioSource()\n if (!audioSource)\n throw new Error('Could not establish audio source')\n\n if (!workletLoaded) {\n const blobUrl = createWorkletBlobUrl()\n await audioCtx.audioWorklet.addModule(blobUrl)\n URL.revokeObjectURL(blobUrl)\n workletLoaded = true\n }\n\n gainNode = audioCtx.createGain()\n gainNode.gain.value = 1\n recorderNode = new AudioWorkletNode(audioCtx, 'recorder-processor')\n recorderNode.port.onmessage = (event) => {\n bufferChunks.push(new Float32Array(event.data))\n }\n audioSource.connect(recorderNode)\n audioSource.connect(gainNode)\n gainNode.connect(audioCtx.destination)\n\n const CHUNK_SAMPLES = sampleRate * (interval / 1000)\n timer = setInterval(async () => {\n if (bufferChunks.length === 0)\n return\n\n let accumulated = new Float32Array(0)\n while (accumulated.length < CHUNK_SAMPLES && bufferChunks.length) {\n const next = bufferChunks.shift()\n const tmp = new Float32Array(accumulated.length + next.length)\n tmp.set(accumulated, 0)\n tmp.set(next, accumulated.length)\n accumulated = tmp\n }\n\n if (accumulated.length < CHUNK_SAMPLES)\n return\n\n const chunkToSend = accumulated.slice(0, CHUNK_SAMPLES)\n const pcm = floatTo16BitPCM(chunkToSend)\n const wav = pcmToWav(pcm, sampleRate)\n const subtitle = await onAudioChunk({ pcm, wav })\n append(subtitle)\n }, interval)\n\n started = true\n }\n catch (err) {\n console.error('[artplayerPluginAsr] Initialization failed:', err)\n await stopCapture()\n }\n }\n\n async function stopCapture() {\n if (!started)\n return\n started = false\n\n clearInterval(timer)\n timer = null\n\n if (recorderNode) {\n recorderNode.disconnect()\n recorderNode.port.onmessage = null\n recorderNode = null\n }\n\n if (gainNode) {\n gainNode.disconnect()\n gainNode = null\n }\n\n bufferChunks = []\n }\n\n async function destroy() {\n await stopCapture()\n\n if (mediaStreamSource) {\n mediaStreamSource.disconnect()\n mediaStreamSource = null\n }\n\n if (sourceNode) {\n sourceNode.disconnect()\n sourceNode = null\n }\n\n if (mediaStream) {\n mediaStream.getTracks().forEach(track => track.stop())\n mediaStream = null\n }\n\n if (audioCtx) {\n await audioCtx.close()\n audioCtx = null\n }\n\n workletLoaded = false\n }\n\n art.on('video:volumechange', () => {\n if (gainNode) {\n gainNode.gain.value = art.volume\n }\n })\n\n art.on('play', startCapture)\n art.on('pause', stopCapture)\n art.on('destroy', destroy)\n\n return {\n name: 'artplayerPluginAsr',\n stop: destroy,\n hide,\n append,\n }\n }\n}\n\nif (typeof document !== 'undefined') {\n if (!document.getElementById('artplayer-plugin-asr')) {\n const $style = document.createElement('style')\n $style.id = 'artplayer-plugin-asr'\n $style.textContent = style\n document.head.appendChild($style)\n }\n}\n\nif (typeof window !== 'undefined') {\n window.artplayerPluginAsr = artplayerPluginAsr\n}\n","module.exports = \"704cf673cb407483\";","exports.interopDefault = function (a) {\n return a && a.__esModule ? a : {default: a};\n};\n\nexports.defineInteropFlag = function (a) {\n Object.defineProperty(a, '__esModule', {value: true});\n};\n\nexports.exportAll = function (source, dest) {\n Object.keys(source).forEach(function (key) {\n if (\n key === 'default' ||\n key === '__esModule' ||\n Object.prototype.hasOwnProperty.call(dest, key)\n ) {\n return;\n }\n\n Object.defineProperty(dest, key, {\n enumerable: true,\n get: function () {\n return source[key];\n },\n });\n });\n\n return dest;\n};\n\nexports.export = function (dest, destName, get) {\n Object.defineProperty(dest, destName, {\n enumerable: true,\n get: get,\n });\n};\n"],"names":["modules","entry","mainEntry","parcelRequireName","externals","distDir","publicUrl","devServer","globalObject","globalThis","self","window","global","previousRequire","importMap","i","cache","nodeRequire","module","require","bind","newRequire","name","jumped","currentRequire","err","Error","code","localRequire","resolve","x","id","Module","call","exports","res","isParcelRequire","moduleName","bundle","parent","register","Object","defineProperty","get","length","mainExports","define","amd","__globalThis","parcelHelpers","defineInteropFlag","export","artplayerPluginAsr","_styleLess","_styleLessDefault","interopDefault","option","interval","sampleRate","autoHideTimeout","onAudioChunk","art","started","audioCtx","sourceNode","recorderNode","gainNode","bufferChunks","timer","workletLoaded","hideTimer","mediaStream","mediaStreamSource","$asr","layers","add","html","hide","style","display","append","subtitle","clearTimeout","setTimeout","innerHTML","splitByPunctuation","text","split","map","s","trim","filter","Boolean","slice","line","join","recorderProcessorCode","setupAudioContext","AudioContext","webkitAudioContext","state","resume","setupAudioSource","video","createMediaElementSource","console","warn","captureAudioFromVideo","createMediaStreamSource","videoElement","captureStream","mozCaptureStream","startCapture","audioSource","blobUrl","createWorkletBlobUrl","blob","Blob","type","URL","createObjectURL","audioWorklet","addModule","revokeObjectURL","createGain","gain","value","AudioWorkletNode","port","onmessage","event","push","Float32Array","data","connect","destination","CHUNK_SAMPLES","setInterval","accumulated","next","shift","tmp","set","chunkToSend","pcm","floatTo16BitPCM","float32Array","len","buffer","ArrayBuffer","view","DataView","Math","max","min","setInt16","wav","pcmToWav","pcmBuffer","pcmLength","byteLength","wavBuffer","writeString","offset","str","setUint8","charCodeAt","setUint32","setUint16","Uint8Array","error","stopCapture","clearInterval","disconnect","destroy","getTracks","forEach","track","stop","close","on","volume","document","getElementById","$style","createElement","textContent","default","head","appendChild","a","__esModule","exportAll","source","dest","keys","key","prototype","hasOwnProperty","enumerable","destName","_default","parcelRequire4dc0"],"version":3,"file":"index.js.map"} |