mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-18 19:01:20 -08:00
refactor(dash): [PKG-DASH-04] migrate strict TypeScript and compatible declarations
This commit is contained in:
1 parent
7de04573b6
commit
6840544e0e
38 files changed
+1744
-102
No files matched your search
@@ -2,4 +2,5 @@ node_modules
|
||||
.DS_Store
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
src
|
||||
src
|
||||
tsconfig.json
|
||||
@@ -8,18 +8,20 @@ destroys it, changes its source, or adds a runtime dependency on dash.js.
|
||||
|
||||
## Module map
|
||||
|
||||
| File | Responsibility |
|
||||
| --- | --- |
|
||||
| `src/index.js` | Deferred installation, media identity, update revisions, event subscription and cleanup |
|
||||
| `src/sdk.js` | 4.x qualityIndex vs 5.x representation ID access and manual/Auto selection |
|
||||
| `src/mapping.js` | Names, current item matching, duplicate labels and selector ordering |
|
||||
| `src/menu.js` | Existing control/setting registries, menu ownership and guarded selection callbacks |
|
||||
| `src/audio.svg`, `src/quality.svg` | Existing setting icons |
|
||||
| `types/artplayer-plugin-dash-control.d.ts` | Existing public declarations; precise TS migration follows in PKG-DASH-04 |
|
||||
| File | Responsibility |
|
||||
| ------------------------------------------ | --------------------------------------------------------------------------------------- |
|
||||
| `src/index.ts` | Deferred installation, media identity, update revisions, event subscription and cleanup |
|
||||
| `src/sdk.ts` | 4.x qualityIndex vs 5.x representation ID access and manual/Auto selection |
|
||||
| `src/mapping.ts` | Names, current item matching, duplicate labels and selector ordering |
|
||||
| `src/menu.ts` | Existing control/setting registries, menu ownership and guarded selection callbacks |
|
||||
| `src/audio.svg`, `src/quality.svg` | Existing setting icons |
|
||||
| `types/artplayer-plugin-dash-control.d.ts` | Public options, generic SDK inputs and callable result |
|
||||
|
||||
Dependencies flow from the entry into mapping/menu, and from mapping into the SDK
|
||||
adapter. Mapping has no DOM dependency. Menu receives a model and validity callback;
|
||||
it does not choose SDK versions. This is the structural step, still in JavaScript.
|
||||
it does not choose SDK versions. All five owned modules are checked with strict
|
||||
TypeScript, noUncheckedIndexedAccess, and skipLibCheck=false; there are no remaining
|
||||
owned JavaScript modules in this package.
|
||||
|
||||
## Selection and lifetime
|
||||
|
||||
@@ -54,6 +56,36 @@ Keep `dash-quality`/`dash-audio`, selector shape, right control placement/paddin
|
||||
setting width/icons, defaults and unbound getName calls compatible. Do not use a
|
||||
filtered representation array index or absoluteIndex as the SDK 5 selection key.
|
||||
|
||||
## Types and compatibility
|
||||
|
||||
`src/types.ts` describes the narrow SDK and registry surfaces, menu models, event
|
||||
names, labels, and cleanup callbacks. SDK keys may be absent in malformed external
|
||||
data; the internal types retain that possibility instead of asserting every value
|
||||
exists. SDK methods are optional by generation. Non-null assertions in `sdk.ts`
|
||||
preserve the selected method family's historical synchronous failure when a caller
|
||||
provides an incomplete SDK. They do not validate the whole SDK at runtime.
|
||||
|
||||
The entry casts only the externally augmented ArtPlayer boundary to the narrow host.
|
||||
The non-empty track check protects the fallback item. Quality sorting casts apply
|
||||
before the synthetic Auto row is appended, and the manual selection key cast follows
|
||||
the Auto branch check. These assertions do not generate runtime conversions or mask
|
||||
the controlled error/identity tests. Changes to SDK capability detection belong in
|
||||
`sdk.ts`, not in a global `any` or ambient module escape.
|
||||
|
||||
Public `Config`, `Option`, `QualityLevel`, `AudioTrack`, and `Result` are named types.
|
||||
Default callbacks infer known SDK fields; explicit generic parameters or callback
|
||||
annotations accept a caller's more detailed SDK interfaces. Original object-based
|
||||
formatters remain valid. The optional overload supports omitted/undefined options;
|
||||
the last required overload preserves historical `Parameters<typeof factory>[0]`.
|
||||
Formatters still receive exactly one argument and return a string; update returns
|
||||
void synchronously. No global augmentation claims every ArtPlayer has a DASH SDK.
|
||||
|
||||
The historical `.d.ts` path stays available. `.d.cts` exports a callable CommonJS
|
||||
value with a type namespace; `.d.mts` bridges ESM default/named types. Runtime root
|
||||
and legacy paths are unchanged. `typesVersions` supports old Node10 type resolution
|
||||
for the legacy subpath. The online editor declaration is generated by `yarn build:ts`
|
||||
and checked standalone against both TS 4.3.5 and 5.9.3, then consumed by real Monaco.
|
||||
|
||||
## Validation and next work
|
||||
|
||||
Run at the workspace root with pinned Node and Yarn:
|
||||
@@ -62,6 +94,9 @@ Run at the workspace root with pinned Node and Yarn:
|
||||
yarn test:dash-control
|
||||
yarn build artplayer-plugin-dash-control
|
||||
yarn test:browser test/browser/dash-control.spec.js --trace on
|
||||
yarn test:browser test/browser/dash-editor-types.spec.js --trace on
|
||||
yarn build:ts
|
||||
yarn test:dash-types-package
|
||||
yarn ci:check
|
||||
```
|
||||
|
||||
@@ -71,6 +106,14 @@ contracts and lifecycle tests; use the operating system's path delimiter.
|
||||
and result/trace directory before running another suite because the output is shared.
|
||||
|
||||
Tests use frozen npm 1.1.0, a frozen pre-refactor 5.x implementation, and candidates.
|
||||
`test/types/dash-source.ts` checks source/public factory compatibility;
|
||||
`test/types/dash-control.ts` covers module modes and rejects invalid calls. The
|
||||
legacy fixture is checked against the actual published declaration and candidate.
|
||||
`test:dash-types-package` packs the current core and DASH with Yarn, installs the
|
||||
tarballs offline outside the workspace, repeats a frozen install and checks all
|
||||
public type modes without resolving any workspace source. It also verifies that
|
||||
implementation files/config do not leak into the archive. This is type acceptance;
|
||||
the full installed runtime and SDK release matrix still belongs to PKG-DASH-06/05.
|
||||
Browser tests exercise real old/new core DOM, menu clicks, native MP4 and cleanup,
|
||||
with controlled SDK methods. They do not load dash.js or test MPD/ABR decoding.
|
||||
PKG-DASH-05 must verify pinned dash.js 4.5.2 and 5.2.1 with real adaptive media and
|
||||
|
||||
+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.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const n=e.get(t.html);return n?(t.default&&Object.assign(n,t),!1):(e.set(t.html,t),!0)})}function e(t,e,n){let o;const r=new Map;function l(n,o=r.get(n)){if(!o||r.get(n)!==o)return;r.delete(n);const l=t[n];"controls"===n&&l.cache?.get&&l.cache.get(e)?.option?.onSelect!==o||"setting"===n&&l.find&&l.find(e)?.onSelect!==o||l.remove(e)}function i(){let t;o=void 0;for(const[n,o]of[...r])try{l(n,o)}catch(e){t||(t=e)}if(t)throw t}return{update:function(c,s,u){if(!s)return void i();const a={};o=a;const f=()=>a===o&&u(),d=e=>f()?(s.select(e,f),f()?(t.notice.show=`${s.title}: ${e.html}`,f()&&c.control&&t.controls.check(e),f()&&c.setting&&t.setting.check(e),e.html):e.html):e.html;c.control?(r.set("controls",d),t.controls.update({name:e,position:"right",html:s.html,style:{padding:"0 10px"},selector:s.selector,onSelect:d})):l("controls"),f()&&(c.setting?(r.set("setting",d),t.setting.update({name:e,tooltip:s.html,html:s.title,icon:n,width:200,selector:s.selector,onSelect:d})):l("setting"))},clear:i}}return function(n={}){return o=>{const{$video:r}=o.template,{errorHandle:l}=o.constructor.utils;let i=!1,c=0;const s=e(o,"dash-quality",'<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>'),u=e(o,"dash-audio",'<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>'),a=[];function f(t=()=>!0){let e;for(const o of[s.clear,u.clear]){if(!t())break;try{o()}catch(n){e||(e=n)}}if(e)throw e}function d(){if(i||o.isDestroy)return;const e=++c,a=o.dash,d=()=>!i&&!o.isDestroy&&e===c&&o.dash===a,h=()=>d()&&a.getVideoElement()===r&&d();try{if(l(a.getVideoElement()===r,'Cannot find instance of DASH from "art.dash"'),!d())return;const e=n.quality||{},o=function(e,n,o){const r=function(t){const e="function"===typeof t.getRepresentationsByType;return{levels:()=>e?t.getRepresentationsByType("video"):t.getBitrateInfoListFor("video"),current(n){if(e)return t.getCurrentRepresentationForType("video");const o=t.getQualityFor("video");return n.find(t=>t.qualityIndex===o)},item:(t,n,o,r)=>e?{value:n,id:t.id,default:!r&&null!=o&&t.id===o.id}:{value:t.qualityIndex,default:!r&&null!=o&&t.qualityIndex===o.qualityIndex},select(n,o){const r="auto"===n.value;t.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:r}}}}),!r&&o()&&(e?t.setRepresentationForTypeById("video",n.id):t.setQualityFor("video",n.value))}}}(e),l=r.levels();if(!o()||!l?.length)return null;const i=n.auto||"Auto",c=n.getName||(t=>`${t.height}p`),s=r.current(l);if(!o())return null;const u=e.getSettings().streaming.abr.autoSwitchBitrate.video;if(!o())return null;const a=!u&&s?c(s):i;if(!o())return null;const f=[];for(const[t,h]of l.entries()){const e=c(h);if(!o())return null;f.push({html:e,...r.item(h,t,s,u)})}const d=t(f).sort((t,e)=>e.value-t.value);return d.push({html:i,value:"auto",default:u}),{html:a,title:n.title||"Quality",selector:d,select:r.select}}(a,e,h);if(!h())return;if(s.update(e,o,h),!h())return;const i=n.audio||{},c=function(e,n,o){const r=e.getTracksFor("audio");if(!o()||!r?.length)return null;const l=n.auto||"Auto",i=n.getName||(t=>t.lang||t.id),c=e.getCurrentTrackFor("audio")||r[0];if(!o())return null;const s=c?i(c):l;if(!o())return null;const u=function(t,e){if(t.includes(e))return e;if(null==e.id&&null==e.index)return;const n=t.filter(t=>["id","index","lang"].every(n=>null==e[n]||t[n]===e[n]));return 1===n.length?n[0]:void 0}(r,c),a=[];for(const t of r){const e=i(t);if(!o())return null;a.push({html:e,value:t,default:t===u})}const f=t(a);return{html:s,title:n.title||"Audio",selector:f,select:t=>e.setCurrentTrack(t.value)}}(a,i,h);h()&&u.update(i,c,h)}catch(g){if(d()){const t=++c;try{f(()=>c===t)}catch(p){console.warn("ArtPlayer DASH cleanup failed:",p)}}throw g}}function h(){if(i)return;let t;i=!0,c++;const e=[f,...a.splice(0).map(([t,e])=>()=>o.off(t,e))Line truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";function t(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const n=e.get(t.html);return n?(t.default&&Object.assign(n,t),!1):(e.set(t.html,t),!0)})}function e(t,e,n){let o;const r=new Map;function l(n,o=r.get(n)){if(!o||r.get(n)!==o)return;r.delete(n);const l=t[n];"controls"===n&&l.cache?.get&&l.cache.get(e)?.option?.onSelect!==o||"setting"===n&&l.find&&l.find(e)?.onSelect!==o||l.remove(e)}function i(){let t;o=void 0;for(const[n,o]of[...r])try{l(n,o)}catch(e){t||(t=e)}if(t)throw t}return{update:function(c,s,u){if(!s)return void i();const a={};o=a;const f=()=>a===o&&u(),d=e=>f()?(s.select(e,f),f()?(t.notice.show=`${s.title}: ${e.html}`,f()&&c.control&&t.controls.check(e),f()&&c.setting&&t.setting.check(e),e.html):e.html):e.html;c.control?(r.set("controls",d),t.controls.update({name:e,position:"right",html:s.html,style:{padding:"0 10px"},selector:s.selector,onSelect:d})):l("controls"),f()&&(c.setting?(r.set("setting",d),t.setting.update({name:e,tooltip:s.html,html:s.title,icon:n,width:200,selector:s.selector,onSelect:d})):l("setting"))},clear:i}}return function(n={}){return o=>{const r=o,{$video:l}=r.template,{errorHandle:i}=r.constructor.utils;let c=!1,s=0;const u=e(r,"dash-quality",'<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>'),a=e(r,"dash-audio",'<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>'),f=[];function d(t=()=>!0){let e;for(const o of[u.clear,a.clear]){if(!t())break;try{o()}catch(n){e||(e=n)}}if(e)throw e}function h(){if(c||r.isDestroy)return;const e=++s,o=r.dash,f=()=>!c&&!r.isDestroy&&e===s&&r.dash===o,h=()=>f()&&o.getVideoElement()===l&&f();try{if(i(o.getVideoElement()===l,'Cannot find instance of DASH from "art.dash"'),!f())return;const e=n.quality||{},r=function(e,n,o){const r=function(t){const e="function"===typeof t.getRepresentationsByType;return{levels:()=>e?t.getRepresentationsByType("video"):t.getBitrateInfoListFor("video"),current(n){if(e)return t.getCurrentRepresentationForType("video");const o=t.getQualityFor("video");return n.find(t=>t.qualityIndex===o)},item:(t,n,o,r)=>e?{value:n,id:t.id,default:!r&&null!=o&&t.id===o.id}:{value:t.qualityIndex,default:!r&&null!=o&&t.qualityIndex===o.qualityIndex},select(n,o){const r="auto"===n.value;t.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:r}}}}),!r&&o()&&(e?t.setRepresentationForTypeById("video",n.id):t.setQualityFor("video",n.value))}}}(e),l=r.levels();if(!o()||!l?.length)return null;const i=n.auto||"Auto",c=n.getName||(t=>`${t.height}p`),s=r.current(l);if(!o())return null;const u=e.getSettings().streaming.abr.autoSwitchBitrate.video;if(!o())return null;const a=!u&&s?c(s):i;if(!o())return null;const f=[];for(const[t,h]of l.entries()){const e=c(h);if(!o())return null;f.push({html:e,...r.item(h,t,s,u)})}const d=t(f).sort((t,e)=>e.value-t.value);return d.push({html:i,value:"auto",default:u}),{html:a,title:n.title||"Quality",selector:d,select:r.select}}(o,e,h);if(!h())return;if(u.update(e,r,h),!h())return;const c=n.audio||{},s=function(e,n,o){const r=e.getTracksFor("audio");if(!o()||!r?.length)return null;const l=n.auto||"Auto",i=n.getName||(t=>t.lang||t.id),c=e.getCurrentTrackFor("audio")||r[0];if(!o())return null;const s=c?i(c):l;if(!o())return null;const u=function(t,e){if(t.includes(e))return e;if(null==e.id&&null==e.index)return;const n=["id","index","lang"],o=t.filter(t=>n.every(n=>null==e[n]||t[n]===e[n]));return 1===o.length?o[0]:void 0}(r,c),a=[];for(const t of r){const e=i(t);if(!o())return null;a.push({html:e,value:t,default:t===u})}const f=t(a);return{html:s,title:n.title||"Audio",selector:f,select:t=>e.setCurrentTrack(t.value)}}(o,c,h);h()&&a.update(c,s,h)}catch(g){if(f()){const t=++s;try{d(()=>s===t)}catch(p){console.warn("ArtPlayer DASH cleanup failed:",p)}}throw g}}function g(){if(c)return;let t;c=!0,s++;const e=[d,...f.splice(0).map(([t,e])=>()=>r.Line 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.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(e,n,o)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[n]=o,l=(t,l)=>{for(var i in l||(l={}))n.call(l,i)&&r(t,i,l[i]);if(e)for(var i of e(l))o.call(l,i)&&r(t,i,l[i]);return t};function i(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const n=e.get(t.html);return n?(t.default&&Object.assign(n,t),!1):(e.set(t.html,t),!0)})}function c(t,e,n){let o;const r=new Map;function l(n,o=r.get(n)){var l,i,c,u;if(!o||r.get(n)!==o)return;r.delete(n);const s=t[n];"controls"===n&&(null==(l=s.cache)?void 0:l.get)&&(null==(c=null==(i=s.cache.get(e))?void 0:i.option)?void 0:c.onSelect)!==o||"setting"===n&&s.find&&(null==(u=s.find(e))?void 0:u.onSelect)!==o||s.remove(e)}function i(){let t;o=void 0;for(const[n,o]of[...r])try{l(n,o)}catch(e){t||(t=e)}if(t)throw t}return{update:function(c,u,s){if(!u)return void i();const a={};o=a;const f=()=>a===o&&s(),d=e=>f()?(u.select(e,f),f()?(t.notice.show=`${u.title}: ${e.html}`,f()&&c.control&&t.controls.check(e),f()&&c.setting&&t.setting.check(e),e.html):e.html):e.html;c.control?(r.set("controls",d),t.controls.update({name:e,position:"right",html:u.html,style:{padding:"0 10px"},selector:u.selector,onSelect:d})):l("controls"),f()&&(c.setting?(r.set("setting",d),t.setting.update({name:e,tooltip:u.html,html:u.title,icon:n,width:200,selector:u.selector,onSelect:d})):l("setting"))},clear:i}}return function(t={}){return e=>{const{$video:n}=e.template,{errorHandle:o}=e.constructor.utils;let r=!1,u=0;const s=c(e,"dash-quality",'<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>'),a=c(e,"dash-audio",'<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>'),f=[];function d(t=()=>!0){let e;for(const o of[s.clear,a.clear]){if(!t())break;try{o()}catch(n){e||(e=n)}}if(e)throw e}function h(){if(r||e.isDestroy)return;const c=++u,f=e.dash,h=()=>!r&&!e.isDestroy&&c===u&&e.dash===f,p=()=>h()&&f.getVideoElement()===n&&h();try{if(o(f.getVideoElement()===n,'Cannot find instance of DASH from "art.dash"'),!h())return;const e=t.quality||{},r=function(t,e,n){const o=function(t){const e="function"===typeof t.getRepresentationsByType;return{levels:()=>e?t.getRepresentationsByType("video"):t.getBitrateInfoListFor("video"),current(n){if(e)return t.getCurrentRepresentationForType("video");const o=t.getQualityFor("video");return n.find(t=>t.qualityIndex===o)},item:(t,n,o,r)=>e?{value:n,id:t.id,default:!r&&null!=o&&t.id===o.id}:{value:t.qualityIndex,default:!r&&null!=o&&t.qualityIndex===o.qualityIndex},select(n,o){const r="auto"===n.value;t.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:r}}}}),!r&&o()&&(e?t.setRepresentationForTypeById("video",n.id):t.setQualityFor("video",n.value))}}}(t),r=o.levels();if(!n()||!(null==r?void 0:r.length))return null;const c=e.auto||"Auto",u=e.getName||(t=>`${t.height}p`),s=o.current(r);if(!n())return null;const a=t.getSettings().streaming.abr.autoSwitchBitrate.video;if(!n())return null;const f=!a&&s?u(s):c;if(!n())return null;const d=[];for(const[i,p]of r.entries()){const t=u(p);if(!n())return null;d.push(l({html:t},o.item(p,i,s,a)))}const h=i(d).sort((t,e)=>e.value-t.value);return h.push({html:c,value:"auto",default:a}),{html:f,title:e.title||"Quality",selector:h,select:o.select}}(f,e,p);if(!p())return;if(s.update(e,r,p),!p())return;const c=t.audio||{},u=function(t,e,n){const o=t.getTracksFor("audio");if(!n()||!(null==o?void 0:o.length))return null;const r=e.auto||"Auto",l=e.getName||(t=>t.lang||t.id),c=t.getCurrentTrackFor("audio")||o[0];if(!n())return null;const u=c?l(c):r;if(!n())return null;const s=function(t,e){if(t.includes(e))return e;if(null==e.id&&null==e.index)return;const n=t.filter(t=>["id","index","lang"].every(n=>null==e[n]||t[n]===e[n]));return 1===n.lLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginDashControl=e(),define(function(){return t.artplayerPluginDashControl})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginDashControl=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(e,n,o)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[n]=o,l=(t,l)=>{for(var i in l||(l={}))n.call(l,i)&&r(t,i,l[i]);if(e)for(var i of e(l))o.call(l,i)&&r(t,i,l[i]);return t};function i(t){const e=new Map;return t.filter(t=>{if(void 0===t.html)return!0;const n=e.get(t.html);return n?(t.default&&Object.assign(n,t),!1):(e.set(t.html,t),!0)})}function c(t,e,n){let o;const r=new Map;function l(n,o=r.get(n)){var l,i,c,u;if(!o||r.get(n)!==o)return;r.delete(n);const s=t[n];"controls"===n&&(null==(l=s.cache)?void 0:l.get)&&(null==(c=null==(i=s.cache.get(e))?void 0:i.option)?void 0:c.onSelect)!==o||"setting"===n&&s.find&&(null==(u=s.find(e))?void 0:u.onSelect)!==o||s.remove(e)}function i(){let t;o=void 0;for(const[n,o]of[...r])try{l(n,o)}catch(e){t||(t=e)}if(t)throw t}return{update:function(c,u,s){if(!u)return void i();const a={};o=a;const f=()=>a===o&&s(),d=e=>f()?(u.select(e,f),f()?(t.notice.show=`${u.title}: ${e.html}`,f()&&c.control&&t.controls.check(e),f()&&c.setting&&t.setting.check(e),e.html):e.html):e.html;c.control?(r.set("controls",d),t.controls.update({name:e,position:"right",html:u.html,style:{padding:"0 10px"},selector:u.selector,onSelect:d})):l("controls"),f()&&(c.setting?(r.set("setting",d),t.setting.update({name:e,tooltip:u.html,html:u.title,icon:n,width:200,selector:u.selector,onSelect:d})):l("setting"))},clear:i}}return function(t={}){return e=>{const n=e,{$video:o}=n.template,{errorHandle:r}=n.constructor.utils;let u=!1,s=0;const a=c(n,"dash-quality",'<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>'),f=c(n,"dash-audio",'<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>'),d=[];function h(t=()=>!0){let e;for(const o of[a.clear,f.clear]){if(!t())break;try{o()}catch(n){e||(e=n)}}if(e)throw e}function p(){if(u||n.isDestroy)return;const e=++s,c=n.dash,d=()=>!u&&!n.isDestroy&&e===s&&n.dash===c,p=()=>d()&&c.getVideoElement()===o&&d();try{if(r(c.getVideoElement()===o,'Cannot find instance of DASH from "art.dash"'),!d())return;const e=t.quality||{},n=function(t,e,n){const o=function(t){const e="function"===typeof t.getRepresentationsByType;return{levels:()=>e?t.getRepresentationsByType("video"):t.getBitrateInfoListFor("video"),current(n){if(e)return t.getCurrentRepresentationForType("video");const o=t.getQualityFor("video");return n.find(t=>t.qualityIndex===o)},item:(t,n,o,r)=>e?{value:n,id:t.id,default:!r&&null!=o&&t.id===o.id}:{value:t.qualityIndex,default:!r&&null!=o&&t.qualityIndex===o.qualityIndex},select(n,o){const r="auto"===n.value;t.updateSettings({streaming:{abr:{autoSwitchBitrate:{video:r}}}}),!r&&o()&&(e?t.setRepresentationForTypeById("video",n.id):t.setQualityFor("video",n.value))}}}(t),r=o.levels();if(!n()||!(null==r?void 0:r.length))return null;const c=e.auto||"Auto",u=e.getName||(t=>`${t.height}p`),s=o.current(r);if(!n())return null;const a=t.getSettings().streaming.abr.autoSwitchBitrate.video;if(!n())return null;const f=!a&&s?u(s):c;if(!n())return null;const d=[];for(const[i,p]of r.entries()){const t=u(p);if(!n())return null;d.push(l({html:t},o.item(p,i,s,a)))}const h=i(d).sort((t,e)=>e.value-t.value);return h.push({html:c,value:"auto",default:a}),{html:f,title:e.title||"Quality",selector:h,select:o.select}}(c,e,p);if(!p())return;if(a.update(e,n,p),!p())return;const u=t.audio||{},s=function(t,e,n){const o=t.getTracksFor("audio");if(!n()||!(null==o?void 0:o.length))return null;const r=e.auto||"Auto",l=e.getName||(t=>t.lang||t.id),c=t.getCurrentTrackFor("audio")||o[0];if(!n())return null;const u=c?l(c):r;if(!n())return null;const s=function(t,e){if(t.includes(e))return e;if(null==e.id&&null==e.index)return;const n=["id","index","lang"],o=t.filter(t=>n.every(n=>null==e[n]||t[n]===e[n]));returLine truncated
|
||||
+6
-3
@@ -77,7 +77,8 @@ function selectedTrack(tracks, current) {
|
||||
return current;
|
||||
if (current.id == null && current.index == null)
|
||||
return void 0;
|
||||
const matching = tracks.filter((track) => ["id", "index", "lang"].every((key) => current[key] == null || track[key] === current[key]));
|
||||
const fields = ["id", "index", "lang"];
|
||||
const matching = tracks.filter((track) => fields.every((key) => current[key] == null || track[key] === current[key]));
|
||||
return matching.length === 1 ? matching[0] : void 0;
|
||||
}
|
||||
function audioModel(dash, config, active) {
|
||||
@@ -170,7 +171,8 @@ function createMenu(art, name, icon) {
|
||||
}
|
||||
const $quality = '<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>';
|
||||
function artplayerPluginDashControl(option = {}) {
|
||||
return (art) => {
|
||||
return (player) => {
|
||||
const art = player;
|
||||
const { $video } = art.template;
|
||||
const { errorHandle } = art.constructor.utils;
|
||||
let closed = false;
|
||||
@@ -244,7 +246,8 @@ function artplayerPluginDashControl(option = {}) {
|
||||
throw failure;
|
||||
}
|
||||
try {
|
||||
for (const entry of [["ready", update], ["restart", update], ["destroy", destroy]]) {
|
||||
const entries = [["ready", update], ["restart", update], ["destroy", destroy]];
|
||||
for (const entry of entries) {
|
||||
if (closed)
|
||||
break;
|
||||
subscriptions.push(entry);
|
||||
|
||||
@@ -19,19 +19,36 @@
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/artplayer-plugin-dash-control.d.ts",
|
||||
"import": "./dist/artplayer-plugin-dash-control.mjs",
|
||||
"require": "./dist/artplayer-plugin-dash-control.js"
|
||||
"import": {
|
||||
"types": "./types/artplayer-plugin-dash-control.d.mts",
|
||||
"default": "./dist/artplayer-plugin-dash-control.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-plugin-dash-control.d.cts",
|
||||
"default": "./dist/artplayer-plugin-dash-control.js"
|
||||
}
|
||||
},
|
||||
"./legacy": {
|
||||
"types": "./types/artplayer-plugin-dash-control.d.ts",
|
||||
"import": "./dist/artplayer-plugin-dash-control.legacy.js",
|
||||
"require": "./dist/artplayer-plugin-dash-control.legacy.js"
|
||||
"import": {
|
||||
"types": "./types/artplayer-plugin-dash-control.d.cts",
|
||||
"default": "./dist/artplayer-plugin-dash-control.legacy.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-plugin-dash-control.d.cts",
|
||||
"default": "./dist/artplayer-plugin-dash-control.legacy.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-dash-control.js",
|
||||
"module": "./dist/artplayer-plugin-dash-control.mjs",
|
||||
"types": "./types/artplayer-plugin-dash-control.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-dash-control.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"legacy": [
|
||||
"types/artplayer-plugin-dash-control.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-12
@@ -1,20 +1,25 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { AudioTrack, Option, QualityLevel, Result } from '../types/artplayer-plugin-dash-control'
|
||||
import type { AudioItem, Cleanup, EventName, Host, QualityItem, Valid } from './types'
|
||||
import $audio from './audio.svg?raw'
|
||||
import { audioModel, qualityModel } from './mapping'
|
||||
import { createMenu } from './menu'
|
||||
import $quality from './quality.svg?raw'
|
||||
|
||||
export default function artplayerPluginDashControl(option = {}) {
|
||||
return (art) => {
|
||||
export default function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track> = {}) {
|
||||
return (player: Artplayer): Result => {
|
||||
// art.dash is caller-owned; update keeps the historical SDK/media validation boundary.
|
||||
const art = player as unknown as Host<Level, Track>
|
||||
const { $video } = art.template
|
||||
const { errorHandle } = art.constructor.utils
|
||||
let closed = false
|
||||
let revision = 0
|
||||
const quality = createMenu(art, 'dash-quality', $quality)
|
||||
const audio = createMenu(art, 'dash-audio', $audio)
|
||||
const subscriptions = []
|
||||
const quality = createMenu<QualityItem>(art, 'dash-quality', $quality)
|
||||
const audio = createMenu<AudioItem<Track>>(art, 'dash-audio', $audio)
|
||||
const subscriptions: [EventName, Cleanup][] = []
|
||||
|
||||
function clear(current = () => true) {
|
||||
let failure
|
||||
function clear(current: Valid = () => true): void {
|
||||
let failure: unknown
|
||||
for (const cleanup of [quality.clear, audio.clear]) {
|
||||
if (!current())
|
||||
break
|
||||
@@ -29,11 +34,11 @@ export default function artplayerPluginDashControl(option = {}) {
|
||||
throw failure
|
||||
}
|
||||
|
||||
function update() {
|
||||
function update(): void {
|
||||
if (closed || art.isDestroy)
|
||||
return
|
||||
const version = ++revision
|
||||
const dash = art.dash
|
||||
const dash = art.dash!
|
||||
const current = () => !closed && !art.isDestroy && version === revision && art.dash === dash
|
||||
const valid = () => current() && dash.getVideoElement() === $video && current()
|
||||
try {
|
||||
@@ -66,12 +71,12 @@ export default function artplayerPluginDashControl(option = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
function destroy(): void {
|
||||
if (closed)
|
||||
return
|
||||
closed = true
|
||||
revision++
|
||||
let failure
|
||||
let failure: unknown
|
||||
const actions = [clear, ...subscriptions.splice(0).map(([name, callback]) => () => art.off(name, callback))]
|
||||
for (const action of actions) {
|
||||
try {
|
||||
@@ -86,7 +91,8 @@ export default function artplayerPluginDashControl(option = {}) {
|
||||
}
|
||||
|
||||
try {
|
||||
for (const entry of [['ready', update], ['restart', update], ['destroy', destroy]]) {
|
||||
const entries: [EventName, Cleanup][] = [['ready', update], ['restart', update], ['destroy', destroy]]
|
||||
for (const entry of entries) {
|
||||
if (closed)
|
||||
break
|
||||
subscriptions.push(entry)
|
||||
+17
-12
@@ -1,7 +1,9 @@
|
||||
import type { Config } from '../types/artplayer-plugin-dash-control'
|
||||
import type { AudioFields, AudioItem, Dash, Label, MenuModel, QualityFields, QualityItem, SelectorItem, Valid } from './types'
|
||||
import { qualityAdapter } from './sdk'
|
||||
|
||||
function uniqueLabels(items) {
|
||||
const seen = new Map()
|
||||
function uniqueLabels<Item extends SelectorItem>(items: Item[]): Item[] {
|
||||
const seen = new Map<Label, Item>()
|
||||
return items.filter((item) => {
|
||||
if (item.html === undefined)
|
||||
return true
|
||||
@@ -16,13 +18,13 @@ function uniqueLabels(items) {
|
||||
})
|
||||
}
|
||||
|
||||
export function qualityModel(dash, config, active) {
|
||||
export function qualityModel<Level extends object, Track extends object>(dash: Dash<Level, Track>, config: Config<Level>, active: Valid): MenuModel<QualityItem> | null {
|
||||
const adapter = qualityAdapter(dash)
|
||||
const levels = adapter.levels()
|
||||
if (!active() || !levels?.length)
|
||||
return null
|
||||
const auto = config.auto || 'Auto'
|
||||
const getName = config.getName || (level => `${level.height}p`)
|
||||
const getName = config.getName || ((level: QualityFields) => `${level.height}p`)
|
||||
const selected = adapter.current(levels)
|
||||
if (!active())
|
||||
return null
|
||||
@@ -32,7 +34,7 @@ export function qualityModel(dash, config, active) {
|
||||
const html = !automatic && selected ? getName(selected) : auto
|
||||
if (!active())
|
||||
return null
|
||||
const items = []
|
||||
const items: QualityItem[] = []
|
||||
for (const [index, level] of levels.entries()) {
|
||||
const label = getName(level)
|
||||
if (!active())
|
||||
@@ -40,34 +42,37 @@ export function qualityModel(dash, config, active) {
|
||||
items.push({ html: label, ...adapter.item(level, index, selected, automatic) })
|
||||
}
|
||||
const selector = uniqueLabels(items)
|
||||
.sort((left, right) => right.value - left.value)
|
||||
// The synthetic Auto item is appended after sorting SDK numeric keys.
|
||||
.sort((left, right) => (right.value as number) - (left.value as number))
|
||||
selector.push({ html: auto, value: 'auto', default: automatic })
|
||||
return { html, title: config.title || 'Quality', selector, select: adapter.select }
|
||||
}
|
||||
|
||||
function selectedTrack(tracks, current) {
|
||||
function selectedTrack<Track extends AudioFields>(tracks: Track[], current: Track): Track | undefined {
|
||||
if (tracks.includes(current))
|
||||
return current
|
||||
if (current.id == null && current.index == null)
|
||||
return undefined
|
||||
const matching = tracks.filter(track => ['id', 'index', 'lang'].every(key => current[key] == null || track[key] === current[key]))
|
||||
const fields = ['id', 'index', 'lang'] as const
|
||||
const matching = tracks.filter(track => fields.every(key => current[key] == null || track[key] === current[key]))
|
||||
return matching.length === 1 ? matching[0] : undefined
|
||||
}
|
||||
|
||||
export function audioModel(dash, config, active) {
|
||||
export function audioModel<Level extends object, Track extends object>(dash: Dash<Level, Track>, config: Config<Track>, active: Valid): MenuModel<AudioItem<Track>> | null {
|
||||
const tracks = dash.getTracksFor('audio')
|
||||
if (!active() || !tracks?.length)
|
||||
return null
|
||||
const auto = config.auto || 'Auto'
|
||||
const getName = config.getName || (track => track.lang || track.id)
|
||||
const current = dash.getCurrentTrackFor('audio') || tracks[0]
|
||||
const getName = config.getName || ((track: AudioFields) => track.lang || track.id)
|
||||
// The non-empty list check above protects the fallback item.
|
||||
const current = dash.getCurrentTrackFor('audio') || tracks[0]!
|
||||
if (!active())
|
||||
return null
|
||||
const html = current ? getName(current) : auto
|
||||
if (!active())
|
||||
return null
|
||||
const selected = selectedTrack(tracks, current)
|
||||
const items = []
|
||||
const items: AudioItem<Track>[] = []
|
||||
for (const track of tracks) {
|
||||
const label = getName(track)
|
||||
if (!active())
|
||||
+10
-8
@@ -1,8 +1,10 @@
|
||||
export function createMenu(art, name, icon) {
|
||||
let current
|
||||
const owned = new Map()
|
||||
import type { DisplayConfig, Label, MenuHost, MenuModel, SelectorItem, Valid } from './types'
|
||||
|
||||
function remove(surface, callback = owned.get(surface)) {
|
||||
export function createMenu<Item extends SelectorItem>(art: MenuHost, name: string, icon: string) {
|
||||
let current: object | undefined
|
||||
const owned = new Map<'controls' | 'setting', (item: Item) => Label>()
|
||||
|
||||
function remove(surface: 'controls' | 'setting', callback = owned.get(surface)): void {
|
||||
if (!callback || owned.get(surface) !== callback)
|
||||
return
|
||||
owned.delete(surface)
|
||||
@@ -14,9 +16,9 @@ export function createMenu(art, name, icon) {
|
||||
registry.remove(name)
|
||||
}
|
||||
|
||||
function clear() {
|
||||
function clear(): void {
|
||||
current = undefined
|
||||
let failure
|
||||
let failure: unknown
|
||||
for (const [surface, callback] of [...owned]) {
|
||||
try {
|
||||
remove(surface, callback)
|
||||
@@ -29,7 +31,7 @@ export function createMenu(art, name, icon) {
|
||||
throw failure
|
||||
}
|
||||
|
||||
function update(config, model, active) {
|
||||
function update(config: DisplayConfig, model: MenuModel<Item> | null, active: Valid): void {
|
||||
if (!model) {
|
||||
clear()
|
||||
return
|
||||
@@ -37,7 +39,7 @@ export function createMenu(art, name, icon) {
|
||||
const state = {}
|
||||
current = state
|
||||
const valid = () => state === current && active()
|
||||
const onSelect = (item) => {
|
||||
const onSelect = (item: Item): Label => {
|
||||
if (!valid())
|
||||
return item.html
|
||||
model.select(item, valid)
|
||||
+9
-6
@@ -1,11 +1,14 @@
|
||||
export function qualityAdapter(dash) {
|
||||
import type { Dash, QualityAdapter } from './types'
|
||||
|
||||
export function qualityAdapter<Level extends object, Track extends object>(dash: Dash<Level, Track>): QualityAdapter<Level> {
|
||||
// Select one SDK method family. Invalid/incomplete SDKs keep synchronous method errors.
|
||||
const modern = typeof dash.getRepresentationsByType === 'function'
|
||||
return {
|
||||
levels: () => modern ? dash.getRepresentationsByType('video') : dash.getBitrateInfoListFor('video'),
|
||||
levels: () => modern ? dash.getRepresentationsByType!('video') : dash.getBitrateInfoListFor!('video'),
|
||||
current(levels) {
|
||||
if (modern)
|
||||
return dash.getCurrentRepresentationForType('video')
|
||||
const quality = dash.getQualityFor('video')
|
||||
return dash.getCurrentRepresentationForType!('video')
|
||||
const quality = dash.getQualityFor!('video')
|
||||
return levels.find(level => level.qualityIndex === quality)
|
||||
},
|
||||
item(level, index, selected, automatic) {
|
||||
@@ -18,9 +21,9 @@ export function qualityAdapter(dash) {
|
||||
dash.updateSettings({ streaming: { abr: { autoSwitchBitrate: { video: automatic } } } })
|
||||
if (!automatic && valid()) {
|
||||
if (modern)
|
||||
dash.setRepresentationForTypeById('video', item.id)
|
||||
dash.setRepresentationForTypeById!('video', item.id)
|
||||
else
|
||||
dash.setQualityFor('video', item.value)
|
||||
dash.setQualityFor!('video', item.value as number | undefined)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import type { Config } from '../types/artplayer-plugin-dash-control'
|
||||
|
||||
export type Label = string | number | undefined
|
||||
export type Identifier = string | number
|
||||
export type Valid = () => boolean
|
||||
export type Cleanup = () => void
|
||||
export type EventName = 'ready' | 'restart' | 'destroy'
|
||||
|
||||
export interface QualityFields {
|
||||
height?: number
|
||||
id?: Identifier
|
||||
qualityIndex?: number
|
||||
}
|
||||
|
||||
export interface AudioFields {
|
||||
id?: Identifier
|
||||
index?: number
|
||||
lang?: string
|
||||
}
|
||||
|
||||
export interface Dash<Level extends object = object, Track extends object = object> {
|
||||
getVideoElement: () => object | null
|
||||
getSettings: () => { streaming: { abr: { autoSwitchBitrate: { video: boolean } } } }
|
||||
updateSettings: (settings: { streaming: { abr: { autoSwitchBitrate: { video: boolean } } } }) => unknown
|
||||
getRepresentationsByType?: (type: 'video') => (Level & QualityFields)[] | null | undefined
|
||||
getCurrentRepresentationForType?: (type: 'video') => (Level & QualityFields) | null | undefined
|
||||
setRepresentationForTypeById?: (type: 'video', id: Identifier | undefined) => unknown
|
||||
getBitrateInfoListFor?: (type: 'video') => (Level & QualityFields)[] | null | undefined
|
||||
getQualityFor?: (type: 'video') => number
|
||||
setQualityFor?: (type: 'video', index: number | undefined) => unknown
|
||||
getTracksFor: (type: 'audio') => (Track & AudioFields)[] | null | undefined
|
||||
getCurrentTrackFor: (type: 'audio') => (Track & AudioFields) | null | undefined
|
||||
setCurrentTrack: (track: Track & AudioFields) => unknown
|
||||
}
|
||||
|
||||
export interface SelectorItem {
|
||||
html: Label
|
||||
default: boolean
|
||||
}
|
||||
|
||||
export interface QualityItem extends SelectorItem {
|
||||
value: number | 'auto' | undefined
|
||||
id?: Identifier
|
||||
}
|
||||
|
||||
export interface AudioItem<Track extends object> extends SelectorItem {
|
||||
value: Track & AudioFields
|
||||
}
|
||||
|
||||
export interface QualityAdapter<Level extends object> {
|
||||
levels: () => (Level & QualityFields)[] | null | undefined
|
||||
current: (levels: (Level & QualityFields)[]) => (Level & QualityFields) | null | undefined
|
||||
item: (level: Level & QualityFields, index: number, selected: (Level & QualityFields) | null | undefined, automatic: boolean) => Omit<QualityItem, 'html'>
|
||||
select: (item: QualityItem, valid: Valid) => void
|
||||
}
|
||||
|
||||
export interface MenuModel<Item extends SelectorItem> {
|
||||
html: Label
|
||||
title: string
|
||||
selector: Item[]
|
||||
select: (item: Item, valid: Valid) => unknown
|
||||
}
|
||||
|
||||
export interface MenuOption<Item extends SelectorItem> {
|
||||
name: string
|
||||
html: Label
|
||||
selector: Item[]
|
||||
onSelect: (item: Item) => Label
|
||||
position?: 'right'
|
||||
style?: { padding: string }
|
||||
tooltip?: Label
|
||||
icon?: string
|
||||
width?: number
|
||||
}
|
||||
|
||||
export interface Registry {
|
||||
update: <Item extends SelectorItem>(option: MenuOption<Item>) => unknown
|
||||
remove: (name: string) => unknown
|
||||
check: (item: SelectorItem) => unknown
|
||||
cache?: { get?: (name: string) => { option?: { onSelect?: unknown } } | undefined }
|
||||
find?: (name: string) => { onSelect?: unknown } | undefined
|
||||
}
|
||||
|
||||
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 } }
|
||||
isDestroy?: boolean
|
||||
dash?: Dash<Level, Track>
|
||||
on: (name: EventName, callback: Cleanup) => unknown
|
||||
off: (name: EventName, callback: Cleanup) => unknown
|
||||
}
|
||||
|
||||
export type DisplayConfig = Pick<Config, 'control' | 'setting'>
|
||||
@@ -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-dash-control.js'
|
||||
|
||||
declare const artplayerPluginDashControl: typeof Definition.default
|
||||
|
||||
declare namespace artplayerPluginDashControl {
|
||||
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 = artplayerPluginDashControl
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default } from './artplayer-plugin-dash-control.cjs'
|
||||
export type { AudioTrack, Config, Option, QualityLevel, Result } from './artplayer-plugin-dash-control.js'
|
||||
+28
-3
@@ -1,16 +1,41 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
|
||||
interface Config {
|
||||
export interface QualityLevel {
|
||||
height: number
|
||||
width?: number
|
||||
id?: string | number
|
||||
qualityIndex?: number
|
||||
bitrate?: number
|
||||
bitrateInKbit?: number
|
||||
}
|
||||
|
||||
export interface AudioTrack {
|
||||
id?: string | number
|
||||
index?: number
|
||||
lang?: string
|
||||
}
|
||||
|
||||
export interface Config<Item extends object = object> {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
getName?: (level: object) => string
|
||||
/** Called without a receiver or index, with the original SDK object. */
|
||||
getName?: (item: Item) => string
|
||||
}
|
||||
|
||||
declare const artplayerPluginDashControl: (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: 'artplayerPluginDashControl'
|
||||
update: () => void
|
||||
}
|
||||
|
||||
declare function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option?: Option<Level, Track>): (art: Artplayer) => Result
|
||||
// Preserve the required last signature for historical Parameters<typeof factory>[0] consumers.
|
||||
declare function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track>): (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginDashControl
|
||||
Reference in new issue
Block a user