forked from the1812/Bilibili-Evolved
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathremember-speed.js
1 lines (1 loc) · 16.7 KB
/
remember-speed.js
1
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["video/player/remember-speed"]=t():e["video/player/remember-speed"]=t()}(self,(function(){return function(){"use strict";var e={d:function(t,i){for(var s in i)e.o(i,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:i[s]})},o:function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},t={};e.d(t,{component:function(){return B}});var i=coreApis.utils.urls,s=coreApis.settings,o=coreApis.utils.log,n=coreApis.pluginApis.hook;const r=e=>"function"==typeof e?{next:e}:e,a=e=>function e(t,i,o){let n=!1;const a=[],d=[];let l=!1;const c=()=>{for(;a.length;)a.pop()();d.length=0,l=!0},p=e=>{l||(d.forEach((t=>{t.error?.(e),(0,s.getGeneralSettings)().devMode&&console.error(e)})),c())},u=e=>{l||d.forEach((t=>{try{t.next(e)}catch(e){p(e)}}))},h=()=>{d.forEach((e=>{e.complete?.()})),c()},b=()=>{if(n)return;const e=t?.({next:u,error:p,complete:h});e&&a.push(e),n=!0},m=e=>null==e?null:(d.push(e),()=>{lodash.pull(d,e)}),g=(...t)=>0===t.length?{subscribe:e=>{const t=m(r(e));return(o?.connect??b)(),t},pipe:g,next:u,error:p,complete:h,...o}:e(t[0],{subscribe:m},o||{connect:b,next:u}).pipe(...t.slice(1));if(i){const e=t?.({subscribe:e=>i.subscribe({error:p,complete:h,...r(e)}),next:u,error:p,complete:h});e&&a.push(e)}return g()}(e),d=(e,t)=>a((({next:i})=>(e.addEventListener(t,i),()=>e.removeEventListener(t,i)))),l=(e,...t)=>a((({next:i})=>{e(...t,i)})),c=e=>new Promise(((t,i)=>{const s=e.subscribe({next:e=>{t(e),s()},error:()=>{i(),s()},complete:()=>{i(),s()}})}));var p=coreApis.componentApis.video.playerAgent,u=coreApis.lifeCycle,h=coreApis.observer,b=coreApis.utils,m=coreApis.utils.sort;const g=e=>(...t)=>{Promise.resolve().then((()=>e(...t)))},v=(...e)=>a((({next:t,error:i,complete:s})=>(e=>{const t=new Set;return e((e=>{lodash.castArray(e).forEach((e=>{t.add(e)}))})),()=>{t.forEach((e=>{e()}))}})((o=>{const n=[];let r=0;o(e.map(((o,a)=>{return o.pipe((d=g,({subscribe:e,next:t,complete:i,error:s})=>{e(lodash.mapValues({next:t,complete:i,error:s},(e=>d(e))))})).subscribe({next:i=>{n[a]=i,n.reduce((e=>e+1),0)===e.length&&t(n.slice())},complete:()=>{r++,r===e.length&&s()},error:i});var d}))),o((()=>{n.length=0,r=0}))})))),f=e=>({subscribe:t,next:i,error:s})=>{t(lodash.debounce((e=>{try{i(e)}catch(e){s(e)}}),e))},y=e=>({subscribe:t,next:i})=>{t((t=>{e(t)&&i(t)}))},S=(...e)=>({next:t,subscribe:i})=>{let s=!1;i((i=>{s||e.forEach((e=>t(e))),t(i),s=!0}))};var x=coreApis.pluginApis.data;const w=(e,t)=>{const i=t=>{(0,x.registerAndGetData)(e,t)[0]=t},s=(0,x.getData)(e);if(s.length)return[s[0],i];if(t){const e=t();return i(e),[e,i]}return[void 0,i]},E=(e,t=!1)=>t&&1===e?"倍速":Math.trunc(e)===e?`${e}.0x`:`${e}x`,R=e=>{if("倍速"===e)return 1;const t=/([0-9]*[.]?[0-9]+)x/.exec(e);if(t)return parseFloat(t[1]);throw new Error(`unknown speed text: ${e}`)};const V=p.playerAgent.provideCustomQuery({video:{speedMenuList:".bilibili-player-video-btn-speed-menu",speedMenuItem:".bilibili-player-video-btn-speed-menu-list",speedNameBtn:".bilibili-player-video-btn-speed-name",speedContainer:".bilibili-player-video-btn-speed",active:".bilibili-player-active",show:".bilibili-player-speed-show"},bangumi:{speedMenuList:".squirtle-speed-select-list",speedMenuItem:".squirtle-select-item",speedNameBtn:".squirtle-speed-select-result",speedContainer:".squirtle-speed-wrap",active:".active",show:".bilibili-player-speed-show"}});let A;!function(e){e[e.MIN=0]="MIN",e[e.CURRENT=1]="CURRENT",e[e.MAX=2]="MAX"}(A||(A={}));const C=(e,t,i)=>{const s=new MutationObserver(i);return s.observe(e,t),s},O=([e,t])=>{if(!e)throw new Error("speed container element not found!");if(!t)throw new Error("video element not found!");const i=e.querySelector(V.custom.speedNameBtn.selector),s=e.querySelector(V.custom.speedMenuList.selector);let o,n,r;const d=a(),l=a().pipe((({subscribe:e,next:t})=>{let i,s=!0;e((e=>{(s||i!==e)&&(s=!1,i=e,t(e))}))}));l.pipe(S(void 0),(({subscribe:e,next:t})=>{const i=[];return e((e=>{2===i.length&&i.shift(),i.push(e),2===i.length&&t(i.slice())})),()=>{i.length=0}})).subscribe((([e,t])=>{n=e,o=t}));const c=e=>{if(e)switch(e.nodeType){case Node.TEXT_NODE:l.next(R(e.data));break;case Node.ELEMENT_NODE:l.next(R(e.innerHTML));break;default:console.warn("The target parameter of updateActiveVideoSpeed must be a Node, and the node type must be one of TEXT_NODE and ELEMENT_NODE")}},p=()=>{r=lodash([...s.children]).map((e=>lodash.attempt((()=>R(e.textContent))))).reject((e=>lodash.isError(e))).sort((0,m.ascendingSort)()).value()};c(i),p();const u=C(s,{childList:!0,attributes:!0},(e=>{const{attributes:t=[],childList:i=[]}=lodash.groupBy(e,"type");i.length&&p(),d.next({attributes:t,childList:i})})),h=C(i,{childList:!0,subtree:!0},(e=>{e.forEach((e=>{const[t]=e.addedNodes;c(t)}))}));return{containerElement:e,videoElement:t,nameBtnElement:i,menuListElement:s,query:e=>{return(0,b.des)(`./*[contains(@class, "${t=V.custom.speedMenuItem.selector,t.replace(/^\./,"")}") and normalize-space()="${E(e)}"]`,s);var t},dispose:()=>{u.disconnect(),h.disconnect()},activeVideoSpeed$:l,menuListElementMutations$:d,getActiveVideoSpeed:()=>o,getOldActiveVideoSpeed:()=>n,getAvailableSpeedValues:()=>r}},$=e=>{const{videoElement:t,menuListElement:i}=e,s=d(i,"click").pipe((o=e=>{const{innerText:t,innerHTML:i}=e.target,s=t.trim()||i.trim();return lodash.attempt((()=>R(s)))},({subscribe:e,next:t})=>{e((e=>{t(o(e))}))}),y((e=>!lodash.isError(e))));var o;const n=a((({next:e})=>{let i=t;do{i=Object.getPrototypeOf(i)}while(null===i||!Object.prototype.hasOwnProperty.call(i,"playbackRate"));const s=Object.getOwnPropertyDescriptor(i,"playbackRate");return Object.defineProperty(i,"playbackRate",{set(t){s.set.call(this,t),e(t)}}),()=>{Object.defineProperty(i,"playbackRate",s)}})),r=s.pipe((({subscribe:e,next:t})=>{let i,s=!0;e((e=>{(s||i!==e)&&(s=!1,i=e,t(e))}))})),l=n.pipe((({subscribe:e,next:t})=>{let i,s=!0;e((e=>{(s||i!==e)&&(s=!1,i=e,t(e))}))})),c=a((({next:e})=>{const t=v(r,l);return t.subscribe((([t,i])=>{t===i&&e(i)})),()=>t.complete()})).pipe((({subscribe:e,next:t})=>{let i,s=!0;e((e=>{(s||i!==e)&&(s=!1,i=e,t(e))}))}));let p;l.pipe(f(200),S(void 0),(({subscribe:e,next:t})=>{const i=[];return e((e=>{2===i.length&&i.shift(),i.push(e),2===i.length&&t(i.slice())})),()=>{i.length=0}})).subscribe((([e])=>{p=e}));const u={menuListElementClickSpeed$:s,menuListElementClickSpeedChange$:r,playbackRate$:n,playbackRateChange$:l,videoSpeedChange$:c};return{...e,...u,dispose:()=>{lodash.values(u).forEach((e=>{e.complete()})),e.dispose()},getOldPlaybackRate:()=>p}},[N]=w("speed.NoSuchSpeedMenuItemElementError",(()=>class extends Error{constructor(e){const t=lodash.attempt((()=>E(e))),i=lodash.isError(t)?String(e):String(t);var s,o,n;super(`There is no such speed menu item as ${i}`),this.speed=e,n=void 0,(o="formattedSpeed")in(s=this)?Object.defineProperty(s,o,{value:n,enumerable:!0,configurable:!0,writable:!0}):s[o]=n,this.formattedSpeed=i}})),j=e=>{const{query:t,videoElement:i,videoSpeedChange$:s,getOldActiveVideoSpeed:o,getAvailableSpeedValues:n,getActiveVideoSpeed:r}=e,a=async(e,o=200)=>{const n=t(e);if(null==n)throw new N(e);n.click();const r=t=>{if((t??i.playbackRate)!==e)throw new Error(`failed to set ${E(e)} video speed.`)},a=[c(s.pipe(f(Math.max(0,o||0))))];o>0&&a.push(new Promise(((e,t)=>setTimeout((()=>setTimeout(t,o)))))),await Promise.all(a).then(r).catch(r)},d=async()=>{await a(1)},l=async(e,t)=>{if(lodash.isNil(e)&&(e=!1),"boolean"==typeof e)e||1===i.playbackRate?await a(o()):await d();else{const i=n();switch(t){case A.MIN:await a(i[e]);break;case A.MAX:await a(i[i.length-1+e]);break;case A.CURRENT:default:{const t=i.indexOf(r());if(-1===t)throw new Error("Unexpected Error: The available speed values do not include the active speed value, this should be a bug, please report the issue on github!");await a(i[t+e])}}}},p=async e=>{try{await l(e,A.CURRENT)}catch(e){if(console.warn(e),!(e instanceof N))throw e}};return Object.assign(e,{set:a,force:async e=>{i.playbackRate=e},reset:d,toggle:l,step:p,increase:async()=>{await p(1)},decrease:async()=>{await p(-1)}})},k=()=>w("speed.speedContext"),T=()=>w("speed.buildArguments$",(()=>{return a().pipe((e=e=>e.settings.enabled,({subscribe:t,next:i})=>{const s=new Set;return t((t=>{const o=s.size;e(t)?s.add(t):s.delete(t),s.size!==o&&i([...s])})),()=>{s.clear()}}));var e})),L=async(e=lodash.identity)=>{const[t,i]=k();if(t)return t;let s,o;const[n]=w("lifeCycleComponentLoaded$",(()=>d(unsafeWindow,u.LifeCycleEventTypes.ComponentsLoaded))),[r]=T(),[p]=w("speed.videoChange$",(()=>l(h.videoChange).pipe(y((({aid:e,cid:t})=>e||t))))),[b]=w("speed.speedContext$",(()=>a((({next:t})=>v(p,r,n).subscribe((([i,n])=>{const[r]=k();r?.dispose(),o?.("context update");const a=new Promise(((e,t)=>{s=e,o=t}));Promise.all([Promise.all([V.custom.speedContainer(),V.query.video.element()]).then(s),a]).then((([,e])=>e)).then(O).then($).then(j).then((e=>Object.assign(e,{videoIdObject:i,speedContext$:b,videoChange$:p}))).then(e(n)).then(t).catch((e=>console.error(e)))}))))));return b.subscribe(i),c(b)};function M(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class P{constructor(e){this.entryContext=e,M(this,"speedContext",void 0),M(this,"settings",void 0),M(this,"coreApis",void 0),M(this,"metadata",void 0),M(this,"options",void 0),M(this,"getVideoIdObject",void 0),M(this,"getAvailableSpeedValues",void 0),M(this,"getOldActiveVideoSpeed",void 0),M(this,"forceVideoSpeed",void 0),M(this,"getVideoSpeed",void 0),M(this,"setVideoSpeed",void 0),M(this,"resetVideoSpeed",void 0),M(this,"toggleVideoSpeed",void 0),M(this,"increaseVideoSpeed",void 0),M(this,"decreaseVideoSpeed",void 0),lodash.assign(this,e,{options:e.settings.options}),this.migrate?.(),lodash.assign(this,lodash.mapValues(P.contextMap,(e=>async(...t)=>{const i=await L(),s=lodash.get(i,e);return lodash.isFunction(s)?await s(...t):s})))}}M(P,"create",void 0),M(P,"contextMap",{getVideoIdObject:"videoIdObject",getAvailableSpeedValues:"getAvailableSpeedValues",getOldActiveVideoSpeed:"getOldActiveVideoSpeed",getVideoSpeed:"videoElement.playbackRate",setVideoSpeed:"set",forceVideoSpeed:"force",resetVideoSpeed:"reset",toggleVideoSpeed:"toggle",increaseVideoSpeed:"increase",decreaseVideoSpeed:"decrease"}),L((e=>t=>{const i=lodash.omit(t,"dispose"),o=e.map((e=>e.getSpeedContextMixin(i)));if(o.length>1){const e=lodash.intersection(...o.map(Object.keys));if(e.length)throw new Error(`In the registered speed component, there is an implementation of getSpeedContextMixin that causes the speed context to be mixed in ambiguous.\nThe repeated key names are ${e.join(", ")}`)}lodash.assign(i,...o);const n=[];return e.forEach((e=>{const t=lodash(e.settings.options).mapValues(((t,i)=>l(s.addComponentListener,`${e.metadata.name}.${i}`).pipe((({subscribe:e,next:t})=>{let i,s=!0;e((e=>{(s||i!==e)&&(s=!1,i=e,t(e))}))})))).mapKeys(((e,t)=>`${t}$`)).value();n.push(...lodash.values(t)),e.options=new Proxy(e.settings.options,{get:(e,i,s)=>lodash.isSymbol(i)?Reflect.get(e,i,s):!Reflect.has(e,i)&&i.endsWith("$")?t[i]:Reflect.get(e,i,s)}),e.speedContext=i,e.onSpeedContext(i),e.settings.enabled&&lodash(t).entries().forEach((([t,i])=>{i.next(e.settings.options[t.slice(0,-1)])}))})),{...i,dispose:()=>{n.forEach((e=>e.complete())),t.dispose()}}})),P.create=function(e){const t=a().pipe((({subscribe:e,next:t})=>{let i,s=!0;e((e=>{(s||i!==e)&&(s=!1,i=e,t(e))}))}));return{...e,entry:i=>{const s=lodash.attempt((()=>new this(i)));if(s instanceof Error)return(0,o.logError)(s),null;const[r]=T();return t.subscribe((()=>{r.next(s)})),r.next(s),(0,n.getHook)(`speed.component.${e.name}`).after(s),s},reload:()=>t.next(!0),unload:()=>t.next(!1)}};var I=coreApis.toast;function q(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class G extends P{getSpeedContextMixin({videoIdObject:e,set:t,reset:i,toggle:s,getActiveVideoSpeed:o,getOldActiveVideoSpeed:n}){const r=async()=>{const i=this.getRestoredVideoSpeed(e);await t(i??1)};return{reset:r,toggle:async(...e)=>{const[a,...d]=e;if(null!=a&&"boolean"!=typeof a)return void s(a,...d);const{fixGlobalSpeed:l,individualRemember:c,globalSpeed:p}=this.options,u=l&&!c;a||o()===(u?p:1)?await t(n()):await(u?r():i())}}}migrate(){const{options:e}=this.settings;let t=!1;e.speed&&(e.globalSpeed=+e.speed||1,delete e.speed,t=!0),e.individualRememberList&&(e.individualRememberRecord=lodash.cloneDeep(e.individualRememberList),delete e.individualRememberList,t=!0),t&&(e.fixGlobalSpeed=!1,e.showRestoreTip=!0,delete e.remember,I.Toast.show("「扩展倍速」和倍速快捷键插件成为独立的组件或插件啦!详情请阅读组件描述.(此弹出提醒仅显示一次)","【记忆倍速】迁移提醒",8e3))}onSpeedContext({videoSpeedChange$:e,videoIdObject:t}){this.options.individualRemember$.subscribe((e=>{e&&(this.options.fixGlobalSpeed=!0)})),this.options.fixGlobalSpeed$.subscribe((e=>{e||(this.options.individualRemember=!1)}));const i=this.getRestoredVideoSpeed(t);i&&requestIdleCallback((async()=>{try{if(await this.setVideoSpeed(i,1e3),this.options.showRestoreTip){let e=`已还原到 ${E(i)} 倍速`;this.options.individualRemember&&null!=this.matchRememberSpeed()&&(e=`【独立倍速视频】${e}`),I.Toast.info(e,this.metadata.displayName,3e3)}}catch(e){const t=`${this.metadata.displayName} - 倍速还原操作失败`,i=e instanceof N?`没有 ${e.formattedSpeed} 这样的倍速项`:String(e);I.Toast.error(i,t,5e3),console.error(e)}})),e.subscribe((e=>{this.settings.enabled&&(this.options.individualRemember?e!==+this.options.globalSpeed&&this.rememberSpeed(e):this.options.fixGlobalSpeed||this.rememberSpeed(e,null))}))}getRestoredVideoSpeed(e){return this.options.individualRemember&&this.matchRememberSpeed(e.aid)||this.readGlobalVideoSpeed()}readGlobalVideoSpeed(){return parseFloat(String(this.options.globalSpeed))}matchRememberSpeed(e){for(const[t,i]of Object.entries(this.options.individualRememberRecord))if(i.some((t=>t.toString()===G.getAid(e).toString())))return parseFloat(t);return null}rememberSpeed(e,t){if(lodash.isNull(t))return void(this.options.globalSpeed=e);lodash.isUndefined(t)&&(t=G.getAid(t));const i=lodash.castArray(t);this.forgetSpeed(i),this.options.individualRememberRecord={...this.options.individualRememberRecord,[e]:lodash.unionWith(this.options.individualRememberRecord[e],i,G.aidComparator)}}forgetSpeed(e){lodash.isNil(e)&&(e=G.getAid(e));const t=lodash.castArray(e);this.options.individualRememberRecord=lodash(this.options.individualRememberRecord).mapValues((e=>lodash(e).pullAllWith(t,G.aidComparator).uniqWith(G.aidComparator).value())).pickBy((e=>e.length)).value()}}q(G,"getAid",((e=unsafeWindow.aid)=>{if(!e)throw new Error("aid is unknown");return e})),q(G,"aidComparator",((e,t)=>e.toString()===t.toString()));const B=G.create({name:"rememberVideoSpeed",displayName:"记忆倍速",author:{name:"JLoeve",link:"https://github.com/LonelySteve"},description:{"zh-CN":"\n\n> 提高视频播放器的倍速记忆体验,可实现跨页共享倍速,也可以按视频分别记忆倍速.\n\n### 🔧 **选项**\n\n- `全局记忆倍速值`:默认情况下,这是跨页共享的倍速值,如果启用「各视频分别记忆」,则作为从未独立记忆倍速视频的初始倍速值.\n- `固定全局倍速值`:默认情况下,全局倍速值将随着用户改变视频倍速而改变,打开此选项后,全局记忆倍速值不再受倍速调整的影响.\n- `各视频分别记忆`:打开此选项后,将按不同视频分别记忆倍速,对于从未被记忆过倍速的视频,将采用全局记忆倍速值,选项「固定全局倍速值」在此情况下强制生效.\n- `弹出还原倍速提示`:打开此选项后,每次成功还原倍速后都会弹出提示.\n\n### 🌈 **温馨提示**\n\n「扩展倍速」和倍速相关的快捷键插件已分离为单独的组件或插件.\n\n请根据自身需要:\n\n- 前往「组件」页面安装[「扩展倍速」](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/registry/dist/components/video/player/extend-speed.js)组件\n- 前往「插件」页面安装[「视频倍速 - 快捷键支持」](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/registry/dist/plugins/video/player/speed.js)插件.\n\n*如果想要清除当前视频的记忆状态,需要安装「视频倍速 - 快捷键支持」插件.*\n"},tags:[componentsTags.video],urlInclude:i.playerUrls,options:{globalSpeed:{displayName:"全局记忆倍速值",defaultValue:1,validator:e=>lodash.clamp(parseFloat(e),.0625,16)||1},fixGlobalSpeed:{displayName:"固定全局倍速值",defaultValue:!1},individualRemember:{displayName:"各视频分别记忆",defaultValue:!1},individualRememberRecord:{displayName:"独立记忆倍速记录",defaultValue:{},hidden:!0},showRestoreTip:{displayName:"弹出还原倍速提示",defaultValue:!0}}});return t=t.component}()}));