mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Merge remote-tracking branch 'upstream/preview' into dark-style
This commit is contained in:
commit
2eade3a29b
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -105,7 +105,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
可以通过 <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>?</kbd> 快捷键清除当前视频的倍数记忆状态.
|
||||
可以通过 <kbd>Shift</kbd> + <kbd>:</kbd> 快捷键清除当前视频的倍数记忆状态.
|
||||
|
||||
</details>
|
||||
|
||||
@ -152,7 +152,7 @@
|
||||
<details>
|
||||
<summary><strong>启用逐帧调整</strong></summary>
|
||||
|
||||
在播放器的时间右边增加两个按钮, 用于**较**精细调整视频时间. 支持键盘快捷键`Shift + 左/右方向键`. (旧版播放器只能用键盘快捷键, 不会显示按钮)
|
||||
在播放器的时间右边增加两个按钮, 用于**较**精细调整视频时间.
|
||||
|
||||
注: `视频的实际播放帧率`跟`视频本身的帧率`和`显示器的刷新率`有关, 很难计算一个精准的数值, 部分视频仍然会有暂停不到那种一闪而过的图的情况.
|
||||
|
||||
@ -166,9 +166,9 @@
|
||||
<details>
|
||||
<summary><strong>启用视频截图</strong></summary>
|
||||
|
||||
在播放器的时间右边增加截图按钮, 点击可以截取视频画面, 不会包含暂停标志和弹幕. 截取的图片将在网页右侧显示(非全屏或网页全屏模式), 可以单独保存或丢弃, 也可以截取一定数量后一次性保存. 支持键盘快捷键`Ctrl + Alt + C`. (旧版播放器只能用键盘快捷键, 不会显示按钮)
|
||||
在播放器的时间右边增加截图按钮, 点击可以截取视频画面, 不会包含暂停标志和弹幕. 截取的图片将在网页右侧显示(非全屏或网页全屏模式), 可以单独保存或丢弃, 也可以截取一定数量后一次性保存.
|
||||
|
||||
如果弹幕渲染类型选择了Canvas, 则可以再按住`Shift`键来截取带弹幕的截图. 也就是鼠标操作为"按住`Shift`点击截图按钮", 键盘操作为"`Ctrl + Shift + Alt + C`".
|
||||
如果弹幕渲染类型选择了Canvas, 则可以再按住`Shift`键来截取带弹幕的截图.
|
||||
|
||||
<img height="100" alt="时间右边的按钮" src="https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/images/compressed/control-enhance-buttons.jpg">
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
"custom-control-background.min.js": "A2699D3CBCB0857C3D0E5F6744964DF705C35C740E59448AFEE62508B7EE8848",
|
||||
"custom-navbar.min.css": "ACE2D981B7132A2FD1BDA8AC04A58E48359E1A5C407522C68349D550EF4D44C0",
|
||||
"custom-navbar.min.html": "B063DEEFF36B29C115483DD0061EF6C62E83085F3D1D9320DE94010A039D8738",
|
||||
"custom-navbar.min.js": "A0C1A4E01C54DB8FE1AEC2EB090824119DE24CCC52AE131D928CB7758F2D354D",
|
||||
"custom-navbar.min.js": "BB169AD738E8EA5C566399A4897C393671E0687F2194615238DD33E693996301",
|
||||
"custom-navbar-activities.min.js": "4AEB94FA06E543E3D0BA9E3337798DA3BC0AD194974A981710CE7CDAC9F6DD98",
|
||||
"custom-navbar-blank.min.js": "E8F08DA7CD2C67F9D064B959A64CFC6658103DBCBE2B9B58D978A1742E02D829",
|
||||
"custom-navbar-category.min.js": "A024B4418A6521EDDD9590F2F0FE5EB7FB0556A23468E8CBFF9609B935805348",
|
||||
@ -54,7 +54,7 @@
|
||||
"custom-navbar-iframe.min.js": "521D95AFDD0F496BD2B9AFA229D5D0E5DD57C518BAE8337D9753887EC1926C87",
|
||||
"custom-navbar-logo.min.js": "CE70A2E60EBDB145FC07D97A1DDABD1077DAA66CE83574B97788216D788BA4C5",
|
||||
"custom-navbar-messages.min.js": "700BD1AD47250B5F4726F547BEA02FAD1D7EF82A8E9BEDB1D3619F2E495E6B70",
|
||||
"custom-navbar-search-box.min.js": "D28DBE5F895FDD7CA54CE39E701D81CEC19C0593C33243A1B0C826EAE279AABB",
|
||||
"custom-navbar-search-box.min.js": "5DA8605A9755A2C75DD9B8D3EDA371A33C3922803A25FE0AFF44D6A09D1B3576",
|
||||
"custom-navbar-settings.min.js": "AFC11C00AF125225609F5A1C81D40324B07CA930B689C14A52E275BBBE3FDA55",
|
||||
"custom-navbar-simple-link.min.js": "51E2FDD06832E585E86884890D1DC6321A802D43332D7E7B5758A20BC1AB1E03",
|
||||
"custom-navbar-subscriptions.min.js": "D99A25DE4ABB104FA95166F51EB4FEE9DFDC4AE162CF189ECBCF99CA2E5E0E6C",
|
||||
@ -66,8 +66,8 @@
|
||||
"danmaku-segment.min.js": "43CC3236AFABA89BD0AE24D640809BE333772824E3994541AFC3CDDD9F881613",
|
||||
"danmaku-send-bar.min.css": "186013DAAC3E9E8C0B408CFA3D5C3F5BF702F25D435A386B384ECF3B5FBBBE18",
|
||||
"danmaku-send-bar.min.js": "670A37F301982F628B6663BB850EF9D9BF87983845CB080E603FC34582CFAD56",
|
||||
"dark.min.css": "B36488B7B6D7D06E6C7846DBC18C5DCA07C21B66F70DC800E503C7A34425E845",
|
||||
"dark.user.css": "DC8C9A2B8E65C9F5B92207AFC096240EB4A8BD9A76341FF8D03F685C73213773",
|
||||
"dark.min.css": "326A85B234DFCACD51633B094DFFFCB4279771E4C337688FDC5D56818973DC6E",
|
||||
"dark.user.css": "A1C5E947DA9C0867861CB22D832ED6717B30353A2447A7AB30C51A4E086202DD",
|
||||
"dark-color-scheme.min.js": "C83A38770DCEC5842E49617B07FFF97BCD6691982AFE40788ADC6A449C6474CB",
|
||||
"dark-important.min.css": "5902E037E040A6C364391FE27885A118A8FD8B30A4B5E8C737C5FE5CFFB67F42",
|
||||
"dark-navbar.min.css": "7FAD547E326B768904B3739C978DF86FFDDD5E5064FB8F490710D197CCC3018B",
|
||||
@ -125,7 +125,7 @@
|
||||
"gbk.min.js": "0EDFCB94F519365A8CCA9BF3AECE57DC6DB273EF3F41545095B8F03625782F0D",
|
||||
"get-number.min.js": "E644267B8A2DCEF2577BB9270F5C738BCE89C1C128071EBD3645903A930E08E0",
|
||||
"gui-settings.min.css": "F5D09B1F2D6FB5C9923A87EA087BB50450F4B912360F6EF578D90F35D8D86D36",
|
||||
"gui-settings.min.html": "E9F1477C563605A0158C9025A22E1165D16AF8D4A5DD179FF9501FEEF1A169BB",
|
||||
"gui-settings.min.html": "67FEEBC728AB02A85CCF55529A3C2BD8289D3E2F05D8CCC798812F11905AFC8A",
|
||||
"gui-settings.min.js": "202F382794C122D384F85555DE053D87066AEB167A47C71FE937CA270C9B204C",
|
||||
"haruna-scale.min.js": "7342274238E3012AD4FBCA753DA64DB8DA54F9E6860DF9689F20852DAEFD7CF8",
|
||||
"hide-bangumi-reviews.min.js": "0E8D100A27D523008041BAF95B7809855B505F4C02D4EE32CC62917528E46DBE",
|
||||
@ -157,7 +157,7 @@
|
||||
"image-viewer.min.html": "5F1EEE9FBFD9D2EB2E2F73A57CB3DB2448A60E3D3480A297A7FC88038F60DF21",
|
||||
"index.min.html": "94B83D9EBB9005C1286A7E0759A7683932F8DADA20D07E5E9D8FF867B04D4B95",
|
||||
"key-bindings.min.js": "B896FECF782C96090607EB47B865F19ADE7D269B029D4E61D02E8671618752FD",
|
||||
"keymap.min.js": "39543583160F098ED78BD6A6B91253B0CFED88989822A050B6439B417C398FD1",
|
||||
"keymap.min.js": "50A6190D87FB848FB59428F7C35E03968ADFD31C9524C4F63B2F80CDC4A640A4",
|
||||
"live-pip.min.js": "48FF137D4CF1DEF16395184360981915FF716978455AAD6462C20EDE8A677819",
|
||||
"live-socket.min.js": "8AB690D1979FB64E7BA6126417700C0DD96C0E5C43712543590753B8344996C8",
|
||||
"magic-grid.min.js": "1CDDA7436511423934EBA3E9CCE3CD1BC913C9B8DAFE09C06939935B4F02DD3D",
|
||||
@ -165,6 +165,7 @@
|
||||
"medal-helper.min.css": "BFB833B7389BE97FE818968789BB13F6576B2023D75F20521E0F55567187EF69",
|
||||
"medal-helper.min.html": "5D7057259368BE97DED3375DD904695B245AA2BF338C5E18CB3CF61DD913617C",
|
||||
"medal-helper.min.js": "08D05F7BCF47F676A8A4AABF26E5CCF089511D0F6E846000AAE3C14E6B21C094",
|
||||
"menu-repeat-video.min.js": "A8A8CE04FC9B8B4118A2358488DE1BF5A9F576A24A657861426696C565EC7197",
|
||||
"minimal-home.vue.min.js": "DFA2E873F7948766950084DB5640A1299F63A6E45BAC943A3D1B9CB0E4A2E19F",
|
||||
"minimal-home-search.vue.min.js": "83ACE262CBA7CB68260746B25DD3009D12BA351220F5732BD74EF0B87CBB5D3A",
|
||||
"mini-player-touch-move.min.css": "285AE33BA492FFE4CE0AE4E079C5C0C6661D70C13010FEBE05A1DA133AF7A7B7",
|
||||
@ -178,22 +179,24 @@
|
||||
"old.min.css": "4C8C918BEBE59E9EE19D5E383234767EE2A2F1DB72E86F0C9F9CE01F26DD193C",
|
||||
"old-tweets.min.js": "AAF995BE7F62E1B57C360246F43BCA8B9ADC850DD828190114F6DCADC9A54C06",
|
||||
"online-info-row.vue.min.js": "48D42BADAD3F52BAFE20E2810567ED404A82DA78C8B7ECEB97C0D3E76CC61138",
|
||||
"outer-watchlater.min.css": "B40E94BADA1A9BC96422777B33150780330763098B539921DA05F9D3BA487424",
|
||||
"outer-watchlater.min.js": "D29860BA24F94DDAC33D057741BC140BA8DDA3364145FBC4EC7AF95F8F818C3E",
|
||||
"outer-watchlater.min.css": "D33D11E6267DA0F5CD51F8F1CDBD94AC67E4B6F7DABEA531D6EA6B36504A1C26",
|
||||
"outer-watchlater.min.js": "1661FC4157EEB842FF5266FB78036209C8C84662305EAE9DFD968AEC3F30892B",
|
||||
"override-navbar.min.css": "E5AA612841281169CA367A238FB934F807900A385CE2298B7352FF3CA4623757",
|
||||
"override-navbar.min.js": "0FF50371A02F47EE384515544EB87D34CEE2DB449B9B864B5627A9645F921DAB",
|
||||
"pako-inflate.min.js": "1B89766B342D4A561B0CF7D5A68B2900B6D1772E507EEB1AF56FA7CABE40BCEC",
|
||||
"player-context-menu.min.js": "D84439ABC219CBCDF4C431DAA73E799265485F3C5C07AE57F9A251C7CF967E4A",
|
||||
"player-focus.min.js": "9A290D6749E68A4A88563983413A296BFA9B5C18B978F9CF80799196AEC0F9EE",
|
||||
"player-on-top.min.js": "0D9AA8561E97A6FFCEABDA206B6A57EB87C1B3EF5D0D53EDABA3ED5EFB0DF687",
|
||||
"player-ready.min.js": "1E2CF36AD9B3D506BD89F7E0BBFB5B4DCE2FDAFB8E22FDC988FA5015B739B413",
|
||||
"player-shadow.min.js": "206E787488805F285A6A2A5A542569F52A25BD673E44EE881319932385CC7D61",
|
||||
"player-shadow.min.js": "2B68ADB744DA70E62A7C4E1B659EAA1994F8C167C260051C1115258C0AB67775",
|
||||
"quality-errors.min.js": "A691A407FC4F80C6B2D243CBFADC636FCFFC4DC35B9E305AEF4184AD3ECFC56B",
|
||||
"quick-favorite.min.css": "F14B5ED3F95E944E55B06FEAFF0AC04306146FE9F9223B2C49CE3D507849BE6B",
|
||||
"quick-favorite.min.js": "57263C99EEB16416D25ED6CE5944D818AB7F4136F50082FEFE39FB1863903F9B",
|
||||
"quick-favorite.min.css": "9D97291211AD43AA618A6755F37BB77A1500F6585D3B25E82FD2B6BBC9010540",
|
||||
"quick-favorite.min.js": "4B4004FF561B057A755528D11787AD16D01E78CF77CC74A670D45227785CD6FA",
|
||||
"rank-list.vue.min.js": "23879CFE7674EA072D579BDE665883FC18A536B06094D1C27DC9C8ECD881BF03",
|
||||
"record-live-danmaku.min.js": "CF1C55683CB20688FAA39B9150144F5C907D8150BF42C1AD2729FB44AB06A604",
|
||||
"record-live-danmaku.vue.min.js": "CFBB560D1C9C1D3510A4217E141FEDD4A7F227F3825859BB7F729544A1B86DAC",
|
||||
"remember-video-speed.min.js": "207AB95275A06977CE46AE37C5892FB7823A696C67DC40B4B13EAE82DED330C6",
|
||||
"remove-guide-popup.min.js": "42D2C3F2E71EF511A82CD846591F046B37EF5F70FF66BAEB9A509CB8344297A8",
|
||||
"remove-promotions.min.css": "5B2E7D7F4030150D30635537F2BA547DAC702574BCFBA80F514D53E1FEC88A30",
|
||||
"remove-promotions.min.js": "C45270389F28BEFD963797665DCBC1D4B5D39401932B34834828549A9B33F2E1",
|
||||
"remove-top-mask.min.js": "D0A554FC1C04B082D01585CE944E322F4F4A0CA25F1C856ADD59883B72DDD52C",
|
||||
@ -212,9 +215,9 @@
|
||||
"settings-tooltip.en-US.min.js": "8B559944CF30766F1A86729A0620E3D13D3857FC67273BB1C874A4E0F24B234A",
|
||||
"settings-tooltip.ja-JP.min.js": "B3F99881B1F4DB293DB80BFFA92793E1834EF3096C536E107C52B116037228B9",
|
||||
"settings-tooltip.loader.min.js": "477DE4B69F477D67BCBC72CE33C91986EB2A5620D6F2D1D8367BBC388C5E3E5C",
|
||||
"settings-tooltip.min.css": "3E06D516A95E676B9B0832B16B2522017741BC551D6F541EF3F5A3FBA7761AD3",
|
||||
"settings-tooltip.min.css": "031B4E11744977C54496A3DB0FAB794401DC1FED2E53D9F729DA4218CD98E8D5",
|
||||
"settings-tooltip.min.js": "C7F9A79EB623BF58CB81DE4A9E74FC6C2EDB2613403EFE6D09B36FB460159A13",
|
||||
"settings-tooltip.zh-CN.min.js": "23AD522F4FC083B49FF9864B610C5F63B7EF39D9635151E3AF86E5A18981A7F6",
|
||||
"settings-tooltip.zh-CN.min.js": "A1C425F8C62F6A9986CA4BFFE24B8CAF0547B333EB7265D40166312FB26E6585",
|
||||
"show-cover-before-play.min.css": "E4050D66F8014029270CB5A4DEFDE2F847B095BA9ED4274BFED3E131B737B06D",
|
||||
"show-cover-before-play.min.js": "5614929DD8CEB3B11D184F037235D91B741AD167B08A4F5B7341C6A50A0838FF",
|
||||
"show-dead-video-title.min.js": "5B968442E71F947F70C57C9FDA083935200CBA9B1038131F1587E70A2B723798",
|
||||
@ -244,12 +247,12 @@
|
||||
"touch-move.min.js": "A962710FE0A970E098A1CB1B5C1F63DBA824386F0CE444621555E62CC4542E1A",
|
||||
"touch-navbar.min.js": "A97A7E536A45DE1DF3F7CC174CF95D855FA6034FB9F7D98B818A7363BADDFE48",
|
||||
"touch-player.min.css": "F75D1C72B1EFBE1D3DAB5E93A413796BCBE3FD5131E62C57356CC00E17DB28A5",
|
||||
"touch-player.min.js": "168371E67A6FADDE44DD52A3279E1AAA75BA8CFD86F036CDE02D50D10572FC41",
|
||||
"touch-player.min.js": "FDFCB93C336C5FA9C8EE133B8F7CC697DBAD5803BBBDC3D7651802ED4E0A4FC4",
|
||||
"trending-videos.min.js": "F69B8025B8A78354425534096765E25ED533D5F3809639808EF196E56A4767CD",
|
||||
"trending-videos.vue.min.js": "4BCA996946D6D042183DACD110917463B97DB16A28A61B05B4E6E9473766FCA8",
|
||||
"tweets.min.css": "9015C1F165C91B9205ABBE4E8A3B5FA83DB1EB4B5CF2442846AF61E44FF178A8",
|
||||
"unfold-feeds.min.js": "586FFB95BF24CA22E68ACE4CC4ABF25F5A2CE84C70D657D0CD62E666C4589B5B",
|
||||
"url-params-clean.min.js": "843D56915EE37352925D5F7F73A8521EB2744240A6441022C783A49EC8F1855C",
|
||||
"url-params-clean.min.js": "3A2B2A671609AF278B5A783702BF53C5F6B9554F5C41CFF91F6776C3B83CE53B",
|
||||
"v-checkbox.vue.min.js": "D630823220562A011DDF7164A8D12E775548C6B81907EB6525B3211B822590B1",
|
||||
"v-dropdown.vue.min.js": "3D1D4DC0D8DD06C58C88A530A04DC1D5BEE6690119709B809CD3FA24C8C51C83",
|
||||
"video-card.vue.min.js": "D24618E924A9D039E24B518361B385AB3155188F8B6EEB8CFBB7F9C332422512",
|
||||
|
||||
BIN
min/bundle.zip
BIN
min/bundle.zip
Binary file not shown.
2
min/custom-navbar-search-box.min.js
vendored
2
min/custom-navbar-search-box.min.js
vendored
File diff suppressed because one or more lines are too long
2
min/custom-navbar.min.js
vendored
2
min/custom-navbar.min.js
vendored
File diff suppressed because one or more lines are too long
2
min/dark.min.css
vendored
2
min/dark.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
min/keymap.min.js
vendored
2
min/keymap.min.js
vendored
File diff suppressed because one or more lines are too long
1
min/menu-repeat-video.min.js
vendored
Normal file
1
min/menu-repeat-video.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
(()=>(e,n)=>{(async()=>{if(!await videoCondition()){return}const{addMenuItem:e}=await n.importAsync("player-context-menu");const t=document.createElement("div");t.addEventListener("click",(()=>console.log("click!")));t.innerHTML="test";e(t)})()})();
|
||||
2
min/outer-watchlater.min.css
vendored
2
min/outer-watchlater.min.css
vendored
@ -1 +1 @@
|
||||
.ops .watchlater{margin-right:28px!important;position:relative}.ops .watchlater .tip{position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%);z-index:1000;background:#000d;padding:4px 8px;border-radius:4px;color:#eee;transition:.2s ease-out;opacity:0;pointer-events:none}.watchlater .tip.show{opacity:1;pointer-events:initial}.ops .watchlater>i{display:inline-block;font-style:normal;vertical-align:baseline;text-align:center;text-transform:none;line-height:1;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}.more-ops-list>ul>li:nth-child(2){display:none!important}
|
||||
.ops .watchlater{margin-right:28px!important;position:relative;width:auto!important}@media screen and (max-width:1320px),(max-height:750px){.ops .watchlater{margin-right:max(calc(11 * 1vw - 117.2px),6px)!important}.ops .watchlater .text{display:none}}.ops .watchlater .tip{position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%);z-index:1000;background:#000d;padding:4px 8px;border-radius:4px;color:#eee;transition:.2s ease-out;opacity:0;pointer-events:none}.ops .watchlater .tip.show{opacity:1;pointer-events:initial}.ops .watchlater>i{display:inline-block;font-style:normal;vertical-align:baseline;text-align:center;text-transform:none;line-height:1;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}.more-ops-list>ul>li:nth-child(2){display:none!important}
|
||||
2
min/outer-watchlater.min.js
vendored
2
min/outer-watchlater.min.js
vendored
@ -1 +1 @@
|
||||
(()=>(t,a)=>{(async()=>{if(!document.URL.startsWith("https://www.bilibili.com/video/")||!getUID()){return}const{playerReady:t}=await a.importAsync("player-ready");await t();const e=dq(".video-toolbar .ops .collect");if(!e){return}a.applyStyle("outerWatchlaterStyle");e.insertAdjacentHTML("afterend",`\n<span title='稍后再看' class='watchlater' :class="{on: isInWatchlater}" @click="toggle()">\n<i class='mdi mdi-timetable'></i>\n 稍后再看\n<div class='tip' :class="{show: tipShowing}">{{tipText}}</div>\n</span>\n`.trim());const i=dq(".ops .watchlater");if(!i){return}const s=new Vue({el:i,store:store,data:{aid:unsafeWindow.aid,tipText:"",tipShowing:false,tipHandle:0},computed:{...Vuex.mapState(["watchlaterList"]),isInWatchlater(){return this.watchlaterList.includes(parseInt(this.aid))}},methods:{...Vuex.mapActions(["toggleWatchlater"]),showTip(t){this.tipText=t;this.tipShowing=true;if(this.tipHandle){clearTimeout(this.tipHandle)}this.tipHandle=setTimeout((()=>{this.tipShowing=false}),2e3)},async toggle(){await this.toggleWatchlater(this.aid);this.showTip(this.isInWatchlater?"已添加至稍后再看":"已从稍后再看移除")}}});Observer.videoChange((()=>{s.aid=unsafeWindow.aid}))})();return{unload:()=>{dqa(".ops .watchlater").forEach((t=>t.style.display="none"))},reload:()=>{dqa(".ops .watchlater").forEach((t=>t.style.display="inline-block"))}}})();
|
||||
(()=>(t,a)=>{(async()=>{if(!document.URL.startsWith("https://www.bilibili.com/video/")||!getUID()){return}const{playerReady:t}=await a.importAsync("player-ready");await t();const e=dq(".video-toolbar .ops .collect");if(!e){return}a.applyStyle("outerWatchlaterStyle");e.insertAdjacentHTML("afterend",`\n<span title='稍后再看' class='watchlater' :class="{ on: isInWatchlater }" @click="toggle()">\n<i class='mdi mdi-timetable'></i>\n<span class="text">稍后再看</span>\n<div class='tip' :class="{ show: tipShowing }">{{ tipText }}</div>\n</span>\n`.trim());const i=dq(".ops .watchlater");if(!i){return}const s=new Vue({el:i,store:store,data:{aid:unsafeWindow.aid,tipText:"",tipShowing:false,tipHandle:0},computed:{...Vuex.mapState(["watchlaterList"]),isInWatchlater(){return this.watchlaterList.includes(parseInt(this.aid))}},methods:{...Vuex.mapActions(["toggleWatchlater"]),showTip(t){this.tipText=t;this.tipShowing=true;if(this.tipHandle){clearTimeout(this.tipHandle)}this.tipHandle=setTimeout((()=>{this.tipShowing=false}),2e3)},async toggle(){await this.toggleWatchlater(this.aid);this.showTip(this.isInWatchlater?"已添加至稍后再看":"已从稍后再看移除")}}});Observer.videoChange((()=>{s.aid=unsafeWindow.aid}))})();return{unload:()=>{dqa(".ops .watchlater").forEach((t=>t.style.display="none"))},reload:()=>{dqa(".ops .watchlater").forEach((t=>t.style.display="inline-block"))}}})();
|
||||
1
min/player-context-menu.min.js
vendored
Normal file
1
min/player-context-menu.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
(()=>(e,t)=>{const n=async e=>{const{open:t,close:n}=e;const i=await videoCondition();if(!i){return}const s=await SpinQuery.select(".bilibili-player");if(!s){return}const o=Observer.childList(s,(()=>{const e=dq(".bilibili-player-context-menu-origin");if(e){o.stop();const i=dq(e,"ul");const s={containerElement:e,listElement:i,get itemElements(){return dqa(e,".context-menu-function")},get isOpen(){return e.classList.contains("active")}};Observer.childList(i,(()=>{if(s.isOpen){t===null||t===void 0?void 0:t(s)}else{n===null||n===void 0?void 0:n(s)}}))}}))};const i=async(e,t)=>n({open:t=>{if(t.listElement.contains(e)){return}const n=document.createElement("li");n.classList.add("context-line","context-menu-function");n.setAttribute("data-append","1");const i=document.createElement("a");i.classList.add("context-menu-a","js-action");i.href="javascript:void(0);";i.appendChild(e);n.addEventListener("mouseover",(()=>n.classList.add("hover")));n.addEventListener("mouseout",(()=>n.classList.remove("hover")));n.appendChild(i);t.listElement.appendChild(n)},close:e=>t===null||t===void 0?void 0:t(e)});return{export:{forEachContextMenu:n,addMenuItem:i}}})();
|
||||
2
min/player-shadow.min.js
vendored
2
min/player-shadow.min.js
vendored
@ -1 +1 @@
|
||||
(()=>(e,l)=>{const r=`<style id="player-shadow-style">\n #bilibiliPlayer,\n .bilibili-player.mini-player::before\n {\n box-shadow: 0px 2px 8px 0px var(--theme-color-30) !important;\n }\n body.dark #bilibiliPlayer,\n body.dark .bilibili-player.mini-player::before\n {\n box-shadow: 0px 2px 8px 0px var(--theme-color-20) !important;\n }\n</style>`;l.applyStyleFromText(r);return{reload:()=>l.applyStyleFromText(r),unload:()=>document.getElementById("player-shadow-style").remove()}})();
|
||||
(()=>(i,l)=>{const r=`\n#bilibiliPlayer,\n#bilibili-player.mini-player:before\n{\n box-shadow: 0px 2px 8px 0px var(--theme-color-30) !important;\n}\nbody.dark #bilibiliPlayer,\nbody.dark #bilibili-player.mini-player::before\n{\n box-shadow: 0px 2px 8px 0px var(--theme-color-20) !important;\n}\n`.trim();return l.toggleStyle(r,"player-shadow-style")})();
|
||||
2
min/quick-favorite.min.css
vendored
2
min/quick-favorite.min.css
vendored
@ -1 +1 @@
|
||||
@font-face{font-family:quick-favorite;src:url(data:application/x-font-ttf;base64,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)}.ops .quick-favorite{margin-right:28px!important;position:relative}.ops .quick-favorite>i{font-family:quick-favorite!important;display:inline-block;font-style:normal;text-align:center;text-transform:none;line-height:1;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}.ops .quick-favorite>i:after{content:""}.ops .quick-favorite .lists-tip,.ops .quick-favorite .select-list,.ops .quick-favorite .tip{line-height:normal;position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%);z-index:1000;background:#000d;padding:4px 8px;border-radius:4px;color:#eee;transition:.2s ease-out;opacity:0;pointer-events:none}.ops .quick-favorite .lists-tip.show,.ops .quick-favorite .select-list.show,.ops .quick-favorite .tip.show{opacity:1;pointer-events:initial}.ops .quick-favorite .tip{padding:8px}.ops .quick-favorite .lists-tip{top:calc(100% + 8px + 42px);color:#aaa;font-size:12px;z-index:100}.ops .quick-favorite .select-list{display:flex;align-items:center}.ops .quick-favorite .select-list>*{white-space:nowrap}.ops .quick-favorite .select-list .lists-loading{padding:4px 32px}.ops .quick-favorite .select-list .lists{margin-left:8px}.ops .quick-favorite .select-list .v-dropdown{color:#000}body.dark .ops .quick-favorite .select-list .v-dropdown{color:#eee}.ops .quick-favorite .select-list .v-dropdown .mdi-chevron-down{color:inherit!important;margin:0!important;transition:.2s ease-out;display:flex;align-items:center;justify-content:center;font-size:16pt!important}
|
||||
@font-face{font-family:quick-favorite;src:url(data:application/x-font-ttf;base64,AAEAAAALAIAAAwAwR1NVQiCLJXoAAAE4AAAAVE9TLzJAIEqwAAABjAAAAFZjbWFw6ynBrQAAAewAAAFwZ2x5ZnI4GW4AAANkAAABDGhlYWQYiH0gAAAA4AAAADZoaGVhB4sD6wAAALwAAAAkaG10eAPoAAAAAAHkAAAACGxvY2EAhgAAAAADXAAAAAZtYXhwAQ8AZAAAARgAAAAgbmFtZa2yT/oAAARwAAACXnBvc3QnqNOhAAAG0AAAAD0AAQAAA+gAAAAAA+gAAAAAA6IAAQAAAAAAAAAAAAAAAAAAAAIAAQAAAAEAAOxSVapfDzz1AAsD6AAAAADa5Bw+AAAAANrkHD4AAAAAA6IDvwAAAAgAAgAAAAAAAAABAAAAAgBYAAMAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKADAAPgACREZMVAAObGF0bgAaAAQAAAAAAAAAAQAAAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAEB9AGQAAUAAAJ6ArwAAACMAnoCvAAAAeAAMQECAAACAAUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBmRWQAQOoB6gED6AAAAFoD6AAAAAAAAQAAAAAAAAAAAAAD6AAAAAAABQAAAAMAAAAsAAAABAAAAVQAAQAAAAAATgADAAEAAAAsAAMACgAAAVQABAAiAAAABAAEAAEAAOoB//8AAOoB//8AAAABAAQAAAABAAABBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAcAAAAAAAAAAEAAOoBAADqAQAAAAEAAAAAAIYAAAADAAAAAAOiA78ANwA9AFcAAAEuAS8BLgEvAS4BIgYPAQ4BDwEOAhYfAR4BDwEGHgI/ATYyFzM3LgM/AT4BOwEyFhc3PgEDPgE1BxYTIzc2JisBIgYPAQYWNzMHBh4BMzI/ATYmIwOcBRsRnh8xDEYIHSQgCEMOMB6eERsLCQx1FhAEGQQOHiQPhhtBGwMJFSUXBghHCi0cshUmDAsNCaoNDj8UdmpVBgsLsAYJAkcECQlUHwEFCQQIBdkICQsCgBEWAxgFJRuUEBMTEZMbJgUYAxYiIgx6FDkeqhIiFAIJSRERKgEVIysUwxogExEMDSL+BAkbED8BAR1zCRMHBcQIEAGLBgsFBtUIFgAAAAAQAMYAAQAAAAAAAQAOAAAAAQAAAAAAAgAHAA4AAQAAAAAAAwAOABUAAQAAAAAABAAOACMAAQAAAAAABQALADEAAQAAAAAABgAOADwAAQAAAAAACgArAEoAAQAAAAAACwATAHUAAwABBAkAAQAcAIgAAwABBAkAAgAOAKQAAwABBAkAAwAcALIAAwABBAkABAAcAM4AAwABBAkABQAWAOoAAwABBAkABgAcAQAAAwABBAkACgBWARwAAwABBAkACwAmAXJxdWljay1mYXZvcml0ZVJlZ3VsYXJxdWljay1mYXZvcml0ZXF1aWNrLWZhdm9yaXRlVmVyc2lvbiAxLjBxdWljay1mYXZvcml0ZUdlbmVyYXRlZCBieSBzdmcydHRmIGZyb20gRm9udGVsbG8gcHJvamVjdC5odHRwOi8vZm9udGVsbG8uY29tAHEAdQBpAGMAawAtAGYAYQB2AG8AcgBpAHQAZQBSAGUAZwB1AGwAYQByAHEAdQBpAGMAawAtAGYAYQB2AG8AcgBpAHQAZQBxAHUAaQBjAGsALQBmAGEAdgBvAHIAaQB0AGUAVgBlAHIAcwBpAG8AbgAgADEALgAwAHEAdQBpAGMAawAtAGYAYQB2AG8AcgBpAHQAZQBHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAGgAdAB0AHAAOgAvAC8AZgBvAG4AdABlAGwAbABvAC4AYwBvAG0AAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAgEDABNxdWljay1mYXZvcml0ZV9fXyAxAAAAAAA=)}.ops .quick-favorite{margin-right:28px!important;position:relative;width:auto!important}.ops .quick-favorite .text{display:inline}@media screen and (max-width:1320px),(max-height:750px){.ops .quick-favorite{margin-right:max(calc(11 * 1vw - 117.2px),6px)!important}.ops .quick-favorite .text{display:none}}.ops .quick-favorite>i{font-family:quick-favorite!important;display:inline-block;font-style:normal;text-align:center;text-transform:none;line-height:1;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}.ops .quick-favorite>i:after{content:""}.ops .quick-favorite .lists-tip,.ops .quick-favorite .select-list,.ops .quick-favorite .tip{line-height:normal;position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%);z-index:1000;background:#000d;padding:4px 8px;border-radius:4px;color:#eee;transition:.2s ease-out;opacity:0;pointer-events:none}.ops .quick-favorite .lists-tip.show,.ops .quick-favorite .select-list.show,.ops .quick-favorite .tip.show{opacity:1;pointer-events:initial}.ops .quick-favorite .tip{padding:8px}.ops .quick-favorite .lists-tip{top:calc(100% + 8px + 42px);color:#aaa;font-size:12px;z-index:100}.ops .quick-favorite .select-list{display:flex;align-items:center}.ops .quick-favorite .select-list>*{white-space:nowrap}.ops .quick-favorite .select-list .lists-loading{padding:4px 32px}.ops .quick-favorite .select-list .lists{margin-left:8px}.ops .quick-favorite .select-list .v-dropdown{color:#000}body.dark .ops .quick-favorite .select-list .v-dropdown{color:#eee}.ops .quick-favorite .select-list .v-dropdown .mdi-chevron-down{color:inherit!important;margin:0!important;transition:.2s ease-out;display:flex;align-items:center;justify-content:center;font-size:16pt!important}
|
||||
2
min/quick-favorite.min.js
vendored
2
min/quick-favorite.min.js
vendored
@ -1 +1 @@
|
||||
(()=>(i,t)=>{(async()=>{if(!document.URL.startsWith("https://www.bilibili.com/video/")||!getUID()){return}const{playerReady:e}=await t.importAsync("player-ready");await e();const s=dq(".video-toolbar .ops .collect");if(!s){return}t.applyStyle("quickFavoriteStyle");const a=`\n<span title="快速收藏" @click.left.self="toggle()" @click.right.prevent.self="listShowing = !listShowing" class="quick-favorite" :class="{ on: isFavorite }">\n<i @click.left="toggle()" @click.right.prevent="listShowing = !listShowing"></i>\n<div style="display: inline" @click.left="toggle()" @click.right.prevent="listShowing = !listShowing">快速收藏</div>\n</template>\n<div class="select-list" ref="selectList" :class="{ show: listShowing }">\n 选择快速收藏夹:\n<div v-if="lists.length > 0" class="lists">\n<v-dropdown :items="lists.map(it => it.title)" :value.sync="selectedFavorite"></v-dropdown>\n</div>\n<div class="lists-loading" v-else>加载中...</div>\n</div>\n<div class="lists-tip" :class="{ show: listShowing }">右键点击快速收藏可再次打开</div>\n<div class="tip" :class="{ show: tipShowing }">{{tipText}}</div>\n</span>\n`.trim();if(i.outerWatchlater){const i=await SpinQuery.select(".ops .watchlater");if(i!==null){i.insertAdjacentHTML("beforebegin",a)}else{s.insertAdjacentHTML("afterend",a)}}else{s.insertAdjacentHTML("afterend",a)}const o=dq(".ops .quick-favorite");if(!o){return}const l=new Vue({el:o,store:store,components:{VDropdown:()=>t.importAsync("v-dropdown.vue")},data:{aid:unsafeWindow.aid,favoriteTitle:"",isFavorite:false,tipText:"",tipShowing:false,tipHandle:0,lists:[],selectedFavorite:"",listShowing:false},async created(){this.syncFavoriteState()},watch:{selectedFavorite(t){if(this.lists.length===0){return}const e=this.lists;const s=e.find((i=>i.title===t));if(s){i.quickFavoriteID=s.id;this.syncFavoriteState()}else{console.error("list not found in selectedFavorite(value)")}},async listShowing(i){if(i){document.addEventListener("click",(i=>{const t=this.$el;const e=i.target;if(e!==t&&!t.contains(e)){this.listShowing=false}}));if(this.lists.length===0){try{const i=await Ajax.getJsonWithCredentials(`https://api.bilibili.com/medialist/gateway/base/created?pn=1&ps=100&up_mid=${getUID()}&is_space=0`);if(i.code!==0){throw new Error(`获取收藏夹列表失败: ${i.message}`)}this.lists=_.get(i,"data.list",[])}catch(i){logError(i)}}}}},methods:{async syncFavoriteState(){if(i.quickFavoriteID===0){return}try{const t=await Ajax.getJsonWithCredentials(`https://api.bilibili.com/x/v3/fav/folder/created/list-all?type=2&rid=${this.aid}&up_mid=${getUID()}`);if(t.code!==0){throw new Error(`获取收藏状态失败: ${t.message}`)}const e=_.get(t,"data.list",[]);const s=e.find((t=>t.id===i.quickFavoriteID));if(s===undefined){i.quickFavoriteID=0;return}this.isFavorite=Boolean(s.fav_state);this.selectedFavorite=this.favoriteTitle=s.title}catch(i){logError(i)}},showTip(i){this.tipText=i;this.tipShowing=true;if(this.tipHandle){clearTimeout(this.tipHandle)}this.tipHandle=setTimeout((()=>{this.tipShowing=false}),2e3)},async toggle(){if(i.quickFavoriteID===0){this.listShowing=true;return}const t={rid:this.aid,type:2,add_media_ids:"",del_media_ids:"",csrf:getCsrf()};t[this.isFavorite?"del_media_ids":"add_media_ids"]=i.quickFavoriteID.toString();try{await Ajax.postTextWithCredentials(`https://api.bilibili.com/x/v3/fav/resource/deal`,Object.entries(t).map((([i,t])=>`${i}=${t}`)).join("&"));this.isFavorite=!this.isFavorite;this.showTip(this.isFavorite?`已添加至收藏夹: ${this.favoriteTitle}`:`已移出收藏夹: ${this.favoriteTitle}`)}catch(i){Toast.error(`快速收藏失败: ${i.message}`,"快速收藏");console.error(i)}}}});Observer.videoChange((()=>{l.aid=unsafeWindow.aid;l.syncFavoriteState()}))})();return{unload:()=>{dqa(".ops .quick-favorite").forEach((i=>i.style.display="none"))},reload:()=>{dqa(".ops .quick-favorite").forEach((i=>i.style.display="inline-block"))}}})();
|
||||
(()=>(t,i)=>{(async()=>{if(!document.URL.startsWith("https://www.bilibili.com/video/")||!getUID()){return}const{playerReady:e}=await i.importAsync("player-ready");await e();const s=dq(".video-toolbar .ops .collect");if(!s){return}i.applyStyle("quickFavoriteStyle");const a=`\n<span title="快速收藏" @click.left.self="toggle()" @click.right.prevent.self="listShowing = !listShowing" class="quick-favorite" :class="{ on: isFavorite }">\n<i @click.left="toggle()" @click.right.prevent="listShowing = !listShowing"></i>\n<div class="text" @click.left="toggle()" @click.right.prevent="listShowing = !listShowing">快速收藏</div>\n</template>\n<div class="select-list" ref="selectList" :class="{ show: listShowing }">\n 选择快速收藏夹:\n<div v-if="lists.length > 0" class="lists">\n<v-dropdown :items="lists.map(it => it.title)" :value.sync="selectedFavorite"></v-dropdown>\n</div>\n<div class="lists-loading" v-else>加载中...</div>\n</div>\n<div class="lists-tip" :class="{ show: listShowing }">右键点击快速收藏可再次打开</div>\n<div class="tip" :class="{ show: tipShowing }">{{tipText}}</div>\n</span>\n`.trim();if(t.outerWatchlater){const t=await SpinQuery.select(".ops .watchlater");if(t!==null){t.insertAdjacentHTML("beforebegin",a)}else{s.insertAdjacentHTML("afterend",a)}}else{s.insertAdjacentHTML("afterend",a)}const o=dq(".ops .quick-favorite");if(!o){return}const l=new Vue({el:o,store:store,components:{VDropdown:()=>i.importAsync("v-dropdown.vue")},data:{aid:unsafeWindow.aid,favoriteTitle:"",isFavorite:false,tipText:"",tipShowing:false,tipHandle:0,lists:[],selectedFavorite:"",listShowing:false},async created(){this.syncFavoriteState()},watch:{selectedFavorite(i){if(this.lists.length===0){return}const e=this.lists;const s=e.find((t=>t.title===i));if(s){t.quickFavoriteID=s.id;this.syncFavoriteState()}else{console.error("list not found in selectedFavorite(value)")}},async listShowing(t){if(t){document.addEventListener("click",(t=>{const i=this.$el;const e=t.target;if(e!==i&&!i.contains(e)){this.listShowing=false}}));if(this.lists.length===0){try{const t=await Ajax.getJsonWithCredentials(`https://api.bilibili.com/medialist/gateway/base/created?pn=1&ps=100&up_mid=${getUID()}&is_space=0`);if(t.code!==0){throw new Error(`获取收藏夹列表失败: ${t.message}`)}this.lists=_.get(t,"data.list",[])}catch(t){logError(t)}}}}},methods:{async syncFavoriteState(){if(t.quickFavoriteID===0){return}try{const i=await Ajax.getJsonWithCredentials(`https://api.bilibili.com/x/v3/fav/folder/created/list-all?type=2&rid=${this.aid}&up_mid=${getUID()}`);if(i.code!==0){throw new Error(`获取收藏状态失败: ${i.message}`)}const e=_.get(i,"data.list",[]);const s=e.find((i=>i.id===t.quickFavoriteID));if(s===undefined){t.quickFavoriteID=0;return}this.isFavorite=Boolean(s.fav_state);this.selectedFavorite=this.favoriteTitle=s.title}catch(t){logError(t)}},showTip(t){this.tipText=t;this.tipShowing=true;if(this.tipHandle){clearTimeout(this.tipHandle)}this.tipHandle=setTimeout((()=>{this.tipShowing=false}),2e3)},async toggle(){if(t.quickFavoriteID===0){this.listShowing=true;return}const i={rid:this.aid,type:2,add_media_ids:"",del_media_ids:"",csrf:getCsrf()};i[this.isFavorite?"del_media_ids":"add_media_ids"]=t.quickFavoriteID.toString();try{await Ajax.postTextWithCredentials(`https://api.bilibili.com/x/v3/fav/resource/deal`,Object.entries(i).map((([t,i])=>`${t}=${i}`)).join("&"));this.isFavorite=!this.isFavorite;this.showTip(this.isFavorite?`已添加至收藏夹: ${this.favoriteTitle}`:`已移出收藏夹: ${this.favoriteTitle}`)}catch(t){Toast.error(`快速收藏失败: ${t.message}`,"快速收藏");console.error(t)}}}});Observer.videoChange((()=>{l.aid=unsafeWindow.aid;l.syncFavoriteState()}))})();return{unload:()=>{dqa(".ops .quick-favorite").forEach((t=>t.style.display="none"))},reload:()=>{dqa(".ops .quick-favorite").forEach((t=>t.style.display="inline-block"))}}})();
|
||||
1
min/remove-guide-popup.min.js
vendored
Normal file
1
min/remove-guide-popup.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
(()=>(e,i)=>i.toggleStyle(`\n .bilibili-player-video-popup-guide-attention { display: none !important; }\n`.trim(),"remove-guide-popup-style"))();
|
||||
2
min/settings-tooltip.min.css
vendored
2
min/settings-tooltip.min.css
vendored
@ -1 +1 @@
|
||||
.gui-settings-tooltip{position:fixed;left:440px;color:#fff;background:#0008;border:1px solid #333;padding:14px 14px 8px;font-size:12pt;top:50%;transform:translateY(-50%);transition:.2s ease-out;opacity:0;min-width:100%;max-height:90%;line-height:1.8;white-space:pre-wrap;pointer-events:none;user-select:text;border-radius:var(--large-corner-radius);overflow:auto;scrollbar-width:none!important}.gui-settings-tooltip::-webkit-scrollbar{height:0!important;width:0!important}.gui-settings-tooltip.show{pointer-events:initial;opacity:1}.gui-settings-box:not(.opened) .gui-settings-tooltip,.gui-settings-tooltip:empty{pointer-events:none;opacity:0}.gui-settings-tooltip .tooltip-title{font-weight:700;font-size:large;line-height:normal;padding-bottom:12px;margin-bottom:6px;border-bottom:1px solid #333}.gui-settings-tooltip span{display:inline-flex;padding:4px;margin:0 2px;line-height:1.2;background-color:#222;border:1px solid #333;border-radius:4px}.gui-settings-tooltip a,.gui-settings-tooltip a:active,.gui-settings-tooltip a:hover{color:var(--theme-color)}
|
||||
.gui-settings-tooltip{position:fixed;left:440px;color:#fff;background:#0008;border:1px solid #333;padding:14px 14px 8px;font-size:12pt;top:50%;transform:translateY(-50%);transition:.2s ease-out;min-width:100%;max-height:90%;line-height:1.8;white-space:pre-wrap;user-select:text;border-radius:var(--large-corner-radius);overflow:auto;scrollbar-width:none!important}.gui-settings-tooltip::-webkit-scrollbar{height:0!important;width:0!important}.gui-settings-box:not(.opened) .gui-settings-tooltip,.gui-settings-tooltip:empty{pointer-events:none;opacity:0}.gui-settings-tooltip .tooltip-title{font-weight:700;font-size:large;line-height:normal;padding-bottom:12px;margin-bottom:6px;border-bottom:1px solid #333}.gui-settings-tooltip span{display:inline-flex;padding:4px;margin:0 2px;line-height:1.2;background-color:#222;border:1px solid #333;border-radius:4px}.gui-settings-tooltip a,.gui-settings-tooltip a:active,.gui-settings-tooltip a:hover{color:var(--theme-color)}
|
||||
2
min/settings-tooltip.zh-CN.min.js
vendored
2
min/settings-tooltip.zh-CN.min.js
vendored
File diff suppressed because one or more lines are too long
2
min/touch-player.min.js
vendored
2
min/touch-player.min.js
vendored
File diff suppressed because one or more lines are too long
2
min/url-params-clean.min.js
vendored
2
min/url-params-clean.min.js
vendored
@ -1 +1 @@
|
||||
(()=>(t,e)=>{const o=["spm_id_from","from_source","from_spmid","from","seid","share_source","share_medium","share_plat","share_tag","bbid","ts","timestamp","unique_k","rt","tdsourcetag","accept_quality","broadcast_type","current_qn","current_quality","playurl_h264","playurl_h265","quality_description","network","network_status","platform_network_status","p2p_type","referfrom","visit_id","bsource"];const s=[{match:/\/\/www\.bilibili\.com\/audio\/(au[\d]+|mycollection)/,param:"type"},{match:/\/\/live\.bilibili\.com\//,param:"session_id"},{match:/\/\/www\.bilibili\.com\/bangumi\//,param:"theme"}];const i=[/game\.bilibili\.com\/fgo/];const r=t=>t;const a=["videocard_series"];const c=()=>{const t=location.search.substring(1).split("&");if(t.some((t=>a.some((e=>t.includes(e)))))){return}const e=t.filter((t=>{if(o.some((e=>t.startsWith(`${e}=`)))){return false}if(s.some((({match:e,param:o})=>document.URL.match(e)&&t.startsWith(`${o}=`)))){return false}return true}));const i=e.join("&");const c=r(document.URL.replace(location.search,""));const n=i?"?"+i:"";const m=c+n;if(m!==document.URL){console.log("[URL params clean]",document.URL,m);history.replaceState({},document.title,m)}};fullyLoaded((()=>{if(document.contentType==="text/html"){c();Observer.videoChange((()=>c()))}}))})();
|
||||
(()=>(t,e)=>{const o=["spm_id_from","from_source","from_spmid","from","seid","share_source","share_medium","share_plat","share_tag","bbid","ts","timestamp","unique_k","rt","tdsourcetag","accept_quality","broadcast_type","current_qn","current_quality","playurl_h264","playurl_h265","quality_description","network","network_status","platform_network_status","p2p_type","referfrom","visit_id","bsource","spm","hotRank"];const i=[{match:/\/\/www\.bilibili\.com\/audio\/(au[\d]+|mycollection)/,param:"type"},{match:/\/\/live\.bilibili\.com\//,param:"session_id"},{match:/\/\/www\.bilibili\.com\/bangumi\//,param:"theme"},{match:/\/\/t\.bilibili\.com\/[\d]+/,param:"type"}];const s=[/game\.bilibili\.com\/fgo/];const a=t=>t;const r=["videocard_series"];const c=()=>{const t=location.search.substring(1).split("&");if(t.some((t=>r.some((e=>t.includes(e)))))){return}const e=t.filter((t=>{if(o.some((e=>t.startsWith(`${e}=`)))){return false}if(i.some((({match:e,param:o})=>document.URL.match(e)&&t.startsWith(`${o}=`)))){return false}return true}));const s=e.join("&");const c=a(document.URL.replace(location.search,""));const m=s?"?"+s:"";const n=c+m;if(n!==document.URL){console.log("[URL params clean]",document.URL,n);history.replaceState({},document.title,n)}};fullyLoaded((()=>{if(document.contentType==="text/html"){c();Observer.videoChange((()=>c()))}}))})();
|
||||
@ -1,6 +1,6 @@
|
||||
// ==UserScript==
|
||||
// @name Bilibili Evolved (Preview)
|
||||
// @version 1.11.14
|
||||
// @version 1.11.15
|
||||
// @description Bilibili Evolved 的预览版, 可以抢先体验新功能.
|
||||
// @author Grant Howard, Coulomb-G
|
||||
// @copyright 2021, Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)
|
||||
@ -126,7 +126,7 @@ window.EventTarget = class EventTarget {
|
||||
}
|
||||
// Safari EventTarget polyfill end
|
||||
|
||||
import { logError, raiseEvent, loadLazyPanel, contentLoaded, fixed, isOffline, getUID, scriptVersion, getCsrf, formatCount, escapeFilename } from './utils'
|
||||
import { logError, raiseEvent, loadLazyPanel, loadDanmakuSettingsPanel, loadLazyPlayerSettingsPanel, loadSubtitleSettingsPanel, contentLoaded, fixed, isOffline, getUID, scriptVersion, getCsrf, formatCount, escapeFilename, fullyLoaded, formatDuration, formatFileSize, getDpiSourceSet, videoCondition, matchPattern, formData, retrieveImageUrl, isTyping, getAid } from './utils'
|
||||
import { settings, loadSettings, settingsChangeHandlers } from './settings'
|
||||
import { Ajax, setupAjaxHook } from './ajax'
|
||||
import { loadResources } from './resource-loader'
|
||||
@ -253,7 +253,11 @@ import { store } from './store'
|
||||
logError,
|
||||
raiseEvent,
|
||||
loadLazyPanel,
|
||||
loadLazyPlayerSettingsPanel,
|
||||
loadDanmakuSettingsPanel,
|
||||
loadSubtitleSettingsPanel,
|
||||
contentLoaded,
|
||||
fullyLoaded,
|
||||
fixed,
|
||||
settings,
|
||||
settingsChangeHandlers,
|
||||
@ -278,6 +282,12 @@ import { store } from './store'
|
||||
getCsrf,
|
||||
formatCount,
|
||||
escapeFilename,
|
||||
videoCondition,
|
||||
matchPattern,
|
||||
formData,
|
||||
retrieveImageUrl,
|
||||
isTyping,
|
||||
getAid,
|
||||
installStyle,
|
||||
uninstallStyle,
|
||||
toggleStyle,
|
||||
|
||||
@ -985,6 +985,19 @@ Resource.manifest = {
|
||||
displayNames: {
|
||||
extendVideoSpeed: '扩展视频倍数菜单'
|
||||
}
|
||||
}
|
||||
},
|
||||
menuRepeatVideo: {
|
||||
path: 'menu-repeat-video.min.js',
|
||||
displayNames: {
|
||||
menuRepeatVideo: '视频右键菜单循环播放',
|
||||
},
|
||||
},
|
||||
removeGuidePopup: {
|
||||
path: 'remove-guide-popup.min.js',
|
||||
displayNames: {
|
||||
removeGuidePopup: '删除视频弹窗',
|
||||
},
|
||||
reloadable: true,
|
||||
},
|
||||
}
|
||||
export const resourceManifest = Resource.manifest
|
||||
|
||||
@ -251,6 +251,8 @@ export const settings = {
|
||||
extendVideoSpeedList: [2.5, 3],
|
||||
customKeyBindings: {},
|
||||
alwaysShowDuration: false,
|
||||
menuRepeatVideo: false,
|
||||
removeGuidePopup: true,
|
||||
cache: {},
|
||||
}
|
||||
const fixedSettings = {
|
||||
|
||||
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
@ -529,6 +529,8 @@ declare global {
|
||||
extendVideoSpeedList: number[],
|
||||
customKeyBindings: { [actionName: string]: string },
|
||||
alwaysShowDuration: boolean,
|
||||
menuRepeatVideo: boolean,
|
||||
removeGuidePopup: boolean,
|
||||
}
|
||||
const GM_info: MonkeyInfo
|
||||
function GM_xmlhttpRequest(details: MonkeyXhrDetails): { abort: () => void }
|
||||
|
||||
@ -29,7 +29,11 @@ const loadSettings = () => {
|
||||
addSettingsListener('customNavbarBlurOpacity', value => {
|
||||
document.documentElement.style.setProperty('--navbar-blur-opacity', value)
|
||||
})
|
||||
if (!document.URL.startsWith('https://space.bilibili.com')) {
|
||||
const fixedNotSupported = [
|
||||
// 'https://search.bilibili.com/all',
|
||||
'https://space.bilibili.com',
|
||||
]
|
||||
if (!fixedNotSupported.some(url => document.URL.startsWith(url))) {
|
||||
addSettingsListener('customNavbarGlobalFixed', value => {
|
||||
document.body.classList.toggle('fixed-navbar', value)
|
||||
}, true)
|
||||
|
||||
@ -3,46 +3,52 @@ interface SuggestItem {
|
||||
value: string
|
||||
html: string
|
||||
}
|
||||
const originalHistory = new class {
|
||||
getAll(): SearchHistoryItem[] {
|
||||
const history = localStorage.getItem('search_history')
|
||||
if (!history) {
|
||||
return []
|
||||
}
|
||||
return (JSON.parse(history) as any[]).map(it => {
|
||||
return {
|
||||
keyword: it.value,
|
||||
date: new Date(it.timestamp).toJSON(),
|
||||
count: 1,
|
||||
}
|
||||
})
|
||||
interface HistoryItem {
|
||||
value: string
|
||||
isHistory: number
|
||||
timestamp: number
|
||||
}
|
||||
const SearchHistoryKey = 'be_search_history'
|
||||
const SearchHistoryMaxItems = 10
|
||||
const getHistoryItems = () => {
|
||||
const historyText = localStorage.getItem(SearchHistoryKey)
|
||||
const historyItems: HistoryItem[] = historyText ? JSON.parse(historyText) : []
|
||||
return historyItems
|
||||
}
|
||||
const clearHistoryItems = () => localStorage.setItem(SearchHistoryKey, '[]')
|
||||
const addHistoryItem = (item: HistoryItem) => {
|
||||
localStorage.setItem(SearchHistoryKey, JSON.stringify(
|
||||
_.sortBy(_.uniqBy(getHistoryItems().concat(item), h => h.value), h => h.timestamp)
|
||||
.reverse()
|
||||
.slice(0, SearchHistoryMaxItems)
|
||||
))
|
||||
}
|
||||
const deleteHistoryItem = (keyword: string) => {
|
||||
const items = getHistoryItems()
|
||||
const index = items.findIndex(it => it.value === keyword)
|
||||
if (index !== -1) {
|
||||
items.splice(index, 1)
|
||||
localStorage.setItem(SearchHistoryKey, JSON.stringify(items))
|
||||
}
|
||||
saveAll(items: SearchHistoryItem[]) {
|
||||
localStorage.setItem('search_history', JSON.stringify(items))
|
||||
}
|
||||
clear() {
|
||||
localStorage.setItem('search_history', '[]')
|
||||
}
|
||||
merge(items: SearchHistoryItem[]) {
|
||||
const originalItems = this.getAll()
|
||||
return _.uniqBy(items.concat(originalItems), it => it.keyword).slice(0, 10)
|
||||
}
|
||||
add(item: SearchHistoryItem) {
|
||||
const items = this.getAll()
|
||||
const existingItem = items.find(it => it.keyword === item.keyword)
|
||||
if (existingItem) {
|
||||
Object.assign(existingItem, item)
|
||||
} else {
|
||||
items.push(item)
|
||||
}
|
||||
this.saveAll(items)
|
||||
}
|
||||
remove(item: SearchHistoryItem) {
|
||||
const items = this.getAll()
|
||||
const index = items.findIndex(it => it.keyword === item.keyword)
|
||||
if (index > -1) {
|
||||
items.splice(index, 1)
|
||||
this.saveAll(items)
|
||||
}
|
||||
const migrateOldHistory = () => {
|
||||
if (settings.searchHistory.length > 0) {
|
||||
try {
|
||||
const currentHistory = getHistoryItems()
|
||||
const oldHistory: HistoryItem[] = settings.searchHistory.map(it => {
|
||||
return {
|
||||
value: it.keyword,
|
||||
isHistory: 1,
|
||||
timestamp: Number(new Date(it.date)),
|
||||
}
|
||||
})
|
||||
const newHistory = _.sortBy(_.uniqBy(oldHistory.concat(currentHistory), h => h.value), h => h.timestamp)
|
||||
.reverse()
|
||||
.slice(0, SearchHistoryMaxItems)
|
||||
localStorage.setItem(SearchHistoryKey, JSON.stringify(newHistory))
|
||||
settings.searchHistory = []
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -134,6 +140,11 @@ export class SearchBox extends NavbarComponent {
|
||||
async init() {
|
||||
const form = await SpinQuery.select('#custom-navbar-search') as HTMLFormElement
|
||||
const keywordInput = form.querySelector("input[name='keyword']") as HTMLInputElement
|
||||
migrateOldHistory()
|
||||
if (document.URL.startsWith('https://search.bilibili.com/all')) {
|
||||
const keyword = window.location.search.match(/keyword=([^&]+)/)?.[1] || ''
|
||||
keywordInput.value = decodeURIComponent(keyword)
|
||||
}
|
||||
form.addEventListener('submit', e => {
|
||||
if (keywordInput.value === '') {
|
||||
if (!settings.hideTopSearch) {
|
||||
@ -150,21 +161,17 @@ export class SearchBox extends NavbarComponent {
|
||||
e.preventDefault()
|
||||
return false
|
||||
}
|
||||
const historyItem = settings.searchHistory.find(item => item.keyword === keywordInput.value)
|
||||
const historyItem = getHistoryItems().find(item => item.value === keywordInput.value)
|
||||
if (historyItem) {
|
||||
historyItem.count++
|
||||
historyItem.date = new Date().toJSON()
|
||||
// originalHistory.add(historyItem)
|
||||
historyItem.timestamp = Number(new Date())
|
||||
} else {
|
||||
const newItem = {
|
||||
count: 1,
|
||||
keyword: keywordInput.value,
|
||||
date: new Date().toJSON(),
|
||||
const newItem: HistoryItem = {
|
||||
value: keywordInput.value,
|
||||
isHistory: 1,
|
||||
timestamp: Number(new Date()),
|
||||
}
|
||||
settings.searchHistory.unshift(newItem)
|
||||
// originalHistory.add(newItem)
|
||||
addHistoryItem(newItem)
|
||||
}
|
||||
settings.searchHistory = settings.searchHistory.slice(0, 10) // save history
|
||||
return true
|
||||
})
|
||||
if (!settings.hideTopSearch) {
|
||||
@ -228,15 +235,11 @@ export class SearchBox extends NavbarComponent {
|
||||
if (keywordInput.value !== '') {
|
||||
keywordInput.value = ''
|
||||
}
|
||||
const historyIndex = settings.searchHistory.findIndex(it => it.keyword === item.value)
|
||||
const [historyItem] = settings.searchHistory.splice(historyIndex, 1)
|
||||
// originalHistory.remove(historyItem)
|
||||
settings.searchHistory = settings.searchHistory
|
||||
deleteHistoryItem(item.value)
|
||||
this.items.splice(index, 1)
|
||||
},
|
||||
clearSearchHistory() {
|
||||
// originalHistory.clear()
|
||||
settings.searchHistory = []
|
||||
clearHistoryItems()
|
||||
this.items = []
|
||||
}
|
||||
},
|
||||
@ -247,19 +250,14 @@ export class SearchBox extends NavbarComponent {
|
||||
searchList.isHistory = text === ''
|
||||
const idJump = getIdJump(text)
|
||||
if (searchList.isHistory) {
|
||||
// searchList.items = originalHistory.merge(settings.searchHistory)
|
||||
searchList.items = settings.searchHistory
|
||||
.sort((a, b) => {
|
||||
const aDate = a.date ? new Date(a.date) : new Date(0)
|
||||
const bDate = b.date ? new Date(b.date) : new Date(0)
|
||||
return Number(bDate) - Number(aDate)
|
||||
})
|
||||
searchList.items = getHistoryItems()
|
||||
.sort((a, b) => b.timestamp - a.timestamp)
|
||||
.map(item => {
|
||||
return {
|
||||
value: item.keyword,
|
||||
html: item.keyword,
|
||||
value: item.value,
|
||||
html: item.value,
|
||||
}
|
||||
}).slice(0, 10)
|
||||
}).slice(0, SearchHistoryMaxItems)
|
||||
} else if (idJump.success) {
|
||||
searchList.items = []
|
||||
const url = idJump.aid ? `https://api.bilibili.com/x/web-interface/view?aid=${idJump.aid}` : `https://api.bilibili.com/x/web-interface/view?bvid=${idJump.bvid}`
|
||||
@ -294,6 +292,10 @@ export class SearchBox extends NavbarComponent {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (location.host === 'search.bilibili.com') {
|
||||
// s.search.bilibili.com 禁止 search.bilibili.com 访问, 迷惑
|
||||
return
|
||||
}
|
||||
const url = `https://s.search.bilibili.com/main/suggest?func=suggest&suggest_type=accurate&sub_type=tag&main_ver=v1&highlight=&userid=${getUID()}&bangumi_acc_num=1&special_acc_num=1&topic_acc_num=1&upuser_acc_num=3&tag_num=10&special_num=10&bangumi_num=10&upuser_num=3&term=${text}`
|
||||
lastQueuedRequest = url
|
||||
const json = await Ajax.getJson(url)
|
||||
|
||||
@ -1673,6 +1673,7 @@ div.drag-bar,
|
||||
{
|
||||
box-shadow: 0px 1px 10px 0 #0003 !important;
|
||||
}
|
||||
#bilibili-player.mini-player::before,
|
||||
.bilibili-player.mini-player::before
|
||||
{
|
||||
box-shadow: 0 4px 8px 0 #0004 !important;
|
||||
|
||||
@ -957,8 +957,13 @@ html {
|
||||
.article-action .more .more-ops-list ul li:hover {
|
||||
@include theme-color();
|
||||
}
|
||||
.bilibili-player-context-menu-container ul > li a {
|
||||
@include color("e");
|
||||
.bilibili-player-context-menu-container ul > li {
|
||||
a {
|
||||
@include color("e");
|
||||
&:hover {
|
||||
@include background-color();
|
||||
}
|
||||
}
|
||||
}
|
||||
.coin-dialog-mask .like-checkbox {
|
||||
@include color("e");
|
||||
|
||||
@ -61,3 +61,6 @@
|
||||
@include background-color("4");
|
||||
}
|
||||
}
|
||||
.filter-wrap .filter-wrap_bottom {
|
||||
@include background-color("4");
|
||||
}
|
||||
|
||||
@ -116,8 +116,6 @@ a.bp_box_bot_click,
|
||||
.paging-box-big .next,
|
||||
.paging-box-big .prev,
|
||||
.bilibili-player-ending-panel-box-functions .bui-button.bui-button-disabled,
|
||||
.bilibili-player-context-menu-container.black ul > li.hover,
|
||||
.bilibili-player-context-menu-container.black ul > li a:hover,
|
||||
.intimacy-bar,
|
||||
.tab-box,
|
||||
.live-module .tab-item .r-item .number,
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
const style = `<style id="player-shadow-style">
|
||||
#bilibiliPlayer,
|
||||
.bilibili-player.mini-player::before
|
||||
{
|
||||
box-shadow: 0px 2px 8px 0px var(--theme-color-30) !important;
|
||||
}
|
||||
body.dark #bilibiliPlayer,
|
||||
body.dark .bilibili-player.mini-player::before
|
||||
{
|
||||
box-shadow: 0px 2px 8px 0px var(--theme-color-20) !important;
|
||||
}
|
||||
</style>`;
|
||||
resources.applyStyleFromText(style);
|
||||
export default {
|
||||
reload: () => resources.applyStyleFromText(style),
|
||||
unload: () => document.getElementById("player-shadow-style").remove(),
|
||||
};
|
||||
13
src/style/player-shadow.ts
Normal file
13
src/style/player-shadow.ts
Normal file
@ -0,0 +1,13 @@
|
||||
const style = `
|
||||
#bilibiliPlayer,
|
||||
#bilibili-player.mini-player:before
|
||||
{
|
||||
box-shadow: 0px 2px 8px 0px var(--theme-color-30) !important;
|
||||
}
|
||||
body.dark #bilibiliPlayer,
|
||||
body.dark #bilibili-player.mini-player::before
|
||||
{
|
||||
box-shadow: 0px 2px 8px 0px var(--theme-color-20) !important;
|
||||
}
|
||||
`.trim()
|
||||
export default resources.toggleStyle(style, 'player-shadow-style')
|
||||
@ -226,47 +226,46 @@ class VideoShot {
|
||||
this.cidData = null
|
||||
this.supportWebp = VideoShot.supportWebp
|
||||
}
|
||||
getVideoshot (currentTime, done) {
|
||||
async getStyle(currentTime) {
|
||||
const data = await this.cidData
|
||||
const indexData = data.index
|
||||
let shotIndex = 0
|
||||
for (let index = 0; index < indexData.length - 2; index++) {
|
||||
if (currentTime >= indexData[index] &&
|
||||
currentTime < indexData[index + 1]) {
|
||||
shotIndex = index
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let imageData = data.image
|
||||
if (!imageData) {
|
||||
return {}
|
||||
}
|
||||
if (this.supportWebp) {
|
||||
imageData = imageData.map(url => url.replace('.jpg', '.jpg@.webp'))
|
||||
}
|
||||
const xLength = parseInt(data.pv_x_len) || 10
|
||||
const yLength = parseInt(data.pv_y_len) || 10
|
||||
const xSize = parseInt(data.pv_x_size) || 160
|
||||
const ySize = parseInt(data.pv_y_size) || 90
|
||||
const x = -(shotIndex % 100 % xLength) * xSize
|
||||
const y = -Math.floor(shotIndex % 100 / yLength) * ySize
|
||||
return {
|
||||
width: xSize,
|
||||
height: ySize,
|
||||
backgroundImage: `url(${imageData[Math.floor(shotIndex / 100)]})`,
|
||||
backgroundPosition: `${x}px ${y}px`
|
||||
}
|
||||
}
|
||||
async getVideoshot (currentTime) {
|
||||
if (!(this.aid && this.cid)) {
|
||||
return
|
||||
return {}
|
||||
}
|
||||
if (!this.cidData) {
|
||||
Ajax.getText(`https://api.bilibili.com/x/player/videoshot?aid=${this.aid}&cid=${this.cid}&index=1`).then(response => {
|
||||
this.cidData = JSON.parse(response).data
|
||||
this.getVideoshot(currentTime, done)
|
||||
})
|
||||
} else {
|
||||
const data = this.cidData
|
||||
const indexData = data.index
|
||||
let shotIndex = 0
|
||||
for (let index = 0; index < indexData.length - 2; index++) {
|
||||
if (currentTime >= indexData[index] &&
|
||||
currentTime < indexData[index + 1]) {
|
||||
shotIndex = index
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let imageData = data.image
|
||||
if (imageData === null) {
|
||||
return
|
||||
}
|
||||
if (this.supportWebp) {
|
||||
imageData = imageData.map(url => url.replace('.jpg', '.jpg@.webp'))
|
||||
}
|
||||
const xLength = parseInt(data.pv_x_len) || 10
|
||||
const yLength = parseInt(data.pv_y_len) || 10
|
||||
const xSize = parseInt(data.pv_x_size) || 160
|
||||
const ySize = parseInt(data.pv_y_size) || 90
|
||||
const x = -(shotIndex % 100 % xLength) * xSize
|
||||
const y = -Math.floor(shotIndex % 100 / yLength) * ySize
|
||||
done({
|
||||
width: xSize,
|
||||
height: ySize,
|
||||
backgroundImage: `url(${imageData[Math.floor(shotIndex / 100)]})`,
|
||||
backgroundPosition: `${x}px ${y}px`
|
||||
})
|
||||
this.cidData = Ajax.getText(`https://api.bilibili.com/x/player/videoshot?aid=${this.aid}&cid=${this.cid}&index=1`).then(response => JSON.parse(response).data)
|
||||
}
|
||||
return this.getStyle(currentTime)
|
||||
}
|
||||
static get supportWebp () {
|
||||
try {
|
||||
@ -381,7 +380,7 @@ function setupTouchPlayer (player) {
|
||||
text.querySelector('.touch-speed').innerHTML = `${speed}速`
|
||||
text.querySelector('.touch-info').innerHTML = `进度: ${sec > 0 ? '+' : '-'}${secondsToTime(change)}`
|
||||
text.querySelector('.touch-result').innerHTML = result
|
||||
videoshot.getVideoshot(finalTime, style => $('.videoshot').css(style))
|
||||
videoshot.getVideoshot(finalTime).then(style => $('.videoshot').css(style))
|
||||
$('.touch-progress').css('width', `${finalPercent}%`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +76,7 @@
|
||||
<checkbox indent="0" key="doubleClickFullscreen" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="showCoverBeforePlay" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="seoJump" dependencies=""></checkbox>
|
||||
<checkbox indent="0" key="removeGuidePopup" dependencies=""></checkbox>
|
||||
<category icon="style">样式</category>
|
||||
<li class="indent-0 folded">
|
||||
<label class="gui-settings-textbox-container">
|
||||
@ -196,5 +197,5 @@
|
||||
<a class="release-notes" target="_blank" href="https://github.com/the1812/Bilibili-Evolved/releases">更新日志</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gui-settings-tooltip show"></div>
|
||||
<div class="gui-settings-tooltip"></div>
|
||||
</div>
|
||||
@ -10,21 +10,15 @@
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
transition: all 0.2s ease-out;
|
||||
opacity: 0;
|
||||
min-width: 100%;
|
||||
max-height: 90%;
|
||||
line-height: 1.8;
|
||||
white-space: pre-wrap;
|
||||
pointer-events: none;
|
||||
user-select: text;
|
||||
border-radius: var(--large-corner-radius);
|
||||
overflow: auto;
|
||||
@include no-scrollbar();
|
||||
|
||||
&.show {
|
||||
pointer-events: initial;
|
||||
opacity: 1;
|
||||
}
|
||||
.gui-settings-box:not(.opened) &,
|
||||
&:empty {
|
||||
pointer-events: none;
|
||||
|
||||
@ -20,7 +20,13 @@ export const toolTips = new Map<keyof BilibiliEvolvedSettings, string>([
|
||||
["autoContinue", /*html*/`播放视频时如果检测到历史记录信息(<span>上次看到...</span>消息), 则自动跳转到相应的时间播放.`],
|
||||
["airborne", /*html*/`当弹幕出现视频时间点时用下划线标记,点击即可空降到相应时间点.`],
|
||||
["skipChargeList", /*html*/`自动跳过视频结尾的充电鸣谢.`],
|
||||
["framePlayback", /*html*/`在播放器的时间右边增加两个按钮, 用于<span>较</span>精细调整视频时间. 支持键盘快捷键<kbd>Shift</kbd>+<kbd>←</kbd>/<kbd>→</kbd>. (旧版播放器只能用键盘快捷键, 不会显示按钮)`],
|
||||
["framePlayback", /*html*/`在播放器的时间右边增加两个按钮, 用于<span>较</span>精细调整视频时间.
|
||||
注: 视频的实际播放帧率跟视频本身的帧率和显示器的刷新率有关, 很难计算一个精准的数值, 部分视频仍然会有暂停不到那种一闪而过的图的情况.
|
||||
|
||||
逐帧调整的精确度固定为:
|
||||
- <span>1080P60</span>/<span>720P60</span>: 1001 / 60000 秒 (59.94006 fps)
|
||||
- <span>其他清晰度</span>: 1001 / 30000 秒 (29.97003 fps)
|
||||
`],
|
||||
["playerFocus", /*html*/`进入视频/番剧页面时, 自动定位到播放器.`],
|
||||
["playerFocusOffset", /*html*/`定位时的竖直偏移量, 单位为像素(px).`],
|
||||
["customStyleColor", /*html*/`设定顶栏(自定义顶栏启用时)和夜间模式使用的主题色, 可以点击颜色预览的圆圈打开色板, 其中含有预定义的16种主题色, 也可以在右侧的文本框直接输入任何有效的16进制颜色值(<span>#rrggbb</span>或<span>#rgb</span>).`],
|
||||
@ -117,8 +123,9 @@ export const toolTips = new Map<keyof BilibiliEvolvedSettings, string>([
|
||||
["hideBanner", /*html*/`隐藏首页顶部横幅.`],
|
||||
["allowJumpContinue", /*html*/`当历史记录的集数与当前打开的不一致时, 仍然自动跳转.`],
|
||||
["hideBangumiReviews", /*html*/`隐藏番剧播放页面里的点评板块.`],
|
||||
["videoScreenshot", /*html*/`启用视频快速截图, 将在播放器的时间右边增加一个截图按钮. 支持键盘快捷键<kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd>. (旧版播放器只能用键盘快捷键, 不会显示按钮)
|
||||
如果弹幕渲染类型选择了Canvas, 则可以再按住<kbd>Shift</kbd>键来截取带弹幕的截图. 也就是鼠标操作为"按住<kbd>Shift</kbd>点击截图按钮", 键盘操作为"<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd>".`],
|
||||
["videoScreenshot", /*html*/`在播放器的时间右边增加截图按钮, 点击可以截取视频画面, 不会包含暂停标志和弹幕. 截取的图片将在网页右侧显示(非全屏或网页全屏模式), 可以单独保存或丢弃, 也可以截取一定数量后一次性保存.
|
||||
|
||||
如果弹幕渲染类型选择了Canvas, 则可以再按住 <kbd>Shift</kbd> 键点击按钮来截取带弹幕的截图.`],
|
||||
["filenameFormat", /*html*/`自定义文件命名格式, 作用于<span>下载弹幕</span>, <span>下载视频</span>, <span>视频截图</span>, <span>查看封面</span>.
|
||||
可以使用的变量有:
|
||||
- <span>title</span>: 视频标题/直播间标题
|
||||
@ -156,12 +163,14 @@ export const toolTips = new Map<keyof BilibiliEvolvedSettings, string>([
|
||||
- <kbd>\`</kbd> 打开播放器菜单
|
||||
- <kbd>Shift + j</kbd> 倒退85秒
|
||||
- <kbd>Shift + w</kbd> 稍后再看
|
||||
- <kbd>Shift + s</kbd> 快速收藏
|
||||
- <kbd>Shift + s</kbd> 快速收藏 (需开启快速收藏功能)
|
||||
- <kbd>Shift + ↑/↓</kbd> / <kbd>Shift + ,/.</kbd> 播放速度调整
|
||||
- <kbd>Shift + /</kbd> 重置播放速度(将播放速度设为 1.0x)
|
||||
- <kbd>Ctrl + Shift + /</kbd> 切换到上次所选播放速度
|
||||
- <kbd>Ctrl + Shift + Alt + /</kbd> 清除对当前视频的倍数记忆
|
||||
- <kbd>Shift + /</kbd> 重置播放速度,再按一次回到之前的速度
|
||||
- <kbd>Shift + :</kbd> 清除对当前视频的倍数记忆
|
||||
- <kbd>0</kbd> 返回开头播放
|
||||
- <kbd>Shift</kbd>+<kbd>←</kbd>/<kbd>→</kbd> 逐帧调整进度 (需开启逐帧调整功能)
|
||||
- <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd> 视频快速截图 (需开启视频快速截图功能)
|
||||
如果弹幕渲染类型选择了Canvas, 则可以按 <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd> 来截取带弹幕的截图.
|
||||
|
||||
如果觉得默认的键位不合适,或者发现与其他插件/脚本的快捷键相冲突,可以参考<a href="https://github.com/the1812/Bilibili-Evolved/blob/preview/src/video/keymap/key-bindings.md" target="__blank">修改默认键位</a>的方法自行修改.
|
||||
`],
|
||||
|
||||
@ -28,6 +28,8 @@ const blockParams = [
|
||||
'referfrom',
|
||||
'visit_id',
|
||||
'bsource',
|
||||
'spm',
|
||||
'hotRank',
|
||||
]
|
||||
const siteSpecifiedParams = [
|
||||
{
|
||||
@ -42,6 +44,10 @@ const siteSpecifiedParams = [
|
||||
match: /\/\/www\.bilibili\.com\/bangumi\//,
|
||||
param: 'theme',
|
||||
},
|
||||
{
|
||||
match: /\/\/t\.bilibili\.com\/[\d]+/,
|
||||
param: 'type',
|
||||
},
|
||||
]
|
||||
const noNormalizes = [
|
||||
/game\.bilibili\.com\/fgo/,
|
||||
|
||||
84
src/video/context-menu/player-context-menu.ts
Normal file
84
src/video/context-menu/player-context-menu.ts
Normal file
@ -0,0 +1,84 @@
|
||||
/** 播放器右键菜单 */
|
||||
export interface PlayerContextMenu {
|
||||
/** 总体容器元素, 不是里面那个 <ul> */
|
||||
containerElement: HTMLElement
|
||||
/** 里面的 <ul> 列表元素 */
|
||||
listElement: HTMLElement
|
||||
/** 所有菜单项元素 */
|
||||
itemElements: HTMLElement[]
|
||||
/** 是否已打开 */
|
||||
isOpen: boolean
|
||||
}
|
||||
/** 在播放器菜单打开/关闭时执行特定操作 */
|
||||
export const forEachContextMenu = async (action: {
|
||||
open?: (menu: PlayerContextMenu) => void,
|
||||
close?: (menu: PlayerContextMenu) => void,
|
||||
}) => {
|
||||
const { open, close } = action
|
||||
const hasVideo = await videoCondition()
|
||||
if (!hasVideo) {
|
||||
return
|
||||
}
|
||||
const player = await SpinQuery.select('.bilibili-player') as HTMLElement
|
||||
if (!player) {
|
||||
return
|
||||
}
|
||||
const playerObserver = Observer.childList(player, () => {
|
||||
const container = dq('.bilibili-player-context-menu-origin') as HTMLElement
|
||||
if (container) {
|
||||
playerObserver.stop()
|
||||
const ul = dq(container, 'ul') as HTMLElement
|
||||
const menu: PlayerContextMenu = {
|
||||
containerElement: container,
|
||||
listElement: ul,
|
||||
get itemElements() {
|
||||
return dqa(container, '.context-menu-function') as HTMLElement[]
|
||||
},
|
||||
get isOpen() {
|
||||
return container.classList.contains('active')
|
||||
}
|
||||
}
|
||||
Observer.childList(ul, () => {
|
||||
if (menu.isOpen) { // 打开菜单
|
||||
open?.(menu)
|
||||
} else { // 关闭菜单
|
||||
close?.(menu)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
/** 添加播放器菜单项 */
|
||||
export const addMenuItem = async (
|
||||
element: HTMLElement,
|
||||
cleanUp?: (menu: PlayerContextMenu) => void,
|
||||
) =>{
|
||||
return forEachContextMenu({
|
||||
open: menu => {
|
||||
if (menu.listElement.contains(element)) {
|
||||
return
|
||||
}
|
||||
// <li class="context-line context-menu-function" data-append="1">
|
||||
// <a class="context-menu-a js-action" href="javascript:void(0);"></a>
|
||||
// </li>
|
||||
const menuItem = document.createElement('li')
|
||||
menuItem.classList.add('context-line', 'context-menu-function')
|
||||
menuItem.setAttribute('data-append', '1')
|
||||
const linkWrapper = document.createElement('a')
|
||||
linkWrapper.classList.add('context-menu-a', 'js-action')
|
||||
linkWrapper.href = 'javascript:void(0);'
|
||||
linkWrapper.appendChild(element)
|
||||
menuItem.addEventListener('mouseover', () => menuItem.classList.add('hover'))
|
||||
menuItem.addEventListener('mouseout', () => menuItem.classList.remove('hover'))
|
||||
menuItem.appendChild(linkWrapper)
|
||||
menu.listElement.appendChild(menuItem)
|
||||
},
|
||||
close: menu => cleanUp?.(menu),
|
||||
})
|
||||
}
|
||||
export default {
|
||||
export: {
|
||||
forEachContextMenu,
|
||||
addMenuItem,
|
||||
}
|
||||
}
|
||||
10
src/video/context-menu/repeat/menu-repeat-video.ts
Normal file
10
src/video/context-menu/repeat/menu-repeat-video.ts
Normal file
@ -0,0 +1,10 @@
|
||||
(async () => {
|
||||
if (!(await videoCondition())) {
|
||||
return
|
||||
}
|
||||
const { addMenuItem } = await import('../player-context-menu')
|
||||
const div = document.createElement('div')
|
||||
div.addEventListener('click', () => console.log('click!'))
|
||||
div.innerHTML = 'test'
|
||||
addMenuItem(div)
|
||||
})()
|
||||
@ -134,40 +134,14 @@ if (supportedUrls.some(url => document.URL.startsWith(url))) {
|
||||
like: (() => {
|
||||
/** 长按`L`三连使用的记忆变量 */
|
||||
let likeClick = true
|
||||
/** 在稍后再看页面里, 记录当前视频是否赞过 */
|
||||
let liked = false
|
||||
|
||||
const listenWatchlaterVideoChange = _.once(() => {
|
||||
Observer.videoChange(() => {
|
||||
Ajax.getJsonWithCredentials(`https://api.bilibili.com/x/web-interface/archive/has/like?aid=${unsafeWindow.aid}`).then(json => {
|
||||
liked = Boolean(json.data)
|
||||
})
|
||||
})
|
||||
})
|
||||
return (({ isWatchlater, isMediaList, event }) => {
|
||||
if (isWatchlater) {
|
||||
listenWatchlaterVideoChange()
|
||||
const formData = {
|
||||
aid: unsafeWindow.aid,
|
||||
/** `1`点赞; `2`取消赞 */
|
||||
like: liked ? 2 : 1,
|
||||
csrf: getCsrf(),
|
||||
}
|
||||
Ajax.postTextWithCredentials(`https://api.bilibili.com/x/web-interface/archive/like`, Object.entries(formData).map(([k, v]) => `${k}=${v}`).join('&')).then(() => {
|
||||
liked = !liked
|
||||
if (liked) {
|
||||
Toast.success(`已点赞`, `快捷键扩展`, 1000)
|
||||
} else {
|
||||
Toast.success(`已取消点赞`, `快捷键扩展`, 1000)
|
||||
}
|
||||
})
|
||||
} else if (isMediaList) {
|
||||
if (isMediaList || isWatchlater) {
|
||||
const likeButton = dq('.play-options-ul > li:first-child') as HTMLLIElement
|
||||
if (likeButton) {
|
||||
likeButton.click()
|
||||
}
|
||||
} else {
|
||||
const likeButton = dq('.video-toolbar .like') as HTMLSpanElement
|
||||
const likeButton = dq('.video-toolbar .like, .tool-bar .like-info') as HTMLSpanElement
|
||||
event.preventDefault()
|
||||
const fireEvent = (name: string, args: Event) => {
|
||||
const event = new CustomEvent(name, args)
|
||||
@ -225,14 +199,11 @@ if (supportedUrls.some(url => document.URL.startsWith(url))) {
|
||||
controller.setVideoSpeed([...rates].reverse().find(it => it < controller.playbackRate) || rates[0])
|
||||
}),
|
||||
videoSpeedReset: videoSpeed((controller) => {
|
||||
controller.reset()
|
||||
controller.toggleVideoSpeed()
|
||||
}),
|
||||
videoSpeedForget: videoSpeed((controller) => {
|
||||
controller.reset(true)
|
||||
}),
|
||||
videoSpeedToggle: videoSpeed((controller) => {
|
||||
controller.toggleVideoSpeed()
|
||||
}),
|
||||
takeScreenshot: clickElement('.video-take-screenshot'),
|
||||
previousFrame: clickElement('.prev-frame'),
|
||||
nextFrame: clickElement('.next-frame'),
|
||||
@ -273,8 +244,7 @@ if (supportedUrls.some(url => document.URL.startsWith(url))) {
|
||||
videoSpeedIncrease: 'shift > 》 arrowUp',
|
||||
videoSpeedDecrease: 'shift < 《 arrowDown',
|
||||
videoSpeedReset: 'shift ? ?',
|
||||
videoSpeedForget: 'ctrl shift alt ?',
|
||||
videoSpeedToggle: 'ctrl shift ?',
|
||||
videoSpeedForget: 'shift :',
|
||||
takeScreenshot: 'ctrl alt c',
|
||||
previousFrame: 'shift arrowLeft',
|
||||
nextFrame: 'shift arrowRight',
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
.ops .watchlater
|
||||
{
|
||||
margin-right: 28px !important;
|
||||
position: relative;
|
||||
}
|
||||
.ops .watchlater .tip
|
||||
{
|
||||
.ops .watchlater {
|
||||
margin-right: 28px !important;
|
||||
position: relative;
|
||||
width: auto !important;
|
||||
@media screen and (max-width: 1320px), (max-height: 750px) {
|
||||
margin-right: max(calc(11 * 1vw - 117.2px), 6px) !important;
|
||||
.text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.tip {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
left: 50%;
|
||||
@ -14,17 +18,15 @@
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
color: #eee;
|
||||
transition: all .2s ease-out;
|
||||
transition: all 0.2s ease-out;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.watchlater .tip.show
|
||||
{
|
||||
opacity: 1;
|
||||
pointer-events: initial;
|
||||
}
|
||||
.ops .watchlater>i
|
||||
{
|
||||
&.show {
|
||||
opacity: 1;
|
||||
pointer-events: initial;
|
||||
}
|
||||
}
|
||||
> i {
|
||||
display: inline-block;
|
||||
font-style: normal;
|
||||
vertical-align: baseline;
|
||||
@ -33,8 +35,8 @@
|
||||
line-height: 1;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
}
|
||||
.more-ops-list > ul > li:nth-child(2) {
|
||||
display: none !important;
|
||||
}
|
||||
.more-ops-list>ul>li:nth-child(2)
|
||||
{
|
||||
display: none !important;
|
||||
}
|
||||
@ -10,10 +10,10 @@
|
||||
}
|
||||
resources.applyStyle('outerWatchlaterStyle')
|
||||
favoriteButton.insertAdjacentHTML('afterend', /*html*/`
|
||||
<span title='稍后再看' class='watchlater' :class="{on: isInWatchlater}" @click="toggle()">
|
||||
<span title='稍后再看' class='watchlater' :class="{ on: isInWatchlater }" @click="toggle()">
|
||||
<i class='mdi mdi-timetable'></i>
|
||||
稍后再看
|
||||
<div class='tip' :class="{show: tipShowing}">{{tipText}}</div>
|
||||
<span class="text">稍后再看</span>
|
||||
<div class='tip' :class="{ show: tipShowing }">{{ tipText }}</div>
|
||||
</span>
|
||||
`.trim())
|
||||
const watchlaterButton = dq('.ops .watchlater')
|
||||
|
||||
@ -6,6 +6,16 @@
|
||||
.quick-favorite {
|
||||
margin-right: 28px !important;
|
||||
position: relative;
|
||||
width: auto !important;
|
||||
.text {
|
||||
display: inline;
|
||||
}
|
||||
@media screen and (max-width: 1320px), (max-height: 750px) {
|
||||
margin-right: max(calc(11 * 1vw - 117.2px), 6px) !important;
|
||||
.text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
> i {
|
||||
font-family: "quick-favorite" !important;
|
||||
display: inline-block;
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
const html = /*html*/`
|
||||
<span title="快速收藏" @click.left.self="toggle()" @click.right.prevent.self="listShowing = !listShowing" class="quick-favorite" :class="{ on: isFavorite }">
|
||||
<i @click.left="toggle()" @click.right.prevent="listShowing = !listShowing"></i>
|
||||
<div style="display: inline" @click.left="toggle()" @click.right.prevent="listShowing = !listShowing">快速收藏</div>
|
||||
<div class="text" @click.left="toggle()" @click.right.prevent="listShowing = !listShowing">快速收藏</div>
|
||||
</template>
|
||||
<div class="select-list" ref="selectList" :class="{ show: listShowing }">
|
||||
选择快速收藏夹:
|
||||
|
||||
3
src/video/remove-guide-popup.ts
Normal file
3
src/video/remove-guide-popup.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export default resources.toggleStyle(`
|
||||
.bilibili-player-video-popup-guide-attention { display: none !important; }
|
||||
`.trim(), 'remove-guide-popup-style')
|
||||
@ -92,7 +92,7 @@ export class VideoSpeedController {
|
||||
settings.rememberVideoSpeedList = settings.rememberVideoSpeedList
|
||||
}
|
||||
|
||||
static async getInstance(previousSpeed?: number) {
|
||||
static async getInstance(previousSpeed?: number, nativeSpeed?: number) {
|
||||
const containerElement = await SpinQuery.select(`.${VideoSpeedController.classNameMap.speedContainer}`)
|
||||
const videoElement = await SpinQuery.select(`.${VideoSpeedController.classNameMap.video} video`) as HTMLVideoElement
|
||||
|
||||
@ -103,19 +103,21 @@ export class VideoSpeedController {
|
||||
throw "video element not found!"
|
||||
}
|
||||
|
||||
return new VideoSpeedController(containerElement, videoElement, previousSpeed)
|
||||
return new VideoSpeedController(containerElement, videoElement, previousSpeed, nativeSpeed)
|
||||
}
|
||||
|
||||
static init = _.once(() => {
|
||||
// 分 P 切换时共享同一个倍数
|
||||
let sharedSpeed = 1
|
||||
// 分 P 切换时共享同一个倍数,这里指定初始倍数可以是 undefined,不需要是 1
|
||||
let sharedSpeed: number | undefined = undefined
|
||||
// 分 P 切换时共享同一个原生倍速值,初始值设置为 1
|
||||
let sharedNativeSpeed = 1
|
||||
// 持有菜单容器元素的引用,videoChange 时更换(以前缓存的 VideoController 就没有意义了)
|
||||
let containerElement: HTMLElement
|
||||
|
||||
Observer.videoChange(async () => {
|
||||
const { getExtraSpeedMenuItemElements } = await import("./extend-video-speed")
|
||||
// 有必要传递之前的 nativeSpeedVal,跨分 P 时原生倍数将保持一样
|
||||
const controller = await VideoSpeedController.getInstance(sharedSpeed)
|
||||
// 有必要传递之前的 nativeSpeed,跨分 P 时原生倍数将保持一样
|
||||
const controller = await VideoSpeedController.getInstance(sharedSpeed, sharedNativeSpeed)
|
||||
controller.observe();
|
||||
if (settings.extendVideoSpeed) {
|
||||
controller._menuListElement.prepend(...await getExtraSpeedMenuItemElements())
|
||||
@ -136,10 +138,13 @@ export class VideoSpeedController {
|
||||
}
|
||||
})
|
||||
}
|
||||
// 理论上这里的 controller 一定是非缓存的,因此不用太担心事件监听注册重复
|
||||
// 理论上这里的 controller 一定是非缓存的(换 P 的时候 containerElement 是会发生改变的),因此不用担心重复注册事件监听
|
||||
({ containerElement } = controller)
|
||||
containerElement.addEventListener("changed", ({ detail: { speed } }: CustomEvent) => {
|
||||
containerElement.addEventListener("changed", ({ detail: { speed, isNativeSpeed } }: CustomEvent) => {
|
||||
sharedSpeed = speed
|
||||
if (isNativeSpeed) {
|
||||
sharedNativeSpeed = speed
|
||||
}
|
||||
})
|
||||
// 首次加载可能会遇到意外情况,导致内部强制更新失效,因此延时 100 ms 再触发速度设置
|
||||
setTimeout(() => {
|
||||
@ -154,21 +159,19 @@ export class VideoSpeedController {
|
||||
private _videoElement: HTMLVideoElement
|
||||
// 这个值模拟原生内部记录的速度倍数,它不应该被赋值成扩展倍数的值
|
||||
private _nativeSpeedVal: number
|
||||
private _previousSpeedVal: number
|
||||
// 这个值用于表示上一次(上一P)的倍数值,如果是首次播放第一P,则为 undefined
|
||||
private _previousSpeedVal?: number
|
||||
|
||||
constructor(containerElement: HTMLElement, videoElement: HTMLVideoElement, previousSpeed?: number) {
|
||||
constructor(containerElement: HTMLElement, videoElement: HTMLVideoElement, previousSpeed?: number, nativeSpeed?: number) {
|
||||
const controller = VideoSpeedController.instanceMap.get(containerElement)
|
||||
if (controller && (!previousSpeed || controller.playbackRate === previousSpeed)) {
|
||||
if (controller && (!previousSpeed || controller._previousSpeedVal === previousSpeed) && (!nativeSpeed || controller._nativeSpeedVal === nativeSpeed)) {
|
||||
return controller
|
||||
}
|
||||
|
||||
this._videoElement = videoElement
|
||||
|
||||
previousSpeed = previousSpeed ?? this.playbackRate
|
||||
|
||||
this._containerElement = containerElement
|
||||
this._previousSpeedVal = previousSpeed
|
||||
this._nativeSpeedVal = VideoSpeedController.nativeSupportedRates.includes(previousSpeed) ? previousSpeed : 1
|
||||
this._nativeSpeedVal = nativeSpeed ?? (previousSpeed && VideoSpeedController.nativeSupportedRates.includes(previousSpeed) ? previousSpeed : 1)
|
||||
this._nameBtn = this._containerElement.querySelector(`.${VideoSpeedController.classNameMap.speedNameBtn}`) as HTMLButtonElement
|
||||
this._menuListElement = this._containerElement.querySelector(`.${VideoSpeedController.classNameMap.speedMenuList}`) as HTMLElement
|
||||
|
||||
@ -213,11 +216,13 @@ export class VideoSpeedController {
|
||||
|
||||
currentSpeed = parseFloat(selectedSpeedOption.dataset.value ?? '1')
|
||||
|
||||
this._containerElement.dispatchEvent(new CustomEvent("changed", { detail: { speed: currentSpeed, previousSpeed: this._previousSpeedVal } }))
|
||||
|
||||
let isNativeSpeed = false
|
||||
if (VideoSpeedController.nativeSupportedRates.includes(currentSpeed)) {
|
||||
this._nativeSpeedVal = currentSpeed
|
||||
isNativeSpeed = true
|
||||
}
|
||||
|
||||
this._containerElement.dispatchEvent(new CustomEvent("changed", { detail: { speed: currentSpeed, isNativeSpeed, previousSpeed: this._previousSpeedVal } }))
|
||||
// 原生支持倍数的应用后,有必要清除扩展倍数选项上的样式
|
||||
if (settings.extendVideoSpeed && VideoSpeedController.nativeSupportedRates.includes(currentSpeed)) {
|
||||
this._menuListElement.querySelector(`.${VideoSpeedController.classNameMap.speedMenuItem}.extended.${VideoSpeedController.classNameMap.active}`)?.classList.remove(VideoSpeedController.classNameMap.active)
|
||||
@ -234,30 +239,63 @@ export class VideoSpeedController {
|
||||
}
|
||||
})
|
||||
// 刷新 this._previousSpeedVal
|
||||
// 用户可以通过倍数菜单或者重置倍数快捷键造成类似 2.0x 1.0x 1.0x ... 这样的倍数设定序列
|
||||
// 我们不希望在第二个 1.0x 的时候刷新 this._previousSpeedVal,这样会比较死板
|
||||
// 判定依据在于 previousSpeed !== currentSpeed
|
||||
// - 用户可以通过倍数菜单或者倍数快捷键造成类似 1.5x 2.0x 2.0x... 这样的倍数设定序列
|
||||
// 我们不希望在第二个 2.0x 的时候刷新 this._previousSpeedVal,这样会比较死板
|
||||
// 判定依据在于 previousSpeed !== currentSpeed
|
||||
if (previousSpeed && previousSpeed !== currentSpeed) {
|
||||
this._previousSpeedVal = previousSpeed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
toggleVideoSpeed() {
|
||||
this.setVideoSpeed(this._previousSpeedVal)
|
||||
/**
|
||||
* 切换当前倍数
|
||||
*
|
||||
* 根据`mode`参数的不同有着不同的行为:
|
||||
*
|
||||
* - `mode === "smart"`(默认):当前倍数等于 1.0x 时,切换到上次不同的视频倍数,否则重置倍数为 1.0x
|
||||
* - `mode === "classic"`:无论当前倍数如何,均切换到上次不同的视频倍数
|
||||
*
|
||||
* 重置倍数的行为可由 `reset()` 方法同款参数 `forget` 来控制
|
||||
*
|
||||
* @param forget 指示是否为清除视频记忆的重置倍数操作
|
||||
*/
|
||||
toggleVideoSpeed(mode: "smart" | "classic" = "smart", forget = false) {
|
||||
switch (mode) {
|
||||
case "smart":
|
||||
this.playbackRate === 1 ? this.setVideoSpeed(this._previousSpeedVal) : this.reset(forget)
|
||||
break
|
||||
case "classic":
|
||||
this.setVideoSpeed(this._previousSpeedVal)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置视频倍数
|
||||
*
|
||||
* @param forget 指示是否为清除视频记忆的重置倍数操作
|
||||
*/
|
||||
reset(forget = false) {
|
||||
if (forget) {
|
||||
const fallbackVideoSpeed = VideoSpeedController.fallbackVideoSpeed
|
||||
// 如果 fallbackVideoSpeed 是 undefined,那么意味着没有开启记忆倍数功能
|
||||
// 考虑到与清除视频级别的倍数记忆功能的相关性,这里会忽略设定
|
||||
// 简单地说,如果没有开启记忆倍数的功能,就无法清除视频级别的倍数记忆
|
||||
if (!fallbackVideoSpeed) {
|
||||
return
|
||||
}
|
||||
VideoSpeedController.forgetSpeed()
|
||||
this.setVideoSpeed(VideoSpeedController.fallbackVideoSpeed || 1)
|
||||
this.setVideoSpeed(VideoSpeedController.fallbackVideoSpeed)
|
||||
} else {
|
||||
this.setVideoSpeed(1)
|
||||
}
|
||||
}
|
||||
|
||||
setVideoSpeed(speed: number) {
|
||||
this.getSpeedMenuItem(speed).click()
|
||||
setVideoSpeed(speed?: number) {
|
||||
speed && this.getSpeedMenuItem(speed).click()
|
||||
}
|
||||
|
||||
private setExtendedVideoSpeed(speed: number) {
|
||||
|
||||
@ -1 +1 @@
|
||||
1.11.14
|
||||
1.11.15
|
||||
Loading…
Reference in New Issue
Block a user