mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-11 22:06:17 -08:00
fix(dash): [PKG-DASH-MENU-01] preserve settings navigation during SDK refresh
This commit is contained in:
1 parent
30f646be97
commit
88ce836f85
21 files changed
+769
-23
No files matched your search
@@ -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 r;const o=new Map;function i(n,r=o.get(n)){if(!r||o.get(n)!==r)return;o.delete(n);const i=t[n];"controls"===n&&i.cache?.get&&i.cache.get(e)?.option?.onSelect!==r||"setting"===n&&i.find&&i.find(e)?.onSelect!==r||i.remove(e)}function c(){let t;r=void 0;for(const[n,r]of[...o])try{i(n,r)}catch(e){t||(t=e)}if(t)throw t}return{update:function(s,a,l){if(!a)return void c();const u={};r=u;const f=()=>u===r&&l(),d=e=>f()?(a.select(e,f),f()?(t.notice.show=`${a.title}: ${e.html}`,f()&&s.control&&t.controls.check(e),f()&&s.setting&&t.setting.check(e),e.html):e.html):e.html;s.control?(o.set("controls",d),t.controls.update({name:e,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(s.setting?(o.set("setting",d),t.setting.update({name:e,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:c}}function n(t){let e;const n=n=>e===n&&t.active(n.dash),r=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function o(){const t=e;if(!t)return;let n;e=void 0,t.epoch++;for(const[e,o]of t.callbacks.splice(0))try{t.off.call(t.dash,e,o)}catch(r){n||(n=r)}if(n)throw n}function i(n,r){if(e===n){try{o()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!e&&t.active(n.dash))try{t.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",r)}function c(e){if(!n(e)||e.suspended||e.queued||e.running)return;e.queued=!0;const o=e.epoch;Promise.resolve().then(()=>{if(n(e)&&e.epoch===o&&!e.suspended){e.queued=!1,e.running=!0;try{e.automatic=r(e),n(e)&&t.refresh()}catch(c){i(e,c)}finally{e.running=!1}}})}return{bind:function(s){const a=e;if(a?.dash===s){const t=r(a);return void(n(a)&&(a.automatic=t,a.suspended=!1))}if(o(),e||!t.active(s)||"function"!==typeof s.on||"function"!==typeof s.off)return;const l={dash:s,off:s.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};e=l;const u=s.on;try{l.automatic=r(l);const e=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(l.suspended=!1),c(l)}]),o=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch{return}let r=!1;return()=>{if(!r&&e()){r=!0;try{const t=n.getVideoElement?.();if(!t?.seeking||!Number.isFinite(t.currentTime))return;const r=t.currentTime,o=n.getActiveStream?.(),i=n.getDashMetrics?.(),c=o?.getProcessors?.();if(!Array.isArray(c)||"function"!==typeof i?.getCurrentBufferLevel||"function"!==typeof i.addBufferLevel)return;for(const s of c){if(!e())return;const c=s.getType?.();if("audio"!==c&&"video"!==c)continue;const a=s.getBufferController?.();if("function"!==typeof a?.getRangeAt||"function"!==typeof a.getIsPruningInProgress||"function"!==typeof a.getAllRangesWithSafetyFactor)continue;const l=i.getCurrentBufferLevel(c),u=a.getRangeAt(r),f=null===u||u&&Number.isFinite(u.end)&&u.end<=r;if(!Number.isFinite(l)||l<=0||!f||!1!==a.getIsPruningInProgress())continue;const d=a.getAllRangesWithSafetyFactor(r);if(Array.isArray(d)&&0===d.length){if(!e()||n.getActiveStream?.()!==o||n.getDashMetrics?.()!==i||n.getVideoElement?.()!==t||t.currentTime!==r||!t.seeking||!e())return;i.addBufferLevel(c,new Date,0)}}}catch(t){console.warn("ArtPlayer DASH seek buffer refresh failed:",t)}finally{r=!1}}}}(s,()=>n(l)&&!l.suspended);o&&e.push(["playbackSeeking",o]),e.push(["playbackTimeUpdated",()=>{if(n(l)&&!l.suspended)try{const t=r(l);n(l)&&t!==l.automatic&&(l.automatic=t,c(l))}catch(t){i(l,t)}}]),e.push(["streamTeardownComplete",()=>{if(n(l)){l.epoch++,l.queued=!1,l.suspended=!0;try{t.reset()}catch(e){i(l,e)}}}]);for(const t of e){if(!n(l))break;l.callbacks.push(t),u.call(s,...t)}}catch(f){if(e===l)try{o()}catch(d){console.warn("ArtPlayer DASH subscription cleanup failed:",d)}throw f}},release:o}}return function(r={}){return o=>{const i=o,{$video:c}=i.template,{errorHandle:s}=i.constructor.utils;let a=!1,l=0;const u=e(i,"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 12Line 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 r;const o=new Map;function i(n,r=o.get(n)){if(!r||o.get(n)!==r)return;o.delete(n);const i=t[n];"controls"===n&&i.cache?.get&&i.cache.get(e)?.option?.onSelect!==r||"setting"===n&&i.find&&i.find(e)?.onSelect!==r||i.remove(e)}function c(){let t;r=void 0;for(const[n,r]of[...o])try{i(n,r)}catch(e){t||(t=e)}if(t)throw t}return{update:function(s,a,l){if(!a)return void c();const u={};r=u;const f=()=>u===r&&l(),d=e=>f()?(a.select(e,f),f()?(t.notice.show=`${a.title}: ${e.html}`,f()&&s.control&&t.controls.check(e),f()&&s.setting&&t.setting.check(e),e.html):e.html):e.html;s.control?(o.set("controls",d),t.controls.update({name:e,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(s.setting?(o.set("setting",d),t.setting.update({name:e,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:c,captureNavigation:function(n){const r=t.setting,i=r.find?.(e),c=o.get("setting");if(n()&&c&&!0===r.show&&i?.onSelect===c&&i.selector&&r.active===i.selector&&"function"===typeof r.render)return()=>{if(!n()||t.setting!==r||!0!==r.show||!r.option||r.active!==r.option)return;const i=r.find?.(e),c=o.get("setting");n()&&c&&i?.onSelect===c&&i.selector&&r.render?.(i.selector)}}}}function n(t){let e;const n=n=>e===n&&t.active(n.dash),r=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function o(){const t=e;if(!t)return;let n;e=void 0,t.epoch++;for(const[e,o]of t.callbacks.splice(0))try{t.off.call(t.dash,e,o)}catch(r){n||(n=r)}if(n)throw n}function i(n,r){if(e===n){try{o()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!e&&t.active(n.dash))try{t.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",r)}function c(e){if(!n(e)||e.suspended||e.queued||e.running)return;e.queued=!0;const o=e.epoch;Promise.resolve().then(()=>{if(n(e)&&e.epoch===o&&!e.suspended){e.queued=!1,e.running=!0;try{e.automatic=r(e),n(e)&&t.refresh()}catch(c){i(e,c)}finally{e.running=!1}}})}return{bind:function(s){const a=e;if(a?.dash===s){const t=r(a);return void(n(a)&&(a.automatic=t,a.suspended=!1))}if(o(),e||!t.active(s)||"function"!==typeof s.on||"function"!==typeof s.off)return;const l={dash:s,off:s.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};e=l;const u=s.on;try{l.automatic=r(l);const e=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(l.suspended=!1),c(l)}]),o=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch{return}let r=!1;return()=>{if(!r&&e()){r=!0;try{const t=n.getVideoElement?.();if(!t?.seeking||!Number.isFinite(t.currentTime))return;const r=t.currentTime,o=n.getActiveStream?.(),i=n.getDashMetrics?.(),c=o?.getProcessors?.();if(!Array.isArray(c)||"function"!==typeof i?.getCurrentBufferLevel||"function"!==typeof i.addBufferLevel)return;for(const s of c){if(!e())return;const c=s.getType?.();if("audio"!==c&&"video"!==c)continue;const a=s.getBufferController?.();if("function"!==typeof a?.getRangeAt||"function"!==typeof a.getIsPruningInProgress||"function"!==typeof a.getAllRangesWithSafetyFactor)continue;const l=i.getCurrentBufferLevel(c),u=a.getRangeAt(r),f=null===u||u&&Number.isFinite(u.end)&&u.end<=r;if(!Number.isFinite(l)||l<=0||!f||!1!==a.getIsPruningInProgress())continue;const d=a.getAllRangesWithSafetyFactor(r);if(Array.isArray(d)&&0===d.length){if(!e()||n.getActiveStream?.()!==o||n.getDashMetrics?.()!==i||n.getVideoElement?.()!==t||t.currentTime!==r||!t.seeking||!e())return;i.addBufferLevel(c,new Date,0)}}}catch(t){console.warn("ArtPlayer DASH seek buffer refresh failed:",t)}finally{r=!1}}}}(s,()=>n(l)&&!l.suspended);o&&e.push(["playbackSeeking",o]),e.push(["playbackTimeUpdated",()=>{if(n(l)&&!l.suspended)try{const t=r(l);n(l)&&t!==l.automatic&&(l.automatic=t,c(l))}catch(t){i(l,t)}}]),e.push(["streamTeardownComplete",()=>{if(n(l)){l.epoch++,l.queued=!1,l.suspended=!0;try{t.reset()}catch(e){i(l,e)}}}]);for(const t of e){if(!n(l))break;l.callbacks.push(t),u.call(s,...t)}}catch(f){if(e===l)try{o()}catch(d){console.warn("ArtPlayer DASH subscription cleanup failed:",d)}throw f}},release:o}}return function(r={}){return o=>{const i=o,{$viLine truncated
|
||||
@@ -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,r=Object.prototype.propertyIsEnumerable,o=(e,n,r)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[n]=r,i=(t,i)=>{for(var l in i||(i={}))n.call(i,l)&&o(t,l,i[l]);if(e)for(var l of e(i))r.call(i,l)&&o(t,l,i[l]);return t};function l(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 r;const o=new Map;function i(n,r=o.get(n)){var i,l,c,a;if(!r||o.get(n)!==r)return;o.delete(n);const s=t[n];"controls"===n&&(null==(i=s.cache)?void 0:i.get)&&(null==(c=null==(l=s.cache.get(e))?void 0:l.option)?void 0:c.onSelect)!==r||"setting"===n&&s.find&&(null==(a=s.find(e))?void 0:a.onSelect)!==r||s.remove(e)}function l(){let t;r=void 0;for(const[n,r]of[...o])try{i(n,r)}catch(e){t||(t=e)}if(t)throw t}return{update:function(c,a,s){if(!a)return void l();const u={};r=u;const f=()=>u===r&&s(),d=e=>f()?(a.select(e,f),f()?(t.notice.show=`${a.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?(o.set("controls",d),t.controls.update({name:e,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(c.setting?(o.set("setting",d),t.setting.update({name:e,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:l}}function a(t){let e;const n=n=>e===n&&t.active(n.dash),r=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function o(){const t=e;if(!t)return;let n;e=void 0,t.epoch++;for(const[e,o]of t.callbacks.splice(0))try{t.off.call(t.dash,e,o)}catch(r){n||(n=r)}if(n)throw n}function i(n,r){if(e===n){try{o()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!e&&t.active(n.dash))try{t.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",r)}function l(e){if(!n(e)||e.suspended||e.queued||e.running)return;e.queued=!0;const o=e.epoch;Promise.resolve().then(()=>{if(n(e)&&e.epoch===o&&!e.suspended){e.queued=!1,e.running=!0;try{e.automatic=r(e),n(e)&&t.refresh()}catch(l){i(e,l)}finally{e.running=!1}}})}return{bind:function(c){const a=e;if((null==a?void 0:a.dash)===c){const t=r(a);return void(n(a)&&(a.automatic=t,a.suspended=!1))}if(o(),e||!t.active(c)||"function"!==typeof c.on||"function"!==typeof c.off)return;const s={dash:c,off:c.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};e=s;const u=c.on;try{s.automatic=r(s);const e=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(s.suspended=!1),l(s)}]),o=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch(o){return}let r=!1;return()=>{var t,o,i,l,c,a,s,u,f;if(!r&&e()){r=!0;try{const r=null==(t=n.getVideoElement)?void 0:t.call(n);if(!(null==r?void 0:r.seeking)||!Number.isFinite(r.currentTime))return;const d=r.currentTime,h=null==(o=n.getActiveStream)?void 0:o.call(n),g=null==(i=n.getDashMetrics)?void 0:i.call(n),p=null==(l=null==h?void 0:h.getProcessors)?void 0:l.call(h);if(!Array.isArray(p)||"function"!==typeof(null==g?void 0:g.getCurrentBufferLevel)||"function"!==typeof g.addBufferLevel)return;for(const t of p){if(!e())return;const o=null==(c=t.getType)?void 0:c.call(t);if("audio"!==o&&"video"!==o)continue;const i=null==(a=t.getBufferController)?void 0:a.call(t);if("function"!==typeof(null==i?void 0:i.getRangeAt)||"function"!==typeof i.getIsPruningInProgress||"function"!==typeof i.getAllRangesWithSafetyFactor)continue;const l=g.getCurrentBufferLevel(o),p=i.getRangeAt(d),y=null===p||p&&Number.isFinite(p.end)&&p.end<=d;if(!Number.isFinite(l)||l<=0||!y||!1!==i.getIsPruningInProgress())continue;const v=i.getAllRangesWithSafetyFactor(d);if(Array.isArray(v)&&0===v.length){if(!e()||(null==(s=n.getActiveStream)?void 0:s.call(n))!==h||(null==(u=n.getDashMetrics)?void 0:u.call(n))!==g||(null==(f=n.getVideoElement)?void 0:f.call(n))!==r||r.currentTime!==d||!r.seeking||!e())return;g.addBufferLevel(o,new Date,0)}}}catch(d){console.warn("ArtPlayer DASH seek buffer refresh failed:",d)}finally{r=!1}}}}(c,()=>n(s)&&!s.suspended);o&&e.push(["playbackSeeking",o]),e.push(["playbackTimeUpdated",()=>{if(n(s)&&!s.suspended)try{const t=r(s);n(s)&&t!==s.automatic&&(s.automatic=t,l(s))}catch(t){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";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,i=(t,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(t,l,i[l]);if(e)for(var l of e(i))o.call(i,l)&&r(t,l,i[l]);return t};function l(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 i(n,o=r.get(n)){var i,l,c,a;if(!o||r.get(n)!==o)return;r.delete(n);const s=t[n];"controls"===n&&(null==(i=s.cache)?void 0:i.get)&&(null==(c=null==(l=s.cache.get(e))?void 0:l.option)?void 0:c.onSelect)!==o||"setting"===n&&s.find&&(null==(a=s.find(e))?void 0:a.onSelect)!==o||s.remove(e)}function l(){let t;o=void 0;for(const[n,o]of[...r])try{i(n,o)}catch(e){t||(t=e)}if(t)throw t}return{update:function(c,a,s){if(!a)return void l();const u={};o=u;const f=()=>u===o&&s(),d=e=>f()?(a.select(e,f),f()?(t.notice.show=`${a.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:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(c.setting?(r.set("setting",d),t.setting.update({name:e,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:l,captureNavigation:function(n){var o;const i=t.setting,l=null==(o=i.find)?void 0:o.call(i,e),c=r.get("setting");if(n()&&c&&!0===i.show&&(null==l?void 0:l.onSelect)===c&&l.selector&&i.active===l.selector&&"function"===typeof i.render)return()=>{var o,l;if(!n()||t.setting!==i||!0!==i.show||!i.option||i.active!==i.option)return;const c=null==(o=i.find)?void 0:o.call(i,e),a=r.get("setting");n()&&a&&(null==c?void 0:c.onSelect)===a&&c.selector&&(null==(l=i.render)||l.call(i,c.selector))}}}}function a(t){let e;const n=n=>e===n&&t.active(n.dash),o=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function r(){const t=e;if(!t)return;let n;e=void 0,t.epoch++;for(const[e,r]of t.callbacks.splice(0))try{t.off.call(t.dash,e,r)}catch(o){n||(n=o)}if(n)throw n}function i(n,o){if(e===n){try{r()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!e&&t.active(n.dash))try{t.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",o)}function l(e){if(!n(e)||e.suspended||e.queued||e.running)return;e.queued=!0;const r=e.epoch;Promise.resolve().then(()=>{if(n(e)&&e.epoch===r&&!e.suspended){e.queued=!1,e.running=!0;try{e.automatic=o(e),n(e)&&t.refresh()}catch(l){i(e,l)}finally{e.running=!1}}})}return{bind:function(c){const a=e;if((null==a?void 0:a.dash)===c){const t=o(a);return void(n(a)&&(a.automatic=t,a.suspended=!1))}if(r(),e||!t.active(c)||"function"!==typeof c.on||"function"!==typeof c.off)return;const s={dash:c,off:c.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};e=s;const u=c.on;try{s.automatic=o(s);const e=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(s.suspended=!1),l(s)}]),r=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch(r){return}let o=!1;return()=>{var t,r,i,l,c,a,s,u,f;if(!o&&e()){o=!0;try{const o=null==(t=n.getVideoElement)?void 0:t.call(n);if(!(null==o?void 0:o.seeking)||!Number.isFinite(o.currentTime))return;const d=o.currentTime,h=null==(r=n.getActiveStream)?void 0:r.call(n),g=null==(i=n.getDashMetrics)?void 0:i.call(n),p=null==(l=null==h?void 0:h.getProcessors)?void 0:l.call(h);if(!Array.isArray(p)||"function"!==typeof(null==g?void 0:g.getCurrentBufferLevel)||"function"!==typeof g.addBufferLevel)return;for(const t of p){if(!e())return;const r=null==(c=t.getType)?void 0:c.call(t);if("audio"!==r&&"video"!==r)continue;const i=null==(a=t.getBufferController)?void 0:a.call(t);if("function"!==typeof(null==i?void 0:i.getRangeAt)||"function"!==typeof i.getIsPruningInProgress||"function"!==typeof i.getAllRangesWithSafetyFactor)continue;const l=g.getCurrentBufferLevel(r),p=i.getRangeAt(d),v=null===p||p&&Number.isFinite(p.end)&&p.end<=d;if(!Number.isFinite(l)||l<=0||!v||!1!==i.getIsPruningInProgress())continue;const y=i.getAllRangesWithSafetyFactor(d);if(Array.isArray(y)&&0===y.length){if(!e()||(null==(s=n.getAcLine truncated
|
||||
@@ -167,7 +167,22 @@ function createMenu(art, name, icon) {
|
||||
remove("setting");
|
||||
}
|
||||
}
|
||||
return { update, clear };
|
||||
function captureNavigation(active) {
|
||||
const setting = art.setting;
|
||||
const item = setting.find?.(name);
|
||||
const callback = owned.get("setting");
|
||||
if (!active() || !callback || setting.show !== true || item?.onSelect !== callback || !item.selector || setting.active !== item.selector || typeof setting.render !== "function")
|
||||
return;
|
||||
return () => {
|
||||
if (!active() || art.setting !== setting || setting.show !== true || !setting.option || setting.active !== setting.option)
|
||||
return;
|
||||
const replacement = setting.find?.(name);
|
||||
const callback2 = owned.get("setting");
|
||||
if (active() && callback2 && replacement?.onSelect === callback2 && replacement.selector)
|
||||
setting.render?.(replacement.selector);
|
||||
};
|
||||
}
|
||||
return { update, clear, captureNavigation };
|
||||
}
|
||||
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 createSeekRecovery(value, active) {
|
||||
@@ -365,7 +380,18 @@ function artplayerPluginDashControl(option = {}) {
|
||||
const subscriptions = [];
|
||||
const observer = observeSDK({
|
||||
active: (dash) => !closed && !art.isDestroy && art.dash === dash,
|
||||
refresh: update,
|
||||
refresh() {
|
||||
const dash = art.dash;
|
||||
let version = revision;
|
||||
const current = () => !closed && !art.isDestroy && art.dash === dash && revision === version;
|
||||
const restore = quality.captureNavigation(current) || audio.captureNavigation(current);
|
||||
if (!current())
|
||||
return;
|
||||
version++;
|
||||
update();
|
||||
if (current())
|
||||
restore?.();
|
||||
},
|
||||
reset() {
|
||||
const version = ++revision;
|
||||
clear(() => version === revision);
|
||||
|
||||
@@ -8,6 +8,19 @@ destroys it, changes its source, or adds a runtime dependency on dash.js.
|
||||
|
||||
## Module map
|
||||
|
||||
Automatic SDK refresh captures an open, plugin-owned quality or audio settings
|
||||
panel before updating both menus. The menu module restores its new selector only
|
||||
if settings remain visible, navigation was reset to the root, and the replacement
|
||||
still belongs to this plugin. Restoration runs after both updates because updating
|
||||
the sibling menu also resets the core settings view. It uses existing optional
|
||||
`find`, `active`, `option`, `show` and `render` capabilities; no core API change or
|
||||
new event subscription is required. The entry checks SDK identity, destruction
|
||||
and the exact update revision before restoration and during its final lookup.
|
||||
Nested explicit updates invalidate the earlier restore. Closed, foreign, removed
|
||||
or unsupported panels are not reopened. Explicit public `update()` retains the
|
||||
historical navigation behavior. Browser tests drive real SDK selection changes
|
||||
while each submenu is open and then select another option through normal clicks.
|
||||
|
||||
| File | Responsibility |
|
||||
| ------------------------------------------ | --------------------------------------------------------------------------------------- |
|
||||
| `src/index.ts` | Deferred installation, media identity, update revisions, event subscription and cleanup |
|
||||
@@ -16,7 +29,7 @@ destroys it, changes its source, or adds a runtime dependency on dash.js.
|
||||
| `src/seek-buffer.ts` | Exact SDK 4.5.2 empty-seek metric recovery and stale/reentrant measurement guards |
|
||||
| `src/types.ts` | Narrow internal SDK, host, model and cleanup types |
|
||||
| `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/menu.ts` | Control/setting ownership, selection callbacks and owned settings navigation |
|
||||
| `src/audio.svg`, `src/quality.svg` | Existing setting icons |
|
||||
| `types/artplayer-plugin-dash-control.d.ts` | Public options, generic SDK inputs and callable result |
|
||||
|
||||
|
||||
@@ -49,5 +49,8 @@ MIT © Harvey Zhao
|
||||
|
||||
## Maintenance
|
||||
|
||||
Automatic SDK refresh keeps an open quality or audio settings menu usable while
|
||||
updating its selected item. Explicit `update()` keeps its existing behavior.
|
||||
|
||||
See [ARCHITECTURE.md](ARCHITECTURE.md) for module ownership, compatibility rules,
|
||||
test commands and the remaining real SDK playback validation scope.
|
||||
+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 r;const o=new Map;function i(n,r=o.get(n)){if(!r||o.get(n)!==r)return;o.delete(n);const i=t[n];"controls"===n&&i.cache?.get&&i.cache.get(e)?.option?.onSelect!==r||"setting"===n&&i.find&&i.find(e)?.onSelect!==r||i.remove(e)}function c(){let t;r=void 0;for(const[n,r]of[...o])try{i(n,r)}catch(e){t||(t=e)}if(t)throw t}return{update:function(s,a,l){if(!a)return void c();const u={};r=u;const f=()=>u===r&&l(),d=e=>f()?(a.select(e,f),f()?(t.notice.show=`${a.title}: ${e.html}`,f()&&s.control&&t.controls.check(e),f()&&s.setting&&t.setting.check(e),e.html):e.html):e.html;s.control?(o.set("controls",d),t.controls.update({name:e,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(s.setting?(o.set("setting",d),t.setting.update({name:e,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:c}}function n(t){let e;const n=n=>e===n&&t.active(n.dash),r=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function o(){const t=e;if(!t)return;let n;e=void 0,t.epoch++;for(const[e,o]of t.callbacks.splice(0))try{t.off.call(t.dash,e,o)}catch(r){n||(n=r)}if(n)throw n}function i(n,r){if(e===n){try{o()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!e&&t.active(n.dash))try{t.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",r)}function c(e){if(!n(e)||e.suspended||e.queued||e.running)return;e.queued=!0;const o=e.epoch;Promise.resolve().then(()=>{if(n(e)&&e.epoch===o&&!e.suspended){e.queued=!1,e.running=!0;try{e.automatic=r(e),n(e)&&t.refresh()}catch(c){i(e,c)}finally{e.running=!1}}})}return{bind:function(s){const a=e;if(a?.dash===s){const t=r(a);return void(n(a)&&(a.automatic=t,a.suspended=!1))}if(o(),e||!t.active(s)||"function"!==typeof s.on||"function"!==typeof s.off)return;const l={dash:s,off:s.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};e=l;const u=s.on;try{l.automatic=r(l);const e=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(l.suspended=!1),c(l)}]),o=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch{return}let r=!1;return()=>{if(!r&&e()){r=!0;try{const t=n.getVideoElement?.();if(!t?.seeking||!Number.isFinite(t.currentTime))return;const r=t.currentTime,o=n.getActiveStream?.(),i=n.getDashMetrics?.(),c=o?.getProcessors?.();if(!Array.isArray(c)||"function"!==typeof i?.getCurrentBufferLevel||"function"!==typeof i.addBufferLevel)return;for(const s of c){if(!e())return;const c=s.getType?.();if("audio"!==c&&"video"!==c)continue;const a=s.getBufferController?.();if("function"!==typeof a?.getRangeAt||"function"!==typeof a.getIsPruningInProgress||"function"!==typeof a.getAllRangesWithSafetyFactor)continue;const l=i.getCurrentBufferLevel(c),u=a.getRangeAt(r),f=null===u||u&&Number.isFinite(u.end)&&u.end<=r;if(!Number.isFinite(l)||l<=0||!f||!1!==a.getIsPruningInProgress())continue;const d=a.getAllRangesWithSafetyFactor(r);if(Array.isArray(d)&&0===d.length){if(!e()||n.getActiveStream?.()!==o||n.getDashMetrics?.()!==i||n.getVideoElement?.()!==t||t.currentTime!==r||!t.seeking||!e())return;i.addBufferLevel(c,new Date,0)}}}catch(t){console.warn("ArtPlayer DASH seek buffer refresh failed:",t)}finally{r=!1}}}}(s,()=>n(l)&&!l.suspended);o&&e.push(["playbackSeeking",o]),e.push(["playbackTimeUpdated",()=>{if(n(l)&&!l.suspended)try{const t=r(l);n(l)&&t!==l.automatic&&(l.automatic=t,c(l))}catch(t){i(l,t)}}]),e.push(["streamTeardownComplete",()=>{if(n(l)){l.epoch++,l.queued=!1,l.suspended=!0;try{t.reset()}catch(e){i(l,e)}}}]);for(const t of e){if(!n(l))break;l.callbacks.push(t),u.call(s,...t)}}catch(f){if(e===l)try{o()}catch(d){console.warn("ArtPlayer DASH subscription cleanup failed:",d)}throw f}},release:o}}return function(r={}){return o=>{const i=o,{$video:c}=i.template,{errorHandle:s}=i.constructor.utils;let a=!1,l=0;const u=e(i,"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 12Line 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 r;const o=new Map;function i(n,r=o.get(n)){if(!r||o.get(n)!==r)return;o.delete(n);const i=t[n];"controls"===n&&i.cache?.get&&i.cache.get(e)?.option?.onSelect!==r||"setting"===n&&i.find&&i.find(e)?.onSelect!==r||i.remove(e)}function c(){let t;r=void 0;for(const[n,r]of[...o])try{i(n,r)}catch(e){t||(t=e)}if(t)throw t}return{update:function(s,a,l){if(!a)return void c();const u={};r=u;const f=()=>u===r&&l(),d=e=>f()?(a.select(e,f),f()?(t.notice.show=`${a.title}: ${e.html}`,f()&&s.control&&t.controls.check(e),f()&&s.setting&&t.setting.check(e),e.html):e.html):e.html;s.control?(o.set("controls",d),t.controls.update({name:e,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(s.setting?(o.set("setting",d),t.setting.update({name:e,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:c,captureNavigation:function(n){const r=t.setting,i=r.find?.(e),c=o.get("setting");if(n()&&c&&!0===r.show&&i?.onSelect===c&&i.selector&&r.active===i.selector&&"function"===typeof r.render)return()=>{if(!n()||t.setting!==r||!0!==r.show||!r.option||r.active!==r.option)return;const i=r.find?.(e),c=o.get("setting");n()&&c&&i?.onSelect===c&&i.selector&&r.render?.(i.selector)}}}}function n(t){let e;const n=n=>e===n&&t.active(n.dash),r=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function o(){const t=e;if(!t)return;let n;e=void 0,t.epoch++;for(const[e,o]of t.callbacks.splice(0))try{t.off.call(t.dash,e,o)}catch(r){n||(n=r)}if(n)throw n}function i(n,r){if(e===n){try{o()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!e&&t.active(n.dash))try{t.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",r)}function c(e){if(!n(e)||e.suspended||e.queued||e.running)return;e.queued=!0;const o=e.epoch;Promise.resolve().then(()=>{if(n(e)&&e.epoch===o&&!e.suspended){e.queued=!1,e.running=!0;try{e.automatic=r(e),n(e)&&t.refresh()}catch(c){i(e,c)}finally{e.running=!1}}})}return{bind:function(s){const a=e;if(a?.dash===s){const t=r(a);return void(n(a)&&(a.automatic=t,a.suspended=!1))}if(o(),e||!t.active(s)||"function"!==typeof s.on||"function"!==typeof s.off)return;const l={dash:s,off:s.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};e=l;const u=s.on;try{l.automatic=r(l);const e=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(l.suspended=!1),c(l)}]),o=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch{return}let r=!1;return()=>{if(!r&&e()){r=!0;try{const t=n.getVideoElement?.();if(!t?.seeking||!Number.isFinite(t.currentTime))return;const r=t.currentTime,o=n.getActiveStream?.(),i=n.getDashMetrics?.(),c=o?.getProcessors?.();if(!Array.isArray(c)||"function"!==typeof i?.getCurrentBufferLevel||"function"!==typeof i.addBufferLevel)return;for(const s of c){if(!e())return;const c=s.getType?.();if("audio"!==c&&"video"!==c)continue;const a=s.getBufferController?.();if("function"!==typeof a?.getRangeAt||"function"!==typeof a.getIsPruningInProgress||"function"!==typeof a.getAllRangesWithSafetyFactor)continue;const l=i.getCurrentBufferLevel(c),u=a.getRangeAt(r),f=null===u||u&&Number.isFinite(u.end)&&u.end<=r;if(!Number.isFinite(l)||l<=0||!f||!1!==a.getIsPruningInProgress())continue;const d=a.getAllRangesWithSafetyFactor(r);if(Array.isArray(d)&&0===d.length){if(!e()||n.getActiveStream?.()!==o||n.getDashMetrics?.()!==i||n.getVideoElement?.()!==t||t.currentTime!==r||!t.seeking||!e())return;i.addBufferLevel(c,new Date,0)}}}catch(t){console.warn("ArtPlayer DASH seek buffer refresh failed:",t)}finally{r=!1}}}}(s,()=>n(l)&&!l.suspended);o&&e.push(["playbackSeeking",o]),e.push(["playbackTimeUpdated",()=>{if(n(l)&&!l.suspended)try{const t=r(l);n(l)&&t!==l.automatic&&(l.automatic=t,c(l))}catch(t){i(l,t)}}]),e.push(["streamTeardownComplete",()=>{if(n(l)){l.epoch++,l.queued=!1,l.suspended=!0;try{t.reset()}catch(e){i(l,e)}}}]);for(const t of e){if(!n(l))break;l.callbacks.push(t),u.call(s,...t)}}catch(f){if(e===l)try{o()}catch(d){console.warn("ArtPlayer DASH subscription cleanup failed:",d)}throw f}},release:o}}return function(r={}){return o=>{const i=o,{$viLine 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,r=Object.prototype.propertyIsEnumerable,o=(e,n,r)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[n]=r,i=(t,i)=>{for(var l in i||(i={}))n.call(i,l)&&o(t,l,i[l]);if(e)for(var l of e(i))r.call(i,l)&&o(t,l,i[l]);return t};function l(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 r;const o=new Map;function i(n,r=o.get(n)){var i,l,c,a;if(!r||o.get(n)!==r)return;o.delete(n);const s=t[n];"controls"===n&&(null==(i=s.cache)?void 0:i.get)&&(null==(c=null==(l=s.cache.get(e))?void 0:l.option)?void 0:c.onSelect)!==r||"setting"===n&&s.find&&(null==(a=s.find(e))?void 0:a.onSelect)!==r||s.remove(e)}function l(){let t;r=void 0;for(const[n,r]of[...o])try{i(n,r)}catch(e){t||(t=e)}if(t)throw t}return{update:function(c,a,s){if(!a)return void l();const u={};r=u;const f=()=>u===r&&s(),d=e=>f()?(a.select(e,f),f()?(t.notice.show=`${a.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?(o.set("controls",d),t.controls.update({name:e,position:"right",html:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(c.setting?(o.set("setting",d),t.setting.update({name:e,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:l}}function a(t){let e;const n=n=>e===n&&t.active(n.dash),r=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function o(){const t=e;if(!t)return;let n;e=void 0,t.epoch++;for(const[e,o]of t.callbacks.splice(0))try{t.off.call(t.dash,e,o)}catch(r){n||(n=r)}if(n)throw n}function i(n,r){if(e===n){try{o()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!e&&t.active(n.dash))try{t.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",r)}function l(e){if(!n(e)||e.suspended||e.queued||e.running)return;e.queued=!0;const o=e.epoch;Promise.resolve().then(()=>{if(n(e)&&e.epoch===o&&!e.suspended){e.queued=!1,e.running=!0;try{e.automatic=r(e),n(e)&&t.refresh()}catch(l){i(e,l)}finally{e.running=!1}}})}return{bind:function(c){const a=e;if((null==a?void 0:a.dash)===c){const t=r(a);return void(n(a)&&(a.automatic=t,a.suspended=!1))}if(o(),e||!t.active(c)||"function"!==typeof c.on||"function"!==typeof c.off)return;const s={dash:c,off:c.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};e=s;const u=c.on;try{s.automatic=r(s);const e=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(s.suspended=!1),l(s)}]),o=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch(o){return}let r=!1;return()=>{var t,o,i,l,c,a,s,u,f;if(!r&&e()){r=!0;try{const r=null==(t=n.getVideoElement)?void 0:t.call(n);if(!(null==r?void 0:r.seeking)||!Number.isFinite(r.currentTime))return;const d=r.currentTime,h=null==(o=n.getActiveStream)?void 0:o.call(n),g=null==(i=n.getDashMetrics)?void 0:i.call(n),p=null==(l=null==h?void 0:h.getProcessors)?void 0:l.call(h);if(!Array.isArray(p)||"function"!==typeof(null==g?void 0:g.getCurrentBufferLevel)||"function"!==typeof g.addBufferLevel)return;for(const t of p){if(!e())return;const o=null==(c=t.getType)?void 0:c.call(t);if("audio"!==o&&"video"!==o)continue;const i=null==(a=t.getBufferController)?void 0:a.call(t);if("function"!==typeof(null==i?void 0:i.getRangeAt)||"function"!==typeof i.getIsPruningInProgress||"function"!==typeof i.getAllRangesWithSafetyFactor)continue;const l=g.getCurrentBufferLevel(o),p=i.getRangeAt(d),y=null===p||p&&Number.isFinite(p.end)&&p.end<=d;if(!Number.isFinite(l)||l<=0||!y||!1!==i.getIsPruningInProgress())continue;const v=i.getAllRangesWithSafetyFactor(d);if(Array.isArray(v)&&0===v.length){if(!e()||(null==(s=n.getActiveStream)?void 0:s.call(n))!==h||(null==(u=n.getDashMetrics)?void 0:u.call(n))!==g||(null==(f=n.getVideoElement)?void 0:f.call(n))!==r||r.currentTime!==d||!r.seeking||!e())return;g.addBufferLevel(o,new Date,0)}}}catch(d){console.warn("ArtPlayer DASH seek buffer refresh failed:",d)}finally{r=!1}}}}(c,()=>n(s)&&!s.suspended);o&&e.push(["playbackSeeking",o]),e.push(["playbackTimeUpdated",()=>{if(n(s)&&!s.suspended)try{const t=r(s);n(s)&&t!==s.automatic&&(s.automatic=t,l(s))}catch(t){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";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,i=(t,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(t,l,i[l]);if(e)for(var l of e(i))o.call(i,l)&&r(t,l,i[l]);return t};function l(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 i(n,o=r.get(n)){var i,l,c,a;if(!o||r.get(n)!==o)return;r.delete(n);const s=t[n];"controls"===n&&(null==(i=s.cache)?void 0:i.get)&&(null==(c=null==(l=s.cache.get(e))?void 0:l.option)?void 0:c.onSelect)!==o||"setting"===n&&s.find&&(null==(a=s.find(e))?void 0:a.onSelect)!==o||s.remove(e)}function l(){let t;o=void 0;for(const[n,o]of[...r])try{i(n,o)}catch(e){t||(t=e)}if(t)throw t}return{update:function(c,a,s){if(!a)return void l();const u={};o=u;const f=()=>u===o&&s(),d=e=>f()?(a.select(e,f),f()?(t.notice.show=`${a.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:a.html,style:{padding:"0 10px"},selector:a.selector,onSelect:d})):i("controls"),f()&&(c.setting?(r.set("setting",d),t.setting.update({name:e,tooltip:a.html,html:a.title,icon:n,width:200,selector:a.selector,onSelect:d})):i("setting"))},clear:l,captureNavigation:function(n){var o;const i=t.setting,l=null==(o=i.find)?void 0:o.call(i,e),c=r.get("setting");if(n()&&c&&!0===i.show&&(null==l?void 0:l.onSelect)===c&&l.selector&&i.active===l.selector&&"function"===typeof i.render)return()=>{var o,l;if(!n()||t.setting!==i||!0!==i.show||!i.option||i.active!==i.option)return;const c=null==(o=i.find)?void 0:o.call(i,e),a=r.get("setting");n()&&a&&(null==c?void 0:c.onSelect)===a&&c.selector&&(null==(l=i.render)||l.call(i,c.selector))}}}}function a(t){let e;const n=n=>e===n&&t.active(n.dash),o=t=>t.dash.getSettings().streaming.abr.autoSwitchBitrate.video;function r(){const t=e;if(!t)return;let n;e=void 0,t.epoch++;for(const[e,r]of t.callbacks.splice(0))try{t.off.call(t.dash,e,r)}catch(o){n||(n=o)}if(n)throw n}function i(n,o){if(e===n){try{r()}catch(i){console.warn("ArtPlayer DASH subscription cleanup failed:",i)}if(!e&&t.active(n.dash))try{t.reset()}catch(i){console.warn("ArtPlayer DASH cleanup failed:",i)}}console.warn("ArtPlayer DASH refresh failed:",o)}function l(e){if(!n(e)||e.suspended||e.queued||e.running)return;e.queued=!0;const r=e.epoch;Promise.resolve().then(()=>{if(n(e)&&e.epoch===r&&!e.suspended){e.queued=!1,e.running=!0;try{e.automatic=o(e),n(e)&&t.refresh()}catch(l){i(e,l)}finally{e.running=!1}}})}return{bind:function(c){const a=e;if((null==a?void 0:a.dash)===c){const t=o(a);return void(n(a)&&(a.automatic=t,a.suspended=!1))}if(r(),e||!t.active(c)||"function"!==typeof c.on||"function"!==typeof c.off)return;const s={dash:c,off:c.off,callbacks:[],epoch:0,queued:!1,running:!1,suspended:!1,automatic:!1};e=s;const u=c.on;try{s.automatic=o(s);const e=["qualityChangeRequested","qualityChangeRendered","trackChangeRendered","streamUpdated","streamInitialized"].map(t=>[t,()=>{"streamUpdated"!==t&&"streamInitialized"!==t||(s.suspended=!1),l(s)}]),r=function(t,e){const n=t;try{if("function"!==typeof n.getVersion||"4.5.2"!==n.getVersion())return;if("function"!==typeof n.getVideoElement||"function"!==typeof n.getActiveStream||"function"!==typeof n.getDashMetrics)return}catch(r){return}let o=!1;return()=>{var t,r,i,l,c,a,s,u,f;if(!o&&e()){o=!0;try{const o=null==(t=n.getVideoElement)?void 0:t.call(n);if(!(null==o?void 0:o.seeking)||!Number.isFinite(o.currentTime))return;const d=o.currentTime,h=null==(r=n.getActiveStream)?void 0:r.call(n),g=null==(i=n.getDashMetrics)?void 0:i.call(n),p=null==(l=null==h?void 0:h.getProcessors)?void 0:l.call(h);if(!Array.isArray(p)||"function"!==typeof(null==g?void 0:g.getCurrentBufferLevel)||"function"!==typeof g.addBufferLevel)return;for(const t of p){if(!e())return;const r=null==(c=t.getType)?void 0:c.call(t);if("audio"!==r&&"video"!==r)continue;const i=null==(a=t.getBufferController)?void 0:a.call(t);if("function"!==typeof(null==i?void 0:i.getRangeAt)||"function"!==typeof i.getIsPruningInProgress||"function"!==typeof i.getAllRangesWithSafetyFactor)continue;const l=g.getCurrentBufferLevel(r),p=i.getRangeAt(d),v=null===p||p&&Number.isFinite(p.end)&&p.end<=d;if(!Number.isFinite(l)||l<=0||!v||!1!==i.getIsPruningInProgress())continue;const y=i.getAllRangesWithSafetyFactor(d);if(Array.isArray(y)&&0===y.length){if(!e()||(null==(s=n.getAcLine truncated
|
||||
+28
-2
@@ -167,7 +167,22 @@ function createMenu(art, name, icon) {
|
||||
remove("setting");
|
||||
}
|
||||
}
|
||||
return { update, clear };
|
||||
function captureNavigation(active) {
|
||||
const setting = art.setting;
|
||||
const item = setting.find?.(name);
|
||||
const callback = owned.get("setting");
|
||||
if (!active() || !callback || setting.show !== true || item?.onSelect !== callback || !item.selector || setting.active !== item.selector || typeof setting.render !== "function")
|
||||
return;
|
||||
return () => {
|
||||
if (!active() || art.setting !== setting || setting.show !== true || !setting.option || setting.active !== setting.option)
|
||||
return;
|
||||
const replacement = setting.find?.(name);
|
||||
const callback2 = owned.get("setting");
|
||||
if (active() && callback2 && replacement?.onSelect === callback2 && replacement.selector)
|
||||
setting.render?.(replacement.selector);
|
||||
};
|
||||
}
|
||||
return { update, clear, captureNavigation };
|
||||
}
|
||||
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 createSeekRecovery(value, active) {
|
||||
@@ -365,7 +380,18 @@ function artplayerPluginDashControl(option = {}) {
|
||||
const subscriptions = [];
|
||||
const observer = observeSDK({
|
||||
active: (dash) => !closed && !art.isDestroy && art.dash === dash,
|
||||
refresh: update,
|
||||
refresh() {
|
||||
const dash = art.dash;
|
||||
let version = revision;
|
||||
const current = () => !closed && !art.isDestroy && art.dash === dash && revision === version;
|
||||
const restore = quality.captureNavigation(current) || audio.captureNavigation(current);
|
||||
if (!current())
|
||||
return;
|
||||
version++;
|
||||
update();
|
||||
if (current())
|
||||
restore?.();
|
||||
},
|
||||
reset() {
|
||||
const version = ++revision;
|
||||
clear(() => version === revision);
|
||||
|
||||
@@ -20,7 +20,18 @@ export default function artplayerPluginDashControl<Level extends object = Qualit
|
||||
const subscriptions: [EventName, Cleanup][] = []
|
||||
const observer = observeSDK<Level, Track>({
|
||||
active: dash => !closed && !art.isDestroy && art.dash === dash,
|
||||
refresh: update,
|
||||
refresh() {
|
||||
const dash = art.dash
|
||||
let version = revision
|
||||
const current = () => !closed && !art.isDestroy && art.dash === dash && revision === version
|
||||
const restore = quality.captureNavigation(current) || audio.captureNavigation(current)
|
||||
if (!current())
|
||||
return
|
||||
version++
|
||||
update()
|
||||
if (current())
|
||||
restore?.()
|
||||
},
|
||||
reset() {
|
||||
const version = ++revision
|
||||
clear(() => version === revision)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DisplayConfig, Label, MenuHost, MenuModel, SelectorItem, Valid } from './types'
|
||||
import type { Cleanup, DisplayConfig, Label, MenuHost, MenuModel, SelectorItem, Valid } from './types'
|
||||
|
||||
export function createMenu<Item extends SelectorItem>(art: MenuHost, name: string, icon: string) {
|
||||
let current: object | undefined
|
||||
@@ -70,5 +70,21 @@ export function createMenu<Item extends SelectorItem>(art: MenuHost, name: strin
|
||||
}
|
||||
}
|
||||
|
||||
return { update, clear }
|
||||
function captureNavigation(active: Valid): Cleanup | undefined {
|
||||
const setting = art.setting
|
||||
const item = setting.find?.(name)
|
||||
const callback = owned.get('setting')
|
||||
if (!active() || !callback || setting.show !== true || item?.onSelect !== callback || !item.selector || setting.active !== item.selector || typeof setting.render !== 'function')
|
||||
return
|
||||
return () => {
|
||||
if (!active() || art.setting !== setting || setting.show !== true || !setting.option || setting.active !== setting.option)
|
||||
return
|
||||
const replacement = setting.find?.(name)
|
||||
const callback = owned.get('setting')
|
||||
if (active() && callback && replacement?.onSelect === callback && replacement.selector)
|
||||
setting.render?.(replacement.selector)
|
||||
}
|
||||
}
|
||||
|
||||
return { update, clear, captureNavigation }
|
||||
}
|
||||
@@ -77,7 +77,11 @@ export interface Registry {
|
||||
remove: (name: string) => unknown
|
||||
check: (item: SelectorItem) => unknown
|
||||
cache?: { get?: (name: string) => { option?: { onSelect?: unknown } } | undefined }
|
||||
find?: (name: string) => { onSelect?: unknown } | undefined
|
||||
find?: (name: string) => { onSelect?: unknown, selector?: SelectorItem[] } | null | undefined
|
||||
active?: SelectorItem[] | null
|
||||
option?: SelectorItem[]
|
||||
show?: boolean
|
||||
render?: (option: SelectorItem[]) => unknown
|
||||
}
|
||||
|
||||
export interface MenuHost {
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "PKG-DASH-MENU-01",
|
||||
"baselineCommit": "30f646be97aaa929265392c661fd6cddad2037f9",
|
||||
"rootCause": "SDK automatic refresh calls setting.update for both menus. Core update renders the root panel; the open quality/audio panel loses art-current before the click. Restore the owned panel only after both automatic updates, guarded by SDK identity, update revision and ownership. Explicit update is unchanged.",
|
||||
"originalFailure": {
|
||||
"file": "refactor/.cache/dash-seek-legacy-final-sdk-report/report.json",
|
||||
"sha256": "74a3924972eeb7f3b22a3595bb1d5450088bba025cc83e022066fd3820989d8a",
|
||||
"title": "published core / DASH 5.2.1: actual settings quality selection survives SDK refresh",
|
||||
"project": "chromium",
|
||||
"trace": {
|
||||
"file": "refactor/.cache/dash-seek-legacy-final-sdk-report/results/dash-sdk-published-core-DA-81045-ection-survives-SDK-refresh-chromium/trace.zip",
|
||||
"sha256": "3b3a12dd98abdedb95a4aa0ab74cdb72f51ed132e0df504bd2872d2cd3c6dc4f"
|
||||
},
|
||||
"panelBeforeClickAt": 63311.912,
|
||||
"panelAfterTimeoutAt": 82551.665,
|
||||
"observation": "Settings remain shown; active quality selector is replaced by root settings panel. Controlled real-SDK refresh reproduces the same navigation reset on all four tested core/SDK pairs."
|
||||
},
|
||||
"environment": {
|
||||
"node": "24.21.0",
|
||||
"yarn": "1.22.22",
|
||||
"platform": "win32",
|
||||
"remoteCI": false,
|
||||
"physicalDevices": false
|
||||
},
|
||||
"source": [
|
||||
{
|
||||
"file": "packages/artplayer-plugin-dash-control/src/index.ts",
|
||||
"sha256LF": "e22cfd0a3a2129913278cb2fbb50e2a7b2333cc9bd53647ec764d3f8f4f30ccc"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-dash-control/src/menu.ts",
|
||||
"sha256LF": "f5049045ead1d47c6275b0d13fc862b53a90e2accfe99935f641d07757e06428"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-dash-control/src/types.ts",
|
||||
"sha256LF": "d812577c7bd877f6998b55747916117da1f400067977292907e3a910e04c239c"
|
||||
},
|
||||
{
|
||||
"file": "test/dash-events.test.js",
|
||||
"sha256LF": "b753e21e068b02fc8176bac1cc804dc3b7daaa59f152cdc1f14ca5b910c8a39a"
|
||||
},
|
||||
{
|
||||
"file": "test/browser/dash-sdk.spec.js",
|
||||
"sha256LF": "e1b2980cfbdd948180308321705e39ca9b8df06d4bde33e421f66abbc5ce2065"
|
||||
}
|
||||
],
|
||||
"artifacts": [
|
||||
{
|
||||
"file": "refactor/.cache/dash-package-types-QIKdVC/runtime/artplayer-plugin-dash-control.js",
|
||||
"member": "package/dist/artplayer-plugin-dash-control.js",
|
||||
"sha256": "2d639a5c6a7044ada2b1d74e5b039d4cc787996b997c5a186a67724848f36c2a",
|
||||
"archiveSha256": "83cd29340bbc6788f9b069d18909fd0344aeb2fa8e12515f92796cfd7bd2fdab"
|
||||
},
|
||||
{
|
||||
"file": "refactor/.cache/dash-package-types-QIKdVC/runtime/artplayer-plugin-dash-control.legacy.js",
|
||||
"member": "package/dist/artplayer-plugin-dash-control.legacy.js",
|
||||
"sha256": "eef089514bf7304c7910e4f093c7c350495458284c6f55871358ae085f504ddc",
|
||||
"archiveSha256": "83cd29340bbc6788f9b069d18909fd0344aeb2fa8e12515f92796cfd7bd2fdab"
|
||||
},
|
||||
{
|
||||
"file": "refactor/.cache/dash-package-types-QIKdVC/runtime/artplayer-plugin-dash-control.mjs",
|
||||
"member": "package/dist/artplayer-plugin-dash-control.mjs",
|
||||
"sha256": "bec1c9fa15fa6b80841517b9afe29da8c63a4d28fc57a6218c869b0c0e407703",
|
||||
"archiveSha256": "83cd29340bbc6788f9b069d18909fd0344aeb2fa8e12515f92796cfd7bd2fdab"
|
||||
}
|
||||
],
|
||||
"reports": [
|
||||
{
|
||||
"directory": "refactor/.cache/dash-menu-red-report",
|
||||
"reportSha256": "09c08de619c8b1c67c4abbcd36827ed36a94c8424b3cea69422690d9b9fb974f",
|
||||
"result": {
|
||||
"scope": "source",
|
||||
"exitCode": 1,
|
||||
"signal": null,
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.source.config.js",
|
||||
"test/browser/dash-sdk.spec.js",
|
||||
"--project=chromium",
|
||||
"--grep",
|
||||
"SDK refresh preserves the open quality",
|
||||
"--workers=2"
|
||||
]
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-14T12:21:57.499Z",
|
||||
"duration": 23198.907,
|
||||
"expected": 0,
|
||||
"skipped": 0,
|
||||
"unexpected": 4,
|
||||
"flaky": 0
|
||||
},
|
||||
"browsers": [
|
||||
"153.0.8010.12"
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"sdk": "4.5.2",
|
||||
"sdkArchiveSha256": "9a0944c48deb0fd8f92b0eea436c5b0d0aea9237c7da0078c0310f1430d0a31f",
|
||||
"sdkCodeMember": "package/dist/dash.all.min.js",
|
||||
"candidate": "workspace source build",
|
||||
"candidateSha256": "b9c81fe7223b79775b5c2d3b9dbc79477b7e993201a8412fba81143df39972cf"
|
||||
},
|
||||
{
|
||||
"sdk": "5.2.1",
|
||||
"sdkArchiveSha256": "4eacb0cc3525276666ca3f084611cdabb5a2264d128dfe0750fe106fbddd088f",
|
||||
"sdkCodeMember": "package/dist/modern/umd/dash.all.min.js",
|
||||
"candidate": "workspace source build",
|
||||
"candidateSha256": "b9c81fe7223b79775b5c2d3b9dbc79477b7e993201a8412fba81143df39972cf"
|
||||
}
|
||||
],
|
||||
"failures": [
|
||||
{
|
||||
"title": "published core / DASH 4.5.2: SDK refresh preserves the open quality settings panel",
|
||||
"project": "chromium",
|
||||
"errors": [
|
||||
"Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\nExpected: \u001b[32mtrue\u001b[39m\nReceived: \u001b[31mfalse\u001b[39m\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 353 | const changed = type === 'quality' ? '180p' : 'fr'\n 354 | await expect(page.locator(`.art-control-dash-${type} .art-selector-value`)).toHaveText(changed)\n> 355 | await expect.poll(() => page.evaluate(type => window.art.setting.active === window.art.setting.find(`dash-${type}`).selector, type)).toBe(true)\n | ^\n 356 | const label = type === 'quality' ? '90p' : 'en'\n 357 | await page.locator('.art-setting-panel.art-current .art-setting-item-left-text').filter({ hasText: new RegExp(`^${label}$`) }).click()\n 358 | if (type === 'quality')\n at D:\\github\\ArtPlayer\\test\\browser\\dash-sdk.spec.js:355:142"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "published core / DASH 5.2.1: SDK refresh preserves the open quality settings panel",
|
||||
"project": "chromium",
|
||||
"errors": [
|
||||
"Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\nExpected: \u001b[32mtrue\u001b[39m\nReceived: \u001b[31mfalse\u001b[39m\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 353 | const changed = type === 'quality' ? '180p' : 'fr'\n 354 | await expect(page.locator(`.art-control-dash-${type} .art-selector-value`)).toHaveText(changed)\n> 355 | await expect.poll(() => page.evaluate(type => window.art.setting.active === window.art.setting.find(`dash-${type}`).selector, type)).toBe(true)\n | ^\n 356 | const label = type === 'quality' ? '90p' : 'en'\n 357 | await page.locator('.art-setting-panel.art-current .art-setting-item-left-text').filter({ hasText: new RegExp(`^${label}$`) }).click()\n 358 | if (type === 'quality')\n at D:\\github\\ArtPlayer\\test\\browser\\dash-sdk.spec.js:355:142"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "candidate core / DASH 4.5.2: SDK refresh preserves the open quality settings panel",
|
||||
"project": "chromium",
|
||||
"errors": [
|
||||
"Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\nExpected: \u001b[32mtrue\u001b[39m\nReceived: \u001b[31mfalse\u001b[39m\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 353 | const changed = type === 'quality' ? '180p' : 'fr'\n 354 | await expect(page.locator(`.art-control-dash-${type} .art-selector-value`)).toHaveText(changed)\n> 355 | await expect.poll(() => page.evaluate(type => window.art.setting.active === window.art.setting.find(`dash-${type}`).selector, type)).toBe(true)\n | ^\n 356 | const label = type === 'quality' ? '90p' : 'en'\n 357 | await page.locator('.art-setting-panel.art-current .art-setting-item-left-text').filter({ hasText: new RegExp(`^${label}$`) }).click()\n 358 | if (type === 'quality')\n at D:\\github\\ArtPlayer\\test\\browser\\dash-sdk.spec.js:355:142"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "candidate core / DASH 5.2.1: SDK refresh preserves the open quality settings panel",
|
||||
"project": "chromium",
|
||||
"errors": [
|
||||
"Error: \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\nExpected: \u001b[32mtrue\u001b[39m\nReceived: \u001b[31mfalse\u001b[39m\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 353 | const changed = type === 'quality' ? '180p' : 'fr'\n 354 | await expect(page.locator(`.art-control-dash-${type} .art-selector-value`)).toHaveText(changed)\n> 355 | await expect.poll(() => page.evaluate(type => window.art.setting.active === window.art.setting.find(`dash-${type}`).selector, type)).toBe(true)\n | ^\n 356 | const label = type === 'quality' ? '90p' : 'en'\n 357 | await page.locator('.art-setting-panel.art-current .art-setting-item-left-text').filter({ hasText: new RegExp(`^${label}$`) }).click()\n 358 | if (type === 'quality')\n at D:\\github\\ArtPlayer\\test\\browser\\dash-sdk.spec.js:355:142"
|
||||
]
|
||||
}
|
||||
],
|
||||
"menuCases": 4
|
||||
},
|
||||
{
|
||||
"directory": "refactor/.cache/dash-menu-source-green-report",
|
||||
"reportSha256": "f793008f42ccca55b431bba347aca88d79602b17a58eb05384b276881079f63e",
|
||||
"result": {
|
||||
"scope": "source",
|
||||
"exitCode": 0,
|
||||
"signal": null,
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.source.config.js",
|
||||
"test/browser/dash-sdk.spec.js",
|
||||
"--project=chromium",
|
||||
"--project=firefox",
|
||||
"--grep",
|
||||
"SDK refresh preserves the open|actual settings",
|
||||
"--workers=2"
|
||||
]
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-14T12:23:06.427Z",
|
||||
"duration": 41683.534,
|
||||
"expected": 32,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"browsers": [
|
||||
"153.0.8010.12",
|
||||
"155.0"
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"sdk": "4.5.2",
|
||||
"sdkArchiveSha256": "9a0944c48deb0fd8f92b0eea436c5b0d0aea9237c7da0078c0310f1430d0a31f",
|
||||
"sdkCodeMember": "package/dist/dash.all.min.js",
|
||||
"candidate": "workspace source build",
|
||||
"candidateSha256": "d5fce5ae917ad8fa3e666aceed9a23f626bfbdd89fd73379db56c85e145ae02d"
|
||||
},
|
||||
{
|
||||
"sdk": "5.2.1",
|
||||
"sdkArchiveSha256": "4eacb0cc3525276666ca3f084611cdabb5a2264d128dfe0750fe106fbddd088f",
|
||||
"sdkCodeMember": "package/dist/modern/umd/dash.all.min.js",
|
||||
"candidate": "workspace source build",
|
||||
"candidateSha256": "d5fce5ae917ad8fa3e666aceed9a23f626bfbdd89fd73379db56c85e145ae02d"
|
||||
}
|
||||
],
|
||||
"failures": [],
|
||||
"menuCases": 32
|
||||
},
|
||||
{
|
||||
"directory": "refactor/.cache/dash-menu-source-final-report",
|
||||
"reportSha256": "7385e41e449f203b7c177355d0a16bafc26e798c7c8104b31fad7d47fa689a73",
|
||||
"result": {
|
||||
"scope": "source",
|
||||
"exitCode": 0,
|
||||
"signal": null,
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.source.config.js",
|
||||
"test/browser/dash-sdk.spec.js",
|
||||
"--project=chromium",
|
||||
"--project=firefox",
|
||||
"--grep-invert",
|
||||
"native SDK track switch|published DASH / 4.5.2",
|
||||
"--workers=2"
|
||||
]
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-14T12:26:48.315Z",
|
||||
"duration": 137303.375,
|
||||
"expected": 92,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"browsers": [
|
||||
"153.0.8010.12",
|
||||
"155.0"
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"sdk": "4.5.2",
|
||||
"sdkArchiveSha256": "9a0944c48deb0fd8f92b0eea436c5b0d0aea9237c7da0078c0310f1430d0a31f",
|
||||
"sdkCodeMember": "package/dist/dash.all.min.js",
|
||||
"candidate": "workspace source build",
|
||||
"candidateSha256": "5bd2e6b031996c2b42970a790769f6e91752cef76697522d0e57c6d8909fb568"
|
||||
},
|
||||
{
|
||||
"sdk": "5.2.1",
|
||||
"sdkArchiveSha256": "4eacb0cc3525276666ca3f084611cdabb5a2264d128dfe0750fe106fbddd088f",
|
||||
"sdkCodeMember": "package/dist/modern/umd/dash.all.min.js",
|
||||
"candidate": "workspace source build",
|
||||
"candidateSha256": "5bd2e6b031996c2b42970a790769f6e91752cef76697522d0e57c6d8909fb568"
|
||||
}
|
||||
],
|
||||
"failures": [],
|
||||
"menuCases": 32
|
||||
},
|
||||
{
|
||||
"directory": "refactor/.cache/dash-menu-main-report",
|
||||
"reportSha256": "dd4d0ae710851220e7edc007b752d7678c404eb8c7cec4484f925bf81bc74858",
|
||||
"result": {
|
||||
"scope": "source",
|
||||
"exitCode": 0,
|
||||
"signal": null,
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.source.config.js",
|
||||
"test/browser/dash-sdk.spec.js",
|
||||
"--project=chromium",
|
||||
"--project=firefox",
|
||||
"--grep",
|
||||
"SDK refresh preserves the open|actual settings",
|
||||
"--workers=2"
|
||||
]
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-14T12:30:20.600Z",
|
||||
"duration": 41334.104,
|
||||
"expected": 32,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"browsers": [
|
||||
"153.0.8010.12",
|
||||
"155.0"
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"sdk": "4.5.2",
|
||||
"sdkArchiveSha256": "9a0944c48deb0fd8f92b0eea436c5b0d0aea9237c7da0078c0310f1430d0a31f",
|
||||
"sdkCodeMember": "package/dist/dash.all.min.js",
|
||||
"candidate": "D:\\github\\ArtPlayer\\refactor\\.cache\\dash-package-types-QIKdVC\\runtime\\artplayer-plugin-dash-control.js",
|
||||
"candidateSha256": "2d639a5c6a7044ada2b1d74e5b039d4cc787996b997c5a186a67724848f36c2a"
|
||||
},
|
||||
{
|
||||
"sdk": "5.2.1",
|
||||
"sdkArchiveSha256": "4eacb0cc3525276666ca3f084611cdabb5a2264d128dfe0750fe106fbddd088f",
|
||||
"sdkCodeMember": "package/dist/modern/umd/dash.all.min.js",
|
||||
"candidate": "D:\\github\\ArtPlayer\\refactor\\.cache\\dash-package-types-QIKdVC\\runtime\\artplayer-plugin-dash-control.js",
|
||||
"candidateSha256": "2d639a5c6a7044ada2b1d74e5b039d4cc787996b997c5a186a67724848f36c2a"
|
||||
}
|
||||
],
|
||||
"failures": [],
|
||||
"menuCases": 32
|
||||
},
|
||||
{
|
||||
"directory": "refactor/.cache/dash-menu-legacy-report",
|
||||
"reportSha256": "3f1db2574bbfd759a6382b09b55842444df6db3005902460acf3a6839304840a",
|
||||
"result": {
|
||||
"scope": "source",
|
||||
"exitCode": 0,
|
||||
"signal": null,
|
||||
"args": [
|
||||
"test",
|
||||
"--config=playwright.source.config.js",
|
||||
"test/browser/dash-sdk.spec.js",
|
||||
"--project=chromium",
|
||||
"--project=firefox",
|
||||
"--grep-invert",
|
||||
"native SDK track switch|published DASH / 4.5.2",
|
||||
"--workers=2"
|
||||
]
|
||||
},
|
||||
"stats": {
|
||||
"startTime": "2026-09-14T12:31:23.841Z",
|
||||
"duration": 136092.201,
|
||||
"expected": 92,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"browsers": [
|
||||
"153.0.8010.12",
|
||||
"155.0"
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"sdk": "4.5.2",
|
||||
"sdkArchiveSha256": "9a0944c48deb0fd8f92b0eea436c5b0d0aea9237c7da0078c0310f1430d0a31f",
|
||||
"sdkCodeMember": "package/dist/dash.all.min.js",
|
||||
"candidate": "D:\\github\\ArtPlayer\\refactor\\.cache\\dash-package-types-QIKdVC\\runtime\\artplayer-plugin-dash-control.legacy.js",
|
||||
"candidateSha256": "eef089514bf7304c7910e4f093c7c350495458284c6f55871358ae085f504ddc"
|
||||
},
|
||||
{
|
||||
"sdk": "5.2.1",
|
||||
"sdkArchiveSha256": "4eacb0cc3525276666ca3f084611cdabb5a2264d128dfe0750fe106fbddd088f",
|
||||
"sdkCodeMember": "package/dist/modern/umd/dash.all.min.js",
|
||||
"candidate": "D:\\github\\ArtPlayer\\refactor\\.cache\\dash-package-types-QIKdVC\\runtime\\artplayer-plugin-dash-control.legacy.js",
|
||||
"candidateSha256": "eef089514bf7304c7910e4f093c7c350495458284c6f55871358ae085f504ddc"
|
||||
}
|
||||
],
|
||||
"failures": [],
|
||||
"menuCases": 32
|
||||
}
|
||||
],
|
||||
"node": {
|
||||
"file": "refactor/.cache/dash-menu-node-artifacts.log",
|
||||
"sha256": "9abf0919778aa5daac80e6951b5f6bc32238a7972389a08bdbdafcf2d065c8e9",
|
||||
"passed": 446,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"initialReentrancyFailures": {
|
||||
"file": "refactor/.cache/dash-menu-node-initial.log",
|
||||
"sha256": "ca9a1394e5ab7f64e1e225b9e25eda8e87a9d99472e1b35d26d8d9ef24f2b0b0"
|
||||
}
|
||||
},
|
||||
"types": {
|
||||
"file": "refactor/.cache/dash-package-types-QIKdVC/report.json",
|
||||
"sha256": "5f3fb18d59cb60fcba08e6f6aa43b947f97a0c283d832c1391f66c581ae87b7f",
|
||||
"archives": [
|
||||
{
|
||||
"name": "artplayer",
|
||||
"sha256": "d4a0cc5dcbe015e254b3bce64d505ee4e010792ab70414bcf8d0139d7c413b75"
|
||||
},
|
||||
{
|
||||
"name": "artplayer-plugin-dash-control",
|
||||
"sha256": "83cd29340bbc6788f9b069d18909fd0344aeb2fa8e12515f92796cfd7bd2fdab"
|
||||
}
|
||||
],
|
||||
"matrix": [
|
||||
{
|
||||
"compiler": "5.9.3",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": 0,
|
||||
"invalidRejected": 8
|
||||
},
|
||||
{
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-cjs",
|
||||
"diagnostics": 0,
|
||||
"invalidRejected": 8
|
||||
},
|
||||
{
|
||||
"compiler": "5.9.3",
|
||||
"mode": "nodenext-esm",
|
||||
"diagnostics": 0,
|
||||
"invalidRejected": 8
|
||||
},
|
||||
{
|
||||
"compiler": "5.9.3",
|
||||
"mode": "bundler-esm",
|
||||
"diagnostics": 0,
|
||||
"invalidRejected": 8
|
||||
},
|
||||
{
|
||||
"compiler": "4.3.5",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": 0,
|
||||
"invalidRejected": 8
|
||||
}
|
||||
],
|
||||
"method": "Offline Yarn install and frozen reinstall outside workspace; all installed files match tarball. Browser uses extracted tarball runtime, not a complete installed browser suite."
|
||||
},
|
||||
"checks": {
|
||||
"strictTypeScriptExitCode": 0,
|
||||
"targetedLintExitCode": 0,
|
||||
"rootLint": {
|
||||
"file": "refactor/.cache/dash-menu-lint.log",
|
||||
"sha256": "8f03fe722a69933197e1985dcd5bffe6110fa8c03be9fa9d92313447762ca4bf",
|
||||
"errors": 0,
|
||||
"existingWarnings": 1
|
||||
}
|
||||
},
|
||||
"limitations": [
|
||||
"Full DASH combination and distribution acceptance remains open",
|
||||
"Standalone SDK 4.5.2 and frozen published-plugin failure controls remain unchanged; only these invocations exclude them from the broad candidate matrix",
|
||||
"WebKit MSE capability, physical devices, remote CI and global release reviews are not completed here"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
# PKG-DASH-MENU-01:SDK 自动刷新保留设置子菜单
|
||||
|
||||
## 问题和根因
|
||||
|
||||
此前最终 legacy SDK 矩阵中,Chromium、旧核心和 dash.js 5.2.1 的 180p 设置点击
|
||||
超时。trace 在点击前显示质量子菜单拥有 `art-current`;失败时设置仍然显示,
|
||||
但根菜单重新成为当前面板。选项仍存在于隐藏子菜单,所以 locator 已解析但不可见。
|
||||
原报告保留于 `refactor/.cache/dash-seek-legacy-final-sdk-report`,不覆盖该失败。
|
||||
|
||||
SDK 自动事件刷新通过 `update()` 更新质量、音轨两个菜单。核心 `setting.update()`
|
||||
会回到根面板;两次更新都会重置导航。新增真实 SDK 选择变化的回归用例,在保持
|
||||
菜单打开时触发实际质量/音轨选择,检查刷新后的当前面板,并用普通鼠标点击选择
|
||||
另一项。修复前质量用例在新旧核心、两代 SDK 的四个 Chromium 组合全部失败。
|
||||
这将 trace 中的导航复位现象与可控的真实 SDK 刷新联系起来,没有伪造 SDK 事件。
|
||||
|
||||
## 实现、兼容和类型
|
||||
|
||||
`src/menu.ts` 在自动刷新前捕获本插件拥有的打开子菜单,两项更新完成后才恢复
|
||||
新的 selector。恢复要求设置仍显示、当前面板确实回到根菜单、目标仍由插件拥有。
|
||||
关闭、移除、其他调用方接管及缺少可选导航能力时不恢复,不强制打开设置。
|
||||
该职责与菜单所有权放在同一模块,不新增只用于转发的抽象或异步资源。
|
||||
|
||||
`src/index.ts` 将此逻辑限定在 SDK observer 的自动 refresh 中;公开同步 `update()`
|
||||
继续保留原有导航行为。恢复与原 SDK 身份、销毁状态、确切 update revision 绑定。
|
||||
初版的嵌套显式 update 用例有两项失败,补入 revision 守卫后通过;销毁中的最后
|
||||
lookup 同样不能重新打开菜单。`src/types.ts` 只添加可选内部导航能力的窄类型。
|
||||
|
||||
工厂/option/update 签名、SDK 选择顺序、公开声明、DOM/CSS hooks、入口不变。
|
||||
没有修改核心 setting.update 的语义,没有强制点击或增加等待超时,没有新增依赖。
|
||||
包内 README 与 ARCHITECTURE 已解释自动和显式刷新、导航及资源所有权。
|
||||
|
||||
## 验证
|
||||
|
||||
固定 Node24.21.0/Yarn1.22.22,Windows 的 Chromium153.0.8010.12、Firefox155.0。
|
||||
源码初轮设置矩阵32项通过;增加重入守卫后,完整候选DASH定向矩阵92项通过。
|
||||
源码及main/legacy/ESM三格式Node446项通过,包内严格TS与专项lint通过;根lint
|
||||
0错误/1个既有warning。最终含文档tarball在仓库外离线安装并冻结重装,全部
|
||||
文件指纹核对,五组类型模式通过且各拒绝八项非法调用。
|
||||
|
||||
打包产物的main设置矩阵32项、legacy完整定向矩阵92项均通过,0失败/跳过/重试。
|
||||
任务完成,DASH-MENU-01按根因和旧红新绿证据关闭;完整组合及发布任务仍开放。
|
||||
浏览器使用核验tarball解出的运行时,类型检查使用实际安装包;不是完整installed
|
||||
浏览器验收。[最终报告](../baselines/dash-menu-validation.json)记录每个浏览器的
|
||||
输入SHA、退出码及失败,不以套件名称替代输入来源证明。
|
||||
|
||||
一次tarball提取辅助脚本最初把字节传给需要路径的函数,提取失败;随后运行未能
|
||||
设置产物路径而实际验证了源码。已按附件输入明确归档为源码92项,修正提取后
|
||||
main/legacy另行运行并核对候选SHA,未把该源码结果计作打包产物验证。
|
||||
|
||||
定向候选矩阵仅在命令行排除已冻结的裸SDK与旧发布插件对照;默认完整文件与CI
|
||||
仍保留它们的原断言。原DASH-SEEK-01的上游缺陷、PKG-DASH-05/06、WebKit能力、
|
||||
设备、远端CI及三轮发布复盘不因本次菜单修复而完成。
|
||||
|
||||
## 重跑与回退
|
||||
|
||||
`yarn test:dash-control`、`yarn test:dash-types-package`;设置专项通过
|
||||
`yarn test:browser:source test/browser/dash-sdk.spec.js --project=chromium
|
||||
--project=firefox --grep 'SDK refresh preserves the open|actual settings' --workers=2`。
|
||||
产物验证必须显式设置 `ARTPLAYER_DASH_ARTIFACT` 为已核验的main/legacy文件。
|
||||
完整候选范围使用 `--grep-invert 'native SDK track switch|published DASH / 4.5.2'`;
|
||||
去掉过滤将包含保留的历史SDK/旧插件失败。每次运行前先归档已有报告。
|
||||
|
||||
回退本任务独立提交并重建DASH三格式即可,不单独修改生成文件。没有push、部署或发布。
|
||||
@@ -99,3 +99,13 @@ UMD 测试 VM 显式注入宿主 console,以检查原始错误身份;没有
|
||||
跳转4失败,新源码8通过,最终main/legacy各8个严格跳转通过。main完整定向76通过;
|
||||
legacy同范围75通过、1个SDK5.2.1设置点击不可见失败,归PKG-DASH-MENU-01继续调查。
|
||||
不将局部跳转修复等同于DASH组合/分发验收全部完成。
|
||||
|
||||
## 自动刷新设置导航修复
|
||||
|
||||
PKG-DASH-MENU-01已确认SDK自动刷新调用setting.update重置根面板,导致打开的
|
||||
子菜单失去art-current;在真实SDK四组组合复现。插件现在只为自动刷新捕获并
|
||||
恢复仍由自己拥有、仍打开的子菜单,且在质量和音轨两项更新后恢复。显式update
|
||||
保持原行为;revision/SDK/销毁/菜单所有权防止陈旧恢复。源码92、main设置32、
|
||||
legacy候选92均通过;Node446和五组安装类型通过,原始75/1报告保留。
|
||||
见[实施记录](changes/2026-09-14-PKG-DASH-MENU-01-settings-navigation.md)及
|
||||
[证据](baselines/dash-menu-validation.json)。DASH-MENU-01关闭,其他SDK/设备/分发门槛不变。
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 261 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 50 / doing 20 / blocked 0 / done 191 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 49 / doing 20 / blocked 0 / done 192 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -219,7 +219,7 @@
|
||||
| PKG-DASH-03 | artplayer-plugin-dash-control<br>整理内部职责与资源 | PKG-DASH-02, CORE-11, CORE-14 | 能力适配保留 SDK 4.x 与 5.x,稳定 ID 映射、ABR 状态、UI 清理和生命周期职责分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
|
||||
| PKG-DASH-04 | artplayer-plugin-dash-control<br>迁移自有源码和公开类型 | PKG-DASH-03, ENG-04, ENG-06, CORE-07 | dash.js adapter、selector 和回调类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done |
|
||||
| PKG-DASH-SEEK-01 | artplayer-plugin-dash-control<br>修复 SDK 4.5.2 暂停跳转后的缓冲指标停滞 | PKG-DASH-04 | 按版本和实测空缓冲限定的指标同步、生命周期守卫及真实 SDK 旧红新绿 | 新插件在新旧核心及 Chromium/Firefox 原位置回归通过;不修改 SDK 方法/配置、媒体时间或删除缓冲;旧 SDK 原生缺陷与旧插件限制独立记录,不宣称第三方本体已修复 | H | done |
|
||||
| PKG-DASH-MENU-01 | artplayer-plugin-dash-control<br>定位并修复 SDK 刷新期间设置选项不可见 | PKG-DASH-SEEK-01 | 真实 SDK 菜单点击失败根因、对应兼容修复及新旧核心回归 | 保留 legacy/旧核心/SDK5.2.1 的原失败;确定菜单在点击过程中不可见的原因;不靠 force 点击、扩大超时或重复运行覆盖问题;main/legacy 质量与音轨设置及 SDK 刷新组合通过 | H | todo |
|
||||
| PKG-DASH-MENU-01 | artplayer-plugin-dash-control<br>定位并修复 SDK 刷新期间设置选项不可见 | PKG-DASH-SEEK-01 | 真实 SDK 菜单点击失败根因、对应兼容修复及新旧核心回归 | 保留 legacy/旧核心/SDK5.2.1 的原失败;确定菜单在点击过程中不可见的原因;不靠 force 点击、扩大超时或重复运行覆盖问题;main/legacy 质量与音轨设置及 SDK 刷新组合通过 | H | done |
|
||||
| PKG-DASH-05 | artplayer-plugin-dash-control<br>验证新旧核心和组合 | PKG-DASH-04, CORE-22, PKG-DASH-SEEK-01 | 固定 dash.js 4.5.2/5.2.1 与本地 DASH 实际清晰度/音轨、高亮、Auto 和换源组合 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | doing |
|
||||
| PKG-DASH-06 | artplayer-plugin-dash-control<br>验证分发并同步文档 | PKG-DASH-05, ENG-07, PKG-DASH-MENU-01 | dash.control.js、支持的 dash.js 版本与产物 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||
|
||||
@@ -563,7 +563,7 @@
|
||||
- PKG-DASH-03: [记录](changes/2026-09-12-PKG-DASH-03-runtime.md) [记录](baselines/dash-runtime.json) [记录](dash-validation.md)
|
||||
- PKG-DASH-04: [记录](changes/2026-09-12-PKG-DASH-04-types.md) [记录](baselines/dash-types-validation.json) [记录](dash-validation.md)
|
||||
- PKG-DASH-SEEK-01: [记录](changes/2026-09-14-PKG-DASH-SEEK-01-buffer-metrics.md) [记录](baselines/dash-seek-recovery-validation.json)
|
||||
- PKG-DASH-MENU-01: [记录](changes/2026-09-14-PKG-DASH-SEEK-01-buffer-metrics.md) [记录](baselines/dash-seek-recovery-validation.json)
|
||||
- PKG-DASH-MENU-01: [记录](changes/2026-09-14-PKG-DASH-MENU-01-settings-navigation.md) [记录](baselines/dash-menu-validation.json) [记录](dash-validation.md)
|
||||
- PKG-DASH-05: [记录](changes/2026-09-12-PKG-DASH-05-sdk-checkpoint.md) [记录](baselines/dash-sdk.json) [记录](baselines/dash-sdk-checkpoint.json) [记录](dash-validation.md) [记录](changes/2026-09-12-PKG-DASH-05-sdk-types.md) [记录](baselines/dash-sdk-types-validation.json) [记录](changes/2026-09-12-PKG-DASH-05-sdk-events.md) [记录](baselines/dash-sdk-events-validation.json) [记录](changes/2026-09-12-PKG-DASH-05-seek-diagnosis.md) [记录](baselines/dash-seek-diagnosis.json)
|
||||
- PKG-MULTI-SUB-01: [记录](baselines/multiple-subtitles-release.json) [记录](baselines/multiple-subtitles-contract.md) [记录](baselines/multiple-subtitles-contract-validation.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-01-contract.md)
|
||||
- PKG-MULTI-SUB-02: [记录](baselines/multiple-subtitles-failures.json) [记录](changes/2026-09-13-PKG-MULTI-SUB-02-failures.md)
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# 进度与证据
|
||||
|
||||
## PKG-DASH-MENU-01 SDK 刷新设置子菜单修复完成
|
||||
|
||||
原legacy设置点击失败的trace显示根面板取代质量子菜单,setting仍显示。
|
||||
真实SDK刷新四组旧红用例全部复现;在插件自动refresh中捕获并在两项菜单更新后
|
||||
恢复拥有的打开selector,显式update维持旧行为。新旧核心/两SDK/两引擎设置32项
|
||||
通过,最终源码完整候选92通过;核验tarball的main设置32、legacy完整候选92通过。
|
||||
三格式及源码Node446、仓库外安装/冻结重装与五组类型通过,严格TS/lint通过,
|
||||
根lint仍1个既有warning。嵌套update旧版本守卫两项失败补修后通过;销毁和接管不复活。
|
||||
|
||||
关闭DASH-MENU-01,原legacy75/1报告与四个新复现均保留,没有force点击、扩大超时
|
||||
或覆盖旧失败。辅助提取最初失败后的运行按真实输入计作源码;产物修正后独立验证。
|
||||
见[记录](changes/2026-09-14-PKG-DASH-MENU-01-settings-navigation.md)和
|
||||
[证据](baselines/dash-menu-validation.json)。261项:192 done、20 doing、49 todo。
|
||||
DASH-SEEK-01的裸SDK/旧插件限制、DASH05/06、设备/远端CI及全局发布仍开放。
|
||||
本任务独立本地提交并完成提交审计后继续其他插件与组合验收;没有push或发布。
|
||||
|
||||
## PKG-DASH-SEEK-01 暂停跳转缓冲指标修复完成
|
||||
|
||||
仅在dash.js 4.5.2真实空缓冲且缓存指标陈旧时同步零值,恢复SDK自身下载调度。
|
||||
|
||||
@@ -274,4 +274,4 @@
|
||||
| CHAPTER-FULLSCREEN-GEOMETRY-01 | resolved / 已复现 | Chromium 原生全屏后章节 hover 标题曾出现后又隐藏 | PKG-CHAPTER-05, PKG-CHAPTER-HOVER-01 |
|
||||
| CANVAS-SUBTITLE-01 | resolved / 已复现 | Canvas底层video缺初始字幕轨道且普通Canvas挂载不能加载原生字幕 | PKG-CANVAS-SUBTITLE-01, PKG-CANVAS-05 |
|
||||
| DPIP-INSTALLED-PROVENANCE-01 | resolved / 已复现 | Document PiP测试加载器忽略显式安装map并回退到源码 | PKG-CANVAS-05, CI-01 |
|
||||
| DASH-MENU-01 | open / 已复现 | SDK 5.2.1 播放中设置质量选项在点击时变为不可见 | PKG-DASH-MENU-01, PKG-DASH-05, REVIEW-02 |
|
||||
| DASH-MENU-01 | resolved / 已复现 | SDK 5.2.1 播放中设置质量选项在点击时变为不可见 | PKG-DASH-MENU-01, PKG-DASH-05, REVIEW-02 |
|
||||
+10
-3
@@ -6275,7 +6275,7 @@
|
||||
"id": "DASH-MENU-01",
|
||||
"title": "SDK 5.2.1 播放中设置质量选项在点击时变为不可见",
|
||||
"confirmation": "reproduced",
|
||||
"status": "open",
|
||||
"status": "resolved",
|
||||
"owners": [
|
||||
"PKG-DASH-MENU-01",
|
||||
"PKG-DASH-05",
|
||||
@@ -6285,8 +6285,15 @@
|
||||
"refactor/changes/2026-09-14-PKG-DASH-SEEK-01-buffer-metrics.md",
|
||||
"refactor/baselines/dash-seek-recovery-validation.json"
|
||||
],
|
||||
"compatibleResolution": "最终 legacy 定向矩阵复现:旧核心、新插件、Chromium 的180p选项先不稳定后不可见;保留点击失败与trace。SDK5.2.1不进入4.5.2指标修复分支,但菜单根因及历史来源尚未确定。",
|
||||
"closureCriteria": "定位实际隐藏/刷新时序并提供可复现旧红新绿;新旧核心、main/legacy、质量/音轨、SDK刷新与销毁组合验证,不靠force点击或重跑覆盖失败。"
|
||||
"compatibleResolution": "SDK自动刷新前捕获本插件拥有的打开子菜单,在两项设置更新后按新selector恢复;显式update、关闭/移除/接管以及嵌套更新保持原边界。守卫SDK身份、revision、销毁与菜单所有权。",
|
||||
"closureCriteria": "定位实际隐藏/刷新时序并提供可复现旧红新绿;新旧核心、main/legacy、质量/音轨、SDK刷新与销毁组合验证,不靠force点击或重跑覆盖失败。",
|
||||
"resolutionEvidence": [
|
||||
"refactor/changes/2026-09-14-PKG-DASH-MENU-01-settings-navigation.md",
|
||||
"refactor/baselines/dash-menu-validation.json",
|
||||
"test/browser/dash-sdk.spec.js",
|
||||
"test/dash-events.test.js"
|
||||
],
|
||||
"resolutionRationale": "原trace显示设置仍打开但导航退回根面板;真实SDK刷新在四组核心/SDK组合复现相同失败。修复后源码92、main设置32、legacy完整候选92通过,新旧核心/两SDK/两引擎覆盖质量及音轨,原失败与未加force/延长超时的回归均保留。Node446验证三格式及重入/销毁边界;DASH其他SDK/设备/发布风险仍独立开放。"
|
||||
}
|
||||
]
|
||||
}
|
||||
+4
-3
@@ -2268,13 +2268,14 @@
|
||||
"dependsOn": [
|
||||
"PKG-DASH-SEEK-01"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "done",
|
||||
"risk": "H",
|
||||
"deliverable": "真实 SDK 菜单点击失败根因、对应兼容修复及新旧核心回归",
|
||||
"acceptance": "保留 legacy/旧核心/SDK5.2.1 的原失败;确定菜单在点击过程中不可见的原因;不靠 force 点击、扩大超时或重复运行覆盖问题;main/legacy 质量与音轨设置及 SDK 刷新组合通过",
|
||||
"evidence": [
|
||||
"changes/2026-09-14-PKG-DASH-SEEK-01-buffer-metrics.md",
|
||||
"baselines/dash-seek-recovery-validation.json"
|
||||
"changes/2026-09-14-PKG-DASH-MENU-01-settings-navigation.md",
|
||||
"baselines/dash-menu-validation.json",
|
||||
"dash-validation.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -330,6 +330,39 @@ for (const version of ['4.5.2', '5.2.1']) {
|
||||
for (const core of ['published', 'candidate']) {
|
||||
for (const version of ['4.5.2', '5.2.1']) {
|
||||
for (const type of ['quality', 'audio']) {
|
||||
test(`${core} core / DASH ${version}: SDK refresh preserves the open ${type} settings panel`, async ({ page }, testInfo) => {
|
||||
await openDash(page, version, core, 'candidate', testInfo)
|
||||
await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)
|
||||
await page.locator('#play').click()
|
||||
await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.3)
|
||||
await page.locator('.art-control-setting').click()
|
||||
await page.locator(`[data-name="dash-${type}"]`).click()
|
||||
await page.evaluate((type) => {
|
||||
const { dash } = window.art
|
||||
if (type === 'quality') {
|
||||
dash.updateSettings({ streaming: { abr: { autoSwitchBitrate: { video: false } } } })
|
||||
if (dash.setQualityFor)
|
||||
dash.setQualityFor('video', 1)
|
||||
else
|
||||
dash.setRepresentationForTypeById('video', '1')
|
||||
}
|
||||
else {
|
||||
dash.setCurrentTrack(dash.getTracksFor('audio').find(track => track.lang === 'fr'))
|
||||
}
|
||||
}, type)
|
||||
const changed = type === 'quality' ? '180p' : 'fr'
|
||||
await expect(page.locator(`.art-control-dash-${type} .art-selector-value`)).toHaveText(changed)
|
||||
await expect.poll(() => page.evaluate(type => window.art.setting.active === window.art.setting.find(`dash-${type}`).selector, type)).toBe(true)
|
||||
const label = type === 'quality' ? '90p' : 'en'
|
||||
await page.locator('.art-setting-panel.art-current .art-setting-item-left-text').filter({ hasText: new RegExp(`^${label}$`) }).click()
|
||||
if (type === 'quality')
|
||||
await expect.poll(() => page.evaluate(() => window.art.video.videoHeight)).toBe(90)
|
||||
else
|
||||
await expect.poll(() => page.evaluate(() => window.art.dash.getCurrentTrackFor('audio').lang)).toBe('en')
|
||||
await expect(page.locator(`.art-control-dash-${type} .art-selector-value`)).toHaveText(label)
|
||||
expect(await page.evaluate(() => window.sdkErrors)).toEqual([])
|
||||
})
|
||||
|
||||
test(`${core} core / DASH ${version}: actual settings ${type} selection survives SDK refresh`, async ({ page }, testInfo) => {
|
||||
await openDash(page, version, core, 'candidate', testInfo)
|
||||
await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true)
|
||||
|
||||
@@ -50,6 +50,108 @@ function seekHost() {
|
||||
return { ...host, samples, levels, buffers, metrics, seekState: state }
|
||||
}
|
||||
|
||||
function navigationHost(version) {
|
||||
const host = eventHost(version)
|
||||
const setting = host.art.setting
|
||||
const update = setting.update
|
||||
const renders = []
|
||||
Object.assign(setting, {
|
||||
option: [],
|
||||
active: null,
|
||||
show: true,
|
||||
find: name => host.settings.get(name),
|
||||
render(option) {
|
||||
setting.active = option
|
||||
renders.push(option)
|
||||
},
|
||||
update(option) {
|
||||
update(option)
|
||||
setting.active = setting.option
|
||||
},
|
||||
})
|
||||
return { ...host, renders, open(name) {
|
||||
setting.active = host.settings.get(name).selector
|
||||
} }
|
||||
}
|
||||
|
||||
for (const { name, sdk, factory } of candidates) {
|
||||
test(`DASH ${sdk} (${name}): automatic refresh retains the owned quality or audio panel after both menu updates`, async () => {
|
||||
for (const name of ['dash-quality', 'dash-audio']) {
|
||||
const host = navigationHost(sdk)
|
||||
factory(bothMenus())(host.art).update()
|
||||
host.open(name)
|
||||
const previous = host.art.setting.active
|
||||
host.fire('qualityChangeRendered')
|
||||
await flush()
|
||||
assert.equal(host.renders.length, 1)
|
||||
assert.equal(host.art.setting.active, host.settings.get(name).selector)
|
||||
assert.notEqual(host.art.setting.active, previous)
|
||||
}
|
||||
})
|
||||
|
||||
test(`DASH ${sdk} (${name}): explicit update and closed or foreign panels retain existing navigation behavior`, async () => {
|
||||
for (const mode of ['explicit', 'closed', 'foreign', 'unavailable', 'removed']) {
|
||||
const host = navigationHost(sdk)
|
||||
const option = bothMenus()
|
||||
const plugin = factory(option)(host.art)
|
||||
plugin.update()
|
||||
host.open('dash-quality')
|
||||
if (mode === 'explicit') {
|
||||
plugin.update()
|
||||
}
|
||||
else {
|
||||
if (mode === 'closed')
|
||||
host.art.setting.show = false
|
||||
if (mode === 'foreign')
|
||||
host.settings.get('dash-quality').onSelect = () => {}
|
||||
if (mode === 'unavailable')
|
||||
delete host.art.setting.render
|
||||
if (mode === 'removed')
|
||||
option.quality.setting = false
|
||||
host.fire('qualityChangeRendered')
|
||||
await flush()
|
||||
}
|
||||
assert.equal(host.renders.length, 0)
|
||||
assert.equal(host.art.setting.active, host.art.setting.option)
|
||||
}
|
||||
})
|
||||
|
||||
test(`DASH ${sdk} (${name}): navigation lookup cannot restore an obsolete refresh after a nested explicit update`, async () => {
|
||||
const host = navigationHost(sdk)
|
||||
const plugin = factory(bothMenus())(host.art)
|
||||
plugin.update()
|
||||
host.open('dash-quality')
|
||||
const find = host.art.setting.find
|
||||
let reads = 0
|
||||
host.art.setting.find = (name) => {
|
||||
if (++reads === 2)
|
||||
plugin.update()
|
||||
return find(name)
|
||||
}
|
||||
host.fire('qualityChangeRendered')
|
||||
await flush()
|
||||
assert.equal(host.renders.length, 0)
|
||||
assert.equal(host.art.setting.active, host.art.setting.option)
|
||||
})
|
||||
|
||||
test(`DASH ${sdk} (${name}): destruction from navigation lookup cannot reopen settings`, async () => {
|
||||
const host = navigationHost(sdk)
|
||||
factory(bothMenus())(host.art).update()
|
||||
host.open('dash-quality')
|
||||
const find = host.art.setting.find
|
||||
let reads = 0
|
||||
host.art.setting.find = (name) => {
|
||||
const result = find(name)
|
||||
if (++reads === 2)
|
||||
host.art.destroy()
|
||||
return result
|
||||
}
|
||||
host.fire('qualityChangeRendered')
|
||||
await flush()
|
||||
assert.equal(host.renders.length, 0)
|
||||
})
|
||||
}
|
||||
|
||||
for (const { name, factory } of candidates.filter(item => item.sdk === 4)) {
|
||||
test(`DASH (${name}): seeking records only measured empty stale metrics without changing SDK methods or media`, () => {
|
||||
const host = seekHost()
|
||||
|
||||
Reference in new issue
Block a user