mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-26 08:51:20 -08:00
refactor(hls): [PKG-HLS-04] migrate modules and compatible types
This commit is contained in:
1 parent
ba93b98be5
commit
2f9bee4ee0
34 files changed
+4860
-88
No files matched your search
@@ -1,21 +1,48 @@
|
||||
# HLS control maintenance
|
||||
|
||||
The public entry remains `src/index.js`: `artplayerPluginHlsControl(option = {})` returns a
|
||||
The source entry is `src/index.ts`: `artplayerPluginHlsControl(option = {})` returns a
|
||||
synchronous ArtPlayer plugin with `{ name: 'artplayerPluginHlsControl', update }`. `update()`
|
||||
returns undefined. The consumer creates, attaches and destroys `art.hls`; this plugin does not
|
||||
import Hls.js or own its media engine. Public declarations are still in `types/` pending the
|
||||
separate TypeScript migration (PKG-HLS-04).
|
||||
import Hls.js or own its media engine. Public declarations are authored in `types/`; implementation
|
||||
imports their configuration/result types so there is one public contract. All five self-owned
|
||||
modules are strict TypeScript, with unchecked indexed access enabled and no emitted compiler files.
|
||||
|
||||
| Module | Responsibility |
|
||||
| --- | --- |
|
||||
| `src/index.js` | Core ready/restart/destroy hooks, current engine identity, refresh generation, selection event barrier |
|
||||
| `src/mapping.js` | Quality/audio labels, duplicate groups, selected item and Auto policy; no ArtPlayer/DOM dependencies |
|
||||
| `src/menu.js` | Existing controls/setting update/remove/check APIs, current callback ownership and stable menu reuse |
|
||||
| `src/sdk-events.js` | Optional SDK event capabilities, six subscriptions, setup rollback and listener release |
|
||||
| `src/index.ts` | Core ready/restart/destroy hooks, current engine identity, refresh generation, selection event barrier |
|
||||
| `src/mapping.ts` | Quality/audio labels, duplicate groups, selected item and Auto policy; no ArtPlayer/DOM dependencies |
|
||||
| `src/menu.ts` | Existing controls/setting update/remove/check APIs, current callback ownership and stable menu reuse |
|
||||
| `src/sdk-events.ts` | Optional SDK event capabilities, six subscriptions, setup rollback and listener release |
|
||||
| `src/types.ts` | Internal SDK capabilities, menu models and the narrow host surface; no runtime code |
|
||||
|
||||
The entry depends on these three modules; they do not import the entry or each other.
|
||||
SVG icons remain local build inputs. There is no cross-instance cache, timer, worker or fetch.
|
||||
|
||||
## Public types and editor generation
|
||||
|
||||
`types/artplayer-plugin-hls-control.d.ts` retains the historical path and TS 4.3.5 syntax.
|
||||
Conditional `.d.cts`/`.d.mts` bridges preserve callable CommonJS/default ESM imports and named types;
|
||||
legacy keeps the same JavaScript file and adds a `typesVersions` fallback for older resolution.
|
||||
Do not change these runtime paths or add a runtime dependency on the Hls SDK to obtain its types.
|
||||
|
||||
Default `QualityLevel`/`AudioTrack` fields provide useful formatter inference. `Option<Level, Track>`
|
||||
also accepts caller-supplied SDK types, including inference from an annotated callback. A formatter
|
||||
still accepts the original object and optional index, returns a string and runs as a plain callback.
|
||||
The optional factory overload permits omitted/undefined configuration. The required last overload
|
||||
deliberately preserves old `Parameters<typeof artplayerPluginHlsControl>[0]['quality']` consumers;
|
||||
do not remove it as redundant. `update()` stays synchronous and returns void.
|
||||
|
||||
The single ArtPlayer-to-Host assertion represents the externally attached SDK surface. `update`
|
||||
still uses the historical errorHandle/media identity guard. The SDK subscription assertion follows
|
||||
actual on/off function checks; guarded selector indices follow an equal-length check. These limited
|
||||
boundaries are not proof that arbitrary external objects implement Hls. Keep runtime contract tests.
|
||||
|
||||
`scripts/plugin-editor-types.mjs` generates the HLS Monaco declaration from the authored public file.
|
||||
It creates private definitions plus a callable global/named-type bridge, rejecting unsupported
|
||||
imports/exports. `yarn build:ts` semantically checks that output with both compilers before writing it;
|
||||
never hand-edit `docs/assets/ts/artplayer-plugin-hls-control.d.ts`. The generic defaults and both
|
||||
overloads must survive generation. Other unconverted plugins still use their existing generator path.
|
||||
|
||||
## Refresh and selection
|
||||
|
||||
Registration does not require an Hls instance yet. The first ready/restart/manual update checks
|
||||
@@ -65,8 +92,11 @@ Use the repository's pinned Node and Yarn:
|
||||
|
||||
```sh
|
||||
node --test test/hls-control.test.js
|
||||
node --test refactor/scripts/hls-types.test.mjs
|
||||
yarn test:browser hls-control.spec.js
|
||||
yarn test:browser hls-editor-types.spec.js
|
||||
yarn build artplayer-plugin-hls-control
|
||||
yarn build:ts
|
||||
yarn ci:check
|
||||
```
|
||||
|
||||
@@ -79,3 +109,8 @@ Windows Playwright WebKit lacks MSE; explicit capability/error cleanup runs ther
|
||||
cases are marked skipped. Safari/native HLS, SDK workers, grouped track changes, SDK version range,
|
||||
updated example and isolated package verification remain PKG-HLS-05/06 work. See
|
||||
[refactor validation](../../refactor/hls-validation.md). Keep these gaps visible in release reviews.
|
||||
|
||||
Actual Hls.js 1.5.17 declaration consumers pass TS 5.9.3. TS 4.3.5 reports two existing SDK DOM type
|
||||
errors (MediaDecodingConfiguration and MediaCapabilitiesDecodingInfo), reproduced with the SDK alone.
|
||||
The plugin introduces no additional errors; do not hide those SDK diagnostics with skipLibCheck or
|
||||
claim every SDK/compiler combination passes. Standalone plugin consumers pass both compilers.
|
||||
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const o=e.get(t.html);return o?(t.default&&(o.default=!0,o.value=t.value),!1):(e.set(t.html,t),!0)})}function e(t,e,o,n,l,i){let r;const c={control:!1,setting:!1};function s(o){c[o]&&(c[o]=!1,t["control"===o?"controls":"setting"].remove(e))}function u(){r=void 0,s("control"),s("setting")}function a(e,o){for(const t of e.model.selector)t.default=t===o;e.config.control&&t.controls.check(o),e===r&&l(e.hls)&&e.config.setting&&t.setting.check(o)}return{update:function(f,d,h,m){if(!h)return void u();const g=r,v=h.selector.findIndex(t=>t.default);if(!m&&g?.hls===f&&g.model.title===h.title&&(-1!==v||!g.model.selector.some(t=>t.default)&&g.model.html===h.html)&&c.control===Boolean(d.control)&&c.setting===Boolean(d.setting)&&g.model.selector.length===h.selector.length&&g.model.selector.every((t,e)=>t.html===h.selector[e].html&&t.value===h.selector[e].value)){g.config=d;const t=g.model.selector[v];return void(!t||t.default&&g.model.html===h.html||(g.model.html=h.html,a(g,t)))}const p={hls:f,config:d,model:h};r=p;const y=()=>r===p&&l(f),T=e=>i(()=>y()?(f[o]=e.value,y()?(h.html=e.html,t.notice.show=`${h.title}: ${e.html}`,y()&&a(p,e),e.html):e.html):e.html);d.control?(c.control=!0,t.controls.update({name:e,position:"right",html:h.html,style:{padding:"0 10px"},selector:h.selector,onSelect:T})):s("control"),y()&&(d.setting?(c.setting=!0,t.setting.update({name:e,tooltip:h.html,html:h.title,icon:n,width:200,selector:h.selector,onSelect:T})):s("setting"))},clear:u,invalidate:function(){r=void 0}}}return function(o={}){return n=>{const{$video:l}=n.template,{errorHandle:i}=n.constructor.utils;let r,c,s=!1,u=0,a=()=>{},f=0;const d=new WeakSet,h=t=>!s&&!d.has(t)&&n.hls===t&&t.media===l,m=e(n,"hls-quality","currentLevel",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',h,v),g=e(n,"hls-audio","audioTrack",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',h,v);function v(t){f++;let e=!1;try{const o=t();return e=!0,o}finally{if(f--,!f){const t=c;c=void 0,e&&t&&p(t,!1)}}}function p(e,n){if(!h(e))return;const l=++u,i=o.quality||{},r=function(e,o){if(!e.levels.length)return null;const n=o.auto||"Auto",l=o.getName||(t=>t.name||`${t.height}P`),i=function(t){return!0===t.autoLevelEnabled?-1:t.currentLevel}(e),r=e.levels[i],c=r?l(r):n,s=t(e.levels.map((t,e)=>({html:l(t,e),value:e,default:i===e}))).sort((t,e)=>e.value-t.value);return s.push({html:n,value:-1,default:-1===i}),{html:c,title:o.title||"Quality",selector:s}}(e,i);if(!h(e)||l!==u)return;if(m.update(e,i,r,n),!h(e)||l!==u)return;const c=o.audio||{},s=function(e,o){if(!e.audioTracks.length)return null;const n=o.auto||"Auto",l=o.getName||(t=>t.name||t.lang||t.language),i=e.audioTracks[e.audioTrack],r=i?l(i):n,c=t(e.audioTracks.map((t,o)=>({html:l(t,o),value:t.id,default:e.audioTrack===t.id})));return{html:r,title:o.title||"Audio",selector:c}}(e,c);h(e)&&l===u&&g.update(e,c,s,n)}function y(){if(s)return;const t=n.hls;if(i(t?.media===l,'Cannot find instance of HLS from "art.hls"'),!d.has(t)){if(r!==t){a(),r=t;try{a=function(t,e,o){const n=t.constructor?.Events;if(!n||"function"!==typeof t.on||"function"!==typeof t.off)return()=>{};const l=[];let i=!0;function r(){if(i){i=!1;for(const[e,o]of l)t.off(e,o);l.length=0}}try{for(const r of["MANIFEST_PARSED","LEVELS_UPDATED","LEVEL_SWITCHED","AUDIO_TRACKS_UPDATED","AUDIO_TRACK_SWITCHED","DESTROYING"]){const c=n[r];if("string"!==typeof c||l.some(([t])=>t===c))continue;const s=()=>{i&&("DESTROYING"===r?o():e())};l.push([c,s]),t.on(c,s)}}catch(c){throw r(),c}return r}(t,()=>{f?c=t:p(t,!1)},()=>{d.add(t),a(),r===t&&(r=void 0,s||(m.clear(),g.clear()))})}catch(e){throw r=void 0,e}}p(t,!0)}}return n.on("ready",y),n.on("restart",y),n.on("destroy",function t(){s||(s=!0,u++,c=void 0,m.invalidate(),g.invalidate(),a(),n.off("ready",Line truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const o=e.get(t.html);return o?(t.default&&(o.default=!0,o.value=t.value),!1):(e.set(t.html,t),!0)})}function e(t,e,o,n,l,i){let r;const c={control:!1,setting:!1};function s(o){c[o]&&(c[o]=!1,t["control"===o?"controls":"setting"].remove(e))}function u(){r=void 0,s("control"),s("setting")}function a(e,o){for(const t of e.model.selector)t.default=t===o;e.config.control&&t.controls.check(o),e===r&&l(e.hls)&&e.config.setting&&t.setting.check(o)}return{update:function(f,d,h,m){if(!h)return void u();const g=r,v=h.selector.findIndex(t=>t.default);if(!m&&g?.hls===f&&g.model.title===h.title&&(-1!==v||!g.model.selector.some(t=>t.default)&&g.model.html===h.html)&&c.control===Boolean(d.control)&&c.setting===Boolean(d.setting)&&g.model.selector.length===h.selector.length&&g.model.selector.every((t,e)=>t.html===h.selector[e].html&&t.value===h.selector[e].value)){g.config=d;const t=g.model.selector[v];return void(!t||t.default&&g.model.html===h.html||(g.model.html=h.html,a(g,t)))}const p={hls:f,config:d,model:h};r=p;const y=()=>r===p&&l(f),T=e=>i(()=>y()?(f[o]=e.value,y()?(h.html=e.html,t.notice.show=`${h.title}: ${e.html}`,y()&&a(p,e),e.html):e.html):e.html);d.control?(c.control=!0,t.controls.update({name:e,position:"right",html:h.html,style:{padding:"0 10px"},selector:h.selector,onSelect:T})):s("control"),y()&&(d.setting?(c.setting=!0,t.setting.update({name:e,tooltip:h.html,html:h.title,icon:n,width:200,selector:h.selector,onSelect:T})):s("setting"))},clear:u,invalidate:function(){r=void 0}}}return function(o={}){return n=>{const l=n,{$video:i}=l.template,{errorHandle:r}=l.constructor.utils;let c,s,u=!1,a=0,f=()=>{},d=0;const h=new WeakSet,m=t=>!u&&!h.has(t)&&l.hls===t&&t.media===i,g=e(l,"hls-quality","currentLevel",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',m,p),v=e(l,"hls-audio","audioTrack",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',m,p);function p(t){d++;let e=!1;try{const o=t();return e=!0,o}finally{if(d--,!d){const t=s;s=void 0,e&&t&&y(t,!1)}}}function y(e,n){if(!m(e))return;const l=++a,i=o.quality||{},r=function(e,o){if(!e.levels.length)return null;const n=o.auto||"Auto",l=o.getName||(t=>t.name||`${t.height}P`),i=function(t){return!0===t.autoLevelEnabled?-1:t.currentLevel}(e),r=e.levels[i],c=r?l(r):n,s=t(e.levels.map((t,e)=>({html:l(t,e),value:e,default:i===e}))).sort((t,e)=>e.value-t.value);return s.push({html:n,value:-1,default:-1===i}),{html:c,title:o.title||"Quality",selector:s}}(e,i);if(!m(e)||l!==a)return;if(g.update(e,i,r,n),!m(e)||l!==a)return;const c=o.audio||{},s=function(e,o){if(!e.audioTracks.length)return null;const n=o.auto||"Auto",l=o.getName||(t=>t.name||t.lang||t.language),i=e.audioTracks[e.audioTrack],r=i?l(i):n,c=t(e.audioTracks.map((t,o)=>({html:l(t,o),value:t.id,default:e.audioTrack===t.id})));return{html:r,title:o.title||"Audio",selector:c}}(e,c);m(e)&&l===a&&v.update(e,c,s,n)}function T(){if(u)return;const t=l.hls;if(r(t?.media===i,'Cannot find instance of HLS from "art.hls"'),!h.has(t)){if(c!==t){f(),c=t;try{f=function(t,e,o){const n=t.constructor?.Events;if(!n||"function"!==typeof t.on||"function"!==typeof t.off)return()=>{};const l=t,i=[];let r=!0;function c(){if(r){r=!1;for(const[t,e]of i)l.off(t,e);i.length=0}}try{for(const t of["MANIFEST_PARSED","LEVELS_UPDATED","LEVEL_SWITCHED","AUDIO_TRACKS_UPDATED","AUDIO_TRACK_SWITCHED","DESTROYING"]){const c=n[t];if("string"!==typeof c||i.some(([t])=>t===c))continue;const s=()=>{r&&("DESTROYING"===t?o():e())};i.push([c,s]),l.on(c,s)}}catch(s){throw c(),s}return c}(t,()=>{d?s=t:y(t,!1)},()=>{h.add(t),f(),c===t&&(c=void 0,u||(g.clear(),v.clear()))})}catch(e){throw c=void 0,e}}y(t,!0)}}return l.on("ready",T),l.on("restart",T),l.on("destroy",function t(){u||(u=!0,a++,s=void 0,g.invalidate(),v.invalidate(),f(),l.offLine truncated
|
||||
+1
-1
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const o=e.get(t.html);return o?(t.default&&(o.default=!0,o.value=t.value),!1):(e.set(t.html,t),!0)})}function e(t,e,o,l,n,i){let r;const c={control:!1,setting:!1};function s(o){c[o]&&(c[o]=!1,t["control"===o?"controls":"setting"].remove(e))}function u(){r=void 0,s("control"),s("setting")}function a(e,o){for(const t of e.model.selector)t.default=t===o;e.config.control&&t.controls.check(o),e===r&&n(e.hls)&&e.config.setting&&t.setting.check(o)}return{update:function(f,d,h,m){if(!h)return void u();const g=r,v=h.selector.findIndex(t=>t.default);if(!m&&(null==g?void 0:g.hls)===f&&g.model.title===h.title&&(-1!==v||!g.model.selector.some(t=>t.default)&&g.model.html===h.html)&&c.control===Boolean(d.control)&&c.setting===Boolean(d.setting)&&g.model.selector.length===h.selector.length&&g.model.selector.every((t,e)=>t.html===h.selector[e].html&&t.value===h.selector[e].value)){g.config=d;const t=g.model.selector[v];return void(!t||t.default&&g.model.html===h.html||(g.model.html=h.html,a(g,t)))}const p={hls:f,config:d,model:h};r=p;const y=()=>r===p&&n(f),T=e=>i(()=>y()?(f[o]=e.value,y()?(h.html=e.html,t.notice.show=`${h.title}: ${e.html}`,y()&&a(p,e),e.html):e.html):e.html);d.control?(c.control=!0,t.controls.update({name:e,position:"right",html:h.html,style:{padding:"0 10px"},selector:h.selector,onSelect:T})):s("control"),y()&&(d.setting?(c.setting=!0,t.setting.update({name:e,tooltip:h.html,html:h.title,icon:l,width:200,selector:h.selector,onSelect:T})):s("setting"))},clear:u,invalidate:function(){r=void 0}}}return function(o={}){return l=>{const{$video:n}=l.template,{errorHandle:i}=l.constructor.utils;let r,c,s=!1,u=0,a=()=>{},f=0;const d=new WeakSet,h=t=>!s&&!d.has(t)&&l.hls===t&&t.media===n,m=e(l,"hls-quality","currentLevel",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',h,v),g=e(l,"hls-audio","audioTrack",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',h,v);function v(t){f++;let e=!1;try{const o=t();return e=!0,o}finally{if(f--,!f){const t=c;c=void 0,e&&t&&p(t,!1)}}}function p(e,l){if(!h(e))return;const n=++u,i=o.quality||{},r=function(e,o){if(!e.levels.length)return null;const l=o.auto||"Auto",n=o.getName||(t=>t.name||`${t.height}P`),i=function(t){return!0===t.autoLevelEnabled?-1:t.currentLevel}(e),r=e.levels[i],c=r?n(r):l,s=t(e.levels.map((t,e)=>({html:n(t,e),value:e,default:i===e}))).sort((t,e)=>e.value-t.value);return s.push({html:l,value:-1,default:-1===i}),{html:c,title:o.title||"Quality",selector:s}}(e,i);if(!h(e)||n!==u)return;if(m.update(e,i,r,l),!h(e)||n!==u)return;const c=o.audio||{},s=function(e,o){if(!e.audioTracks.length)return null;const l=o.auto||"Auto",n=o.getName||(t=>t.name||t.lang||t.language),i=e.audioTracks[e.audioTrack],r=i?n(i):l,c=t(e.audioTracks.map((t,o)=>({html:n(t,o),value:t.id,default:e.audioTrack===t.id})));return{html:r,title:o.title||"Audio",selector:c}}(e,c);h(e)&&n===u&&g.update(e,c,s,l)}function y(){if(s)return;const t=l.hls;if(i((null==t?void 0:t.media)===n,'Cannot find instance of HLS from "art.hls"'),!d.has(t)){if(r!==t){a(),r=t;try{a=function(t,e,o){var l;const n=null==(l=t.constructor)?void 0:l.Events;if(!n||"function"!==typeof t.on||"function"!==typeof t.off)return()=>{};const i=[];let r=!0;function c(){if(r){r=!1;for(const[e,o]of i)t.off(e,o);i.length=0}}try{for(const l of["MANIFEST_PARSED","LEVELS_UPDATED","LEVEL_SWITCHED","AUDIO_TRACKS_UPDATED","AUDIO_TRACK_SWITCHED","DESTROYING"]){const c=n[l];if("string"!==typeof c||i.some(([t])=>t===c))continue;const s=()=>{r&&("DESTROYING"===l?o():e())};i.push([c,s]),t.on(c,s)}}catch(s){throw c(),s}return c}(t,()=>{f?c=t:p(t,!1)},()=>{d.add(t),a(),r===t&&(r=void 0,s||(m.clear(),g.clear()))})}catch(e){throw r=void 0,e}}p(t,!0)}}return l.on("ready",y),l.on("restart",y),l.on("destroy",function t(){s||(s=!0,u++,cLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginHlsControl=e(),define(function(){return t.artplayerPluginHlsControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginHlsControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const o=e.get(t.html);return o?(t.default&&(o.default=!0,o.value=t.value),!1):(e.set(t.html,t),!0)})}function e(t,e,o,l,n,i){let r;const c={control:!1,setting:!1};function s(o){c[o]&&(c[o]=!1,t["control"===o?"controls":"setting"].remove(e))}function u(){r=void 0,s("control"),s("setting")}function a(e,o){for(const t of e.model.selector)t.default=t===o;e.config.control&&t.controls.check(o),e===r&&n(e.hls)&&e.config.setting&&t.setting.check(o)}return{update:function(f,d,h,m){if(!h)return void u();const g=r,v=h.selector.findIndex(t=>t.default);if(!m&&(null==g?void 0:g.hls)===f&&g.model.title===h.title&&(-1!==v||!g.model.selector.some(t=>t.default)&&g.model.html===h.html)&&c.control===Boolean(d.control)&&c.setting===Boolean(d.setting)&&g.model.selector.length===h.selector.length&&g.model.selector.every((t,e)=>t.html===h.selector[e].html&&t.value===h.selector[e].value)){g.config=d;const t=g.model.selector[v];return void(!t||t.default&&g.model.html===h.html||(g.model.html=h.html,a(g,t)))}const p={hls:f,config:d,model:h};r=p;const y=()=>r===p&&n(f),T=e=>i(()=>y()?(f[o]=e.value,y()?(h.html=e.html,t.notice.show=`${h.title}: ${e.html}`,y()&&a(p,e),e.html):e.html):e.html);d.control?(c.control=!0,t.controls.update({name:e,position:"right",html:h.html,style:{padding:"0 10px"},selector:h.selector,onSelect:T})):s("control"),y()&&(d.setting?(c.setting=!0,t.setting.update({name:e,tooltip:h.html,html:h.title,icon:l,width:200,selector:h.selector,onSelect:T})):s("setting"))},clear:u,invalidate:function(){r=void 0}}}return function(o={}){return l=>{const n=l,{$video:i}=n.template,{errorHandle:r}=n.constructor.utils;let c,s,u=!1,a=0,f=()=>{},d=0;const h=new WeakSet,m=t=>!u&&!h.has(t)&&n.hls===t&&t.media===i,g=e(n,"hls-quality","currentLevel",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M0 96C0 60.7 28.7 32 64 32l384 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6l96 0 32 0 208 0c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"/></svg>',m,p),v=e(n,"hls-audio","audioTrack",'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="18"><path fill="#fff" d="M256 80C149.9 80 62.4 159.4 49.6 262c9.4-3.8 19.6-6 30.4-6c26.5 0 48 21.5 48 48l0 128c0 26.5-21.5 48-48 48c-44.2 0-80-35.8-80-80l0-16 0-48 0-48C0 146.6 114.6 32 256 32s256 114.6 256 256l0 48 0 48 0 16c0 44.2-35.8 80-80 80c-26.5 0-48-21.5-48-48l0-128c0-26.5 21.5-48 48-48c10.8 0 21 2.1 30.4 6C449.6 159.4 362.1 80 256 80z"/></svg>',m,p);function p(t){d++;let e=!1;try{const o=t();return e=!0,o}finally{if(d--,!d){const t=s;s=void 0,e&&t&&y(t,!1)}}}function y(e,l){if(!m(e))return;const n=++a,i=o.quality||{},r=function(e,o){if(!e.levels.length)return null;const l=o.auto||"Auto",n=o.getName||(t=>t.name||`${t.height}P`),i=function(t){return!0===t.autoLevelEnabled?-1:t.currentLevel}(e),r=e.levels[i],c=r?n(r):l,s=t(e.levels.map((t,e)=>({html:n(t,e),value:e,default:i===e}))).sort((t,e)=>e.value-t.value);return s.push({html:l,value:-1,default:-1===i}),{html:c,title:o.title||"Quality",selector:s}}(e,i);if(!m(e)||n!==a)return;if(g.update(e,i,r,l),!m(e)||n!==a)return;const c=o.audio||{},s=function(e,o){if(!e.audioTracks.length)return null;const l=o.auto||"Auto",n=o.getName||(t=>t.name||t.lang||t.language),i=e.audioTracks[e.audioTrack],r=i?n(i):l,c=t(e.audioTracks.map((t,o)=>({html:n(t,o),value:t.id,default:e.audioTrack===t.id})));return{html:r,title:o.title||"Audio",selector:c}}(e,c);m(e)&&n===a&&v.update(e,c,s,l)}function T(){if(u)return;const t=n.hls;if(r((null==t?void 0:t.media)===i,'Cannot find instance of HLS from "art.hls"'),!h.has(t)){if(c!==t){f(),c=t;try{f=function(t,e,o){var l;const n=null==(l=t.constructor)?void 0:l.Events;if(!n||"function"!==typeof t.on||"function"!==typeof t.off)return()=>{};const i=t,r=[];let c=!0;function s(){if(c){c=!1;for(const[t,e]of r)i.off(t,e);r.length=0}}try{for(const t of["MANIFEST_PARSED","LEVELS_UPDATED","LEVEL_SWITCHED","AUDIO_TRACKS_UPDATED","AUDIO_TRACK_SWITCHED","DESTROYING"]){const l=n[t];if("string"!==typeof l||r.some(([t])=>t===l))continue;const s=()=>{c&&("DESTROYING"===t?o():e())};r.push([l,s]),i.on(l,s)}}catch(u){throw s(),u}return s}(t,()=>{d?s=t:y(t,!1)},()=>{h.add(t),f(),c===t&&(c=void 0,u||(g.clear(),v.clear()))})}catch(e){throw c=void 0,e}}y(t,!0)}}return n.on("ready",T),n.on("restart",T),n.on("destroy",function t(){u||(uLine truncated
|
||||
+5
-3
@@ -129,6 +129,7 @@ function subscribeHls(hls, refresh, destroyed) {
|
||||
if (!events || typeof hls.on !== "function" || typeof hls.off !== "function")
|
||||
return () => {
|
||||
};
|
||||
const source = hls;
|
||||
const subscriptions = [];
|
||||
let active = true;
|
||||
function release() {
|
||||
@@ -136,7 +137,7 @@ function subscribeHls(hls, refresh, destroyed) {
|
||||
return;
|
||||
active = false;
|
||||
for (const [event, callback] of subscriptions)
|
||||
hls.off(event, callback);
|
||||
source.off(event, callback);
|
||||
subscriptions.length = 0;
|
||||
}
|
||||
try {
|
||||
@@ -153,7 +154,7 @@ function subscribeHls(hls, refresh, destroyed) {
|
||||
refresh();
|
||||
};
|
||||
subscriptions.push([event, callback]);
|
||||
hls.on(event, callback);
|
||||
source.on(event, callback);
|
||||
}
|
||||
} catch (error) {
|
||||
release();
|
||||
@@ -162,7 +163,8 @@ function subscribeHls(hls, refresh, destroyed) {
|
||||
return release;
|
||||
}
|
||||
function artplayerPluginHlsControl(option = {}) {
|
||||
return (art) => {
|
||||
return (player) => {
|
||||
const art = player;
|
||||
const { $video } = art.template;
|
||||
const { errorHandle } = art.constructor.utils;
|
||||
let closed = false;
|
||||
|
||||
@@ -19,19 +19,36 @@
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/artplayer-plugin-hls-control.d.ts",
|
||||
"import": "./dist/artplayer-plugin-hls-control.mjs",
|
||||
"require": "./dist/artplayer-plugin-hls-control.js"
|
||||
"import": {
|
||||
"types": "./types/artplayer-plugin-hls-control.d.mts",
|
||||
"default": "./dist/artplayer-plugin-hls-control.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-plugin-hls-control.d.cts",
|
||||
"default": "./dist/artplayer-plugin-hls-control.js"
|
||||
}
|
||||
},
|
||||
"./legacy": {
|
||||
"types": "./types/artplayer-plugin-hls-control.d.ts",
|
||||
"import": "./dist/artplayer-plugin-hls-control.legacy.js",
|
||||
"require": "./dist/artplayer-plugin-hls-control.legacy.js"
|
||||
"import": {
|
||||
"types": "./types/artplayer-plugin-hls-control.d.cts",
|
||||
"default": "./dist/artplayer-plugin-hls-control.legacy.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-plugin-hls-control.d.cts",
|
||||
"default": "./dist/artplayer-plugin-hls-control.legacy.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-hls-control.js",
|
||||
"module": "./dist/artplayer-plugin-hls-control.mjs",
|
||||
"types": "./types/artplayer-plugin-hls-control.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-hls-control.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"legacy": [
|
||||
"types/artplayer-plugin-hls-control.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-11
@@ -1,25 +1,30 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { AudioTrack, Option, QualityLevel, Result } from '../types/artplayer-plugin-hls-control'
|
||||
import type { Cleanup, Hls, Host } from './types'
|
||||
import $audio from './audio.svg?raw'
|
||||
import { audioModel, qualityModel } from './mapping'
|
||||
import { createMenu } from './menu'
|
||||
import $quality from './quality.svg?raw'
|
||||
import { subscribeHls } from './sdk-events'
|
||||
|
||||
export default function artplayerPluginHlsControl(option = {}) {
|
||||
return (art) => {
|
||||
export default function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track> = {}) {
|
||||
return (player: Artplayer): Result => {
|
||||
// The consumer owns the optional SDK; update validates its media identity before use.
|
||||
const art = player as unknown as Host<Level, Track>
|
||||
const { $video } = art.template
|
||||
const { errorHandle } = art.constructor.utils
|
||||
let closed = false
|
||||
let revision = 0
|
||||
let engine
|
||||
let unsubscribe = () => {}
|
||||
let engine: Hls<Level, Track> | undefined
|
||||
let unsubscribe: Cleanup = () => {}
|
||||
let selecting = 0
|
||||
let pending
|
||||
let pending: Hls<Level, Track> | undefined
|
||||
const retired = new WeakSet()
|
||||
const active = hls => !closed && !retired.has(hls) && art.hls === hls && hls.media === $video
|
||||
const active = (hls: Hls<Level, Track>) => !closed && !retired.has(hls) && art.hls === hls && hls.media === $video
|
||||
const quality = createMenu(art, 'hls-quality', 'currentLevel', $quality, active, select)
|
||||
const audio = createMenu(art, 'hls-audio', 'audioTrack', $audio, active, select)
|
||||
|
||||
function select(callback) {
|
||||
function select<T>(callback: () => T): T {
|
||||
selecting++
|
||||
let succeeded = false
|
||||
try {
|
||||
@@ -38,7 +43,7 @@ export default function artplayerPluginHlsControl(option = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
function refresh(hls, force) {
|
||||
function refresh(hls: Hls<Level, Track>, force: boolean): void {
|
||||
if (!active(hls))
|
||||
return
|
||||
const version = ++revision
|
||||
@@ -55,10 +60,10 @@ export default function artplayerPluginHlsControl(option = {}) {
|
||||
audio.update(hls, audioConfig, audioView, force)
|
||||
}
|
||||
|
||||
function update() {
|
||||
function update(): void {
|
||||
if (closed)
|
||||
return
|
||||
const hls = art.hls
|
||||
const hls = art.hls!
|
||||
errorHandle(hls?.media === $video, 'Cannot find instance of HLS from "art.hls"')
|
||||
if (retired.has(hls))
|
||||
return
|
||||
@@ -91,7 +96,7 @@ export default function artplayerPluginHlsControl(option = {}) {
|
||||
refresh(hls, true)
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
function destroy(): void {
|
||||
if (closed)
|
||||
return
|
||||
closed = true
|
||||
+10
-7
@@ -1,5 +1,8 @@
|
||||
function uniqueLabels(items) {
|
||||
const seen = new Map()
|
||||
import type { Config } from '../types/artplayer-plugin-hls-control'
|
||||
import type { AudioFields, Hls, LevelFields, MenuModel, SelectorItem } from './types'
|
||||
|
||||
function uniqueLabels(items: SelectorItem[]): SelectorItem[] {
|
||||
const seen = new Map<string, SelectorItem>()
|
||||
return items.filter((item) => {
|
||||
if (item.html === undefined)
|
||||
return true
|
||||
@@ -16,15 +19,15 @@ function uniqueLabels(items) {
|
||||
})
|
||||
}
|
||||
|
||||
export function qualitySelection(hls) {
|
||||
export function qualitySelection(hls: Pick<Hls, 'currentLevel' | 'autoLevelEnabled'>): number {
|
||||
return hls.autoLevelEnabled === true ? -1 : hls.currentLevel
|
||||
}
|
||||
|
||||
export function qualityModel(hls, config) {
|
||||
export function qualityModel<Level extends object>(hls: Pick<Hls<Level>, 'levels' | 'currentLevel' | 'autoLevelEnabled'>, config: Config<Level>): MenuModel | null {
|
||||
if (!hls.levels.length)
|
||||
return null
|
||||
const auto = config.auto || 'Auto'
|
||||
const getName = config.getName || (level => level.name || `${level.height}P`)
|
||||
const getName = config.getName || ((level: LevelFields) => level.name || `${level.height}P`)
|
||||
const selected = qualitySelection(hls)
|
||||
const level = hls.levels[selected]
|
||||
const html = level ? getName(level) : auto
|
||||
@@ -34,11 +37,11 @@ export function qualityModel(hls, config) {
|
||||
return { html, title: config.title || 'Quality', selector }
|
||||
}
|
||||
|
||||
export function audioModel(hls, config) {
|
||||
export function audioModel<Track extends object>(hls: Pick<Hls<object, Track>, 'audioTracks' | 'audioTrack'>, config: Config<Track>): MenuModel | null {
|
||||
if (!hls.audioTracks.length)
|
||||
return null
|
||||
const auto = config.auto || 'Auto'
|
||||
const getName = config.getName || (track => track.name || track.lang || track.language)
|
||||
const getName = config.getName || ((track: AudioFields) => track.name || track.lang || track.language)
|
||||
const track = hls.audioTracks[hls.audioTrack]
|
||||
const html = track ? getName(track) : auto
|
||||
const selector = uniqueLabels(hls.audioTracks.map((item, index) => ({ html: getName(item, index), value: item.id, default: hls.audioTrack === item.id })))
|
||||
+12
-9
@@ -1,21 +1,23 @@
|
||||
export function createMenu(art, name, field, icon, active, select) {
|
||||
let current
|
||||
import type { DisplayConfig, MenuHost, MenuModel, MenuState, SelectorItem } from './types'
|
||||
|
||||
export function createMenu<Engine extends { currentLevel: number, audioTrack: number }>(art: MenuHost, name: string, field: 'currentLevel' | 'audioTrack', icon: string, active: (hls: Engine) => boolean, select: <T>(callback: () => T) => T) {
|
||||
let current: MenuState<Engine> | undefined
|
||||
const owned = { control: false, setting: false }
|
||||
|
||||
function remove(surface) {
|
||||
function remove(surface: 'control' | 'setting'): void {
|
||||
if (!owned[surface])
|
||||
return
|
||||
owned[surface] = false
|
||||
art[surface === 'control' ? 'controls' : 'setting'].remove(name)
|
||||
}
|
||||
|
||||
function clear() {
|
||||
function clear(): void {
|
||||
current = undefined
|
||||
remove('control')
|
||||
remove('setting')
|
||||
}
|
||||
|
||||
function check(state, item) {
|
||||
function check(state: MenuState<Engine>, item: SelectorItem): void {
|
||||
for (const entry of state.model.selector)
|
||||
entry.default = entry === item
|
||||
if (state.config.control)
|
||||
@@ -26,18 +28,19 @@ export function createMenu(art, name, field, icon, active, select) {
|
||||
art.setting.check(item)
|
||||
}
|
||||
|
||||
function update(hls, config, model, force) {
|
||||
function update(hls: Engine, config: DisplayConfig, model: MenuModel | null, force: boolean): void {
|
||||
if (!model) {
|
||||
clear()
|
||||
return
|
||||
}
|
||||
const previous = current
|
||||
const selectedIndex = model.selector.findIndex(item => item.default)
|
||||
// Equal lengths below protect the same-index reads in the comparison.
|
||||
const reusable = !force && previous?.hls === hls && previous.model.title === model.title
|
||||
&& (selectedIndex !== -1 || (!previous.model.selector.some(item => item.default) && previous.model.html === model.html))
|
||||
&& owned.control === Boolean(config.control) && owned.setting === Boolean(config.setting)
|
||||
&& previous.model.selector.length === model.selector.length
|
||||
&& previous.model.selector.every((item, index) => item.html === model.selector[index].html && item.value === model.selector[index].value)
|
||||
&& previous.model.selector.every((item, index) => item.html === model.selector[index]!.html && item.value === model.selector[index]!.value)
|
||||
if (reusable) {
|
||||
previous.config = config
|
||||
const target = previous.model.selector[selectedIndex]
|
||||
@@ -50,7 +53,7 @@ export function createMenu(art, name, field, icon, active, select) {
|
||||
const state = { hls, config, model }
|
||||
current = state
|
||||
const valid = () => current === state && active(hls)
|
||||
const onSelect = item => select(() => {
|
||||
const onSelect = (item: SelectorItem) => select(() => {
|
||||
if (!valid())
|
||||
return item.html
|
||||
hls[field] = item.value
|
||||
@@ -80,7 +83,7 @@ export function createMenu(art, name, field, icon, active, select) {
|
||||
}
|
||||
}
|
||||
|
||||
function invalidate() {
|
||||
function invalidate(): void {
|
||||
current = undefined
|
||||
}
|
||||
return { update, clear, invalidate }
|
||||
+10
-6
@@ -1,19 +1,23 @@
|
||||
export function subscribeHls(hls, refresh, destroyed) {
|
||||
import type { Cleanup, Hls, SdkEvent } from './types'
|
||||
|
||||
export function subscribeHls(hls: Hls, refresh: Cleanup, destroyed: Cleanup): Cleanup {
|
||||
const events = hls.constructor?.Events
|
||||
if (!events || typeof hls.on !== 'function' || typeof hls.off !== 'function')
|
||||
return () => {}
|
||||
const subscriptions = []
|
||||
// Keep the checked SDK object so method calls retain their original receiver.
|
||||
const source = hls as Hls & Required<Pick<Hls, 'on' | 'off'>>
|
||||
const subscriptions: [string, Cleanup][] = []
|
||||
let active = true
|
||||
function release() {
|
||||
function release(): void {
|
||||
if (!active)
|
||||
return
|
||||
active = false
|
||||
for (const [event, callback] of subscriptions)
|
||||
hls.off(event, callback)
|
||||
source.off(event, callback)
|
||||
subscriptions.length = 0
|
||||
}
|
||||
try {
|
||||
for (const key of ['MANIFEST_PARSED', 'LEVELS_UPDATED', 'LEVEL_SWITCHED', 'AUDIO_TRACKS_UPDATED', 'AUDIO_TRACK_SWITCHED', 'DESTROYING']) {
|
||||
for (const key of ['MANIFEST_PARSED', 'LEVELS_UPDATED', 'LEVEL_SWITCHED', 'AUDIO_TRACKS_UPDATED', 'AUDIO_TRACK_SWITCHED', 'DESTROYING'] satisfies SdkEvent[]) {
|
||||
const event = events[key]
|
||||
if (typeof event !== 'string' || subscriptions.some(([name]) => name === event))
|
||||
continue
|
||||
@@ -26,7 +30,7 @@ export function subscribeHls(hls, refresh, destroyed) {
|
||||
refresh()
|
||||
}
|
||||
subscriptions.push([event, callback])
|
||||
hls.on(event, callback)
|
||||
source.on(event, callback)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
@@ -0,0 +1,79 @@
|
||||
import type { Config } from '../types/artplayer-plugin-hls-control'
|
||||
|
||||
export interface LevelFields {
|
||||
height?: number
|
||||
name?: string
|
||||
}
|
||||
|
||||
export interface AudioFields {
|
||||
id: number
|
||||
name?: string
|
||||
lang?: string
|
||||
language?: string
|
||||
}
|
||||
|
||||
export type SdkEvent = 'MANIFEST_PARSED' | 'LEVELS_UPDATED' | 'LEVEL_SWITCHED' | 'AUDIO_TRACKS_UPDATED' | 'AUDIO_TRACK_SWITCHED' | 'DESTROYING'
|
||||
export type Cleanup = () => void
|
||||
|
||||
export interface Hls<Level extends object = object, Track extends object = object> {
|
||||
media: object | null
|
||||
levels: (Level & LevelFields)[]
|
||||
audioTracks: (Track & AudioFields)[]
|
||||
currentLevel: number
|
||||
audioTrack: number
|
||||
autoLevelEnabled?: boolean
|
||||
constructor?: { Events?: Partial<Record<SdkEvent, unknown>> }
|
||||
on?: (event: string, callback: Cleanup) => unknown
|
||||
off?: (event: string, callback: Cleanup) => unknown
|
||||
}
|
||||
|
||||
export interface SelectorItem {
|
||||
html: string | undefined
|
||||
value: number
|
||||
default: boolean
|
||||
}
|
||||
|
||||
export interface MenuModel {
|
||||
html: string | undefined
|
||||
title: string
|
||||
selector: SelectorItem[]
|
||||
}
|
||||
|
||||
export interface MenuOption {
|
||||
name: string
|
||||
html: string | undefined
|
||||
selector: SelectorItem[]
|
||||
onSelect: (item: SelectorItem) => string | undefined
|
||||
position?: 'right'
|
||||
style?: { padding: string }
|
||||
tooltip?: string
|
||||
icon?: string
|
||||
width?: number
|
||||
}
|
||||
|
||||
export interface Registry {
|
||||
update: (option: MenuOption) => unknown
|
||||
remove: (name: string) => unknown
|
||||
check: (item: SelectorItem) => unknown
|
||||
}
|
||||
|
||||
export interface MenuHost {
|
||||
controls: Registry
|
||||
setting: Registry
|
||||
notice: { show: string }
|
||||
}
|
||||
|
||||
export interface Host<Level extends object, Track extends object> extends MenuHost {
|
||||
template: { $video: object }
|
||||
constructor: { utils: { errorHandle: (condition: unknown, message: string) => void } }
|
||||
hls?: Hls<Level, Track>
|
||||
on: (event: 'ready' | 'restart' | 'destroy', callback: Cleanup) => unknown
|
||||
off: (event: 'ready' | 'restart' | 'destroy', callback: Cleanup) => unknown
|
||||
}
|
||||
|
||||
export type DisplayConfig = Pick<Config, 'control' | 'setting'>
|
||||
export interface MenuState<Engine> {
|
||||
hls: Engine
|
||||
config: DisplayConfig
|
||||
model: MenuModel
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": { "allowJs": false },
|
||||
"include": ["src/**/*.ts", "types/**/*.d.ts", "types/**/*.d.mts", "types/**/*.d.cts", "../../types/assets.d.ts"]
|
||||
}
|
||||
@@ -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-hls-control.js'
|
||||
|
||||
declare const artplayerPluginHlsControl: typeof Definition.default
|
||||
|
||||
declare namespace artplayerPluginHlsControl {
|
||||
type QualityLevel = Definition.QualityLevel
|
||||
type AudioTrack = Definition.AudioTrack
|
||||
type Config<Item extends object = object> = Definition.Config<Item>
|
||||
type Option<Level extends object = QualityLevel, Track extends object = AudioTrack> = Definition.Option<Level, Track>
|
||||
type Result = Definition.Result
|
||||
}
|
||||
|
||||
export = artplayerPluginHlsControl
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default } from './artplayer-plugin-hls-control.cjs'
|
||||
export type { AudioTrack, Config, Option, QualityLevel, Result } from './artplayer-plugin-hls-control.js'
|
||||
+25
-3
@@ -1,16 +1,38 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
|
||||
interface Config {
|
||||
export interface QualityLevel {
|
||||
height: number
|
||||
name?: string
|
||||
}
|
||||
|
||||
export interface AudioTrack {
|
||||
id: number
|
||||
name: string
|
||||
lang?: string
|
||||
language?: string
|
||||
}
|
||||
|
||||
export interface Config<Item extends object = object> {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
getName?: (level: object) => string
|
||||
/** Plain callback; current-label calls omit index. SDK objects retain their identity. */
|
||||
getName?: (item: Item, index?: number) => string
|
||||
}
|
||||
|
||||
declare const artplayerPluginHlsControl: (option: { quality?: Config, audio?: Config }) => (art: Artplayer) => {
|
||||
export interface Option<Level extends object = QualityLevel, Track extends object = AudioTrack> {
|
||||
quality?: Config<Level>
|
||||
audio?: Config<Track>
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
name: 'artplayerPluginHlsControl'
|
||||
update: () => void
|
||||
}
|
||||
|
||||
declare function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option?: Option<Level, Track>): (art: Artplayer) => Result
|
||||
// Keep the required last signature for historical Parameters<typeof factory>[0] consumers.
|
||||
declare function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track>): (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginHlsControl
|
||||
Reference in new issue
Block a user