8
8
// @license AGPL-3.0-only
9
9
// @author Sv443
10
10
// @copyright Sv443 (https://github.com/Sv443)
11
- // @icon https://cdn.jsdelivr.net/gh/Sv443/BetterYTM@e609d291 /assets/images/logo/logo_dev_48.png
11
+ // @icon https://cdn.jsdelivr.net/gh/Sv443/BetterYTM@059c0308 /assets/images/logo/logo_dev_48.png
12
12
// @match https://music.youtube.com/*
13
13
// @match https://www.youtube.com/*
14
14
// @run -at document-start
@@ -335,7 +335,7 @@ const rawConsts = {
335
335
mode : "development" ,
336
336
branch : "develop" ,
337
337
host : "github" ,
338
- buildNumber : "e609d291 " ,
338
+ buildNumber : "059c0308 " ,
339
339
assetSource : "jsdelivr" ,
340
340
devServerPort : "8710" ,
341
341
} ;
@@ -2213,115 +2213,7 @@ function getChannelIdFromPrompt(promptStr) {
2213
2213
const isUrl = promptStr . match ( / ^ (?: h t t p s ? : \/ \/ ) ? (?: w w w \. ) ? (?: m u s i c \. ) ? y o u t u b e \. c o m \/ (?: c h a n n e l \/ | @ ) ( [ a - z A - Z 0 - 9 _ - ] + ) / ) ;
2214
2214
const id = ( ( isId === null || isId === void 0 ? void 0 : isId [ 0 ] ) || ( isUrl === null || isUrl === void 0 ? void 0 : isUrl [ 1 ] ) || "" ) . trim ( ) ;
2215
2215
return id . length > 0 ? id : null ;
2216
- } //#region utils
2217
- const ignoreTagNamesInput = [ "INPUT" , "TEXTAREA" , "SELECT" , "BUTTON" , "A" ] ;
2218
- const ignoreIdsInput = [
2219
- "contenteditable-root" , // comment field on YT
2220
- "volume-slider" , // volume slider on YTM
2221
- ] ;
2222
- const ignoreClassNamesInput = [ ] ;
2223
- /** Returns true, if the given element (document.activeElement by default) is an input element that should make BYTM ignore keypresses */
2224
- function isIgnoredInputElement ( el = document . activeElement ) {
2225
- if ( ! el )
2226
- return false ;
2227
- return ignoreTagNamesInput . includes ( el . tagName . toUpperCase ( ) )
2228
- || ignoreClassNamesInput . some ( ( cls ) => el . classList . contains ( cls ) )
2229
- || ignoreIdsInput . includes ( el . id ) ;
2230
- }
2231
- //#region arrow key skip
2232
- let sliderEl ;
2233
- async function initArrowKeySkip ( ) {
2234
- addSelectorListener ( "playerBarRightControls" , "tp-yt-paper-slider#volume-slider" , {
2235
- listener : ( el ) => sliderEl = el ,
2236
- } ) ;
2237
- document . addEventListener ( "keydown" , ( evt ) => {
2238
- var _a , _b ;
2239
- if ( ! getFeature ( "arrowKeySupport" ) )
2240
- return ;
2241
- if ( [ "ArrowUp" , "ArrowDown" ] . includes ( evt . code ) && getDomain ( ) === "ytm" )
2242
- return handleVolumeKeyPress ( evt ) ;
2243
- if ( ! [ "ArrowLeft" , "ArrowRight" ] . includes ( evt . code ) )
2244
- return ;
2245
- const allowedClasses = [ "bytm-generic-btn" , "yt-spec-button-shape-next" ] ;
2246
- // discard the event when a (text) input is currently active, like when editing a playlist or writing a comment
2247
- if ( isIgnoredInputElement ( ) && ! allowedClasses . some ( ( cls ) => { var _a ; return ( _a = document . activeElement ) === null || _a === void 0 ? void 0 : _a . classList . contains ( cls ) ; } ) )
2248
- return info ( `Captured valid key to skip forward or backward but the current active element is <${ ( _a = document . activeElement ) === null || _a === void 0 ? void 0 : _a . tagName . toLowerCase ( ) } >, so the keypress is ignored` ) ;
2249
- evt . preventDefault ( ) ;
2250
- evt . stopImmediatePropagation ( ) ;
2251
- let skipBy = ( _b = getFeature ( "arrowKeySkipBy" ) ) !== null && _b !== void 0 ? _b : featInfo . arrowKeySkipBy . default ;
2252
- if ( evt . code === "ArrowLeft" )
2253
- skipBy *= - 1 ;
2254
- log ( `Captured arrow key '${ evt . code } ' - skipping by ${ skipBy } seconds` ) ;
2255
- const vidElem = getVideoElement ( ) ;
2256
- if ( vidElem && vidElem . readyState > 0 )
2257
- vidElem . currentTime = UserUtils . clamp ( vidElem . currentTime + skipBy , 0 , vidElem . duration ) ;
2258
- } ) ;
2259
- log ( "Added arrow key press listener" ) ;
2260
- }
2261
- function handleVolumeKeyPress ( evt ) {
2262
- var _a ;
2263
- evt . preventDefault ( ) ;
2264
- evt . stopImmediatePropagation ( ) ;
2265
- if ( ! getVideoElement ( ) )
2266
- return warn ( "Couldn't find video element, so the keypress is ignored" ) ;
2267
- if ( ! sliderEl )
2268
- return warn ( "Couldn't find volume slider element, so the keypress is ignored" ) ;
2269
- const step = Number ( sliderEl . step ) ;
2270
- const newVol = UserUtils . clamp ( Number ( sliderEl . value )
2271
- + ( evt . code === "ArrowUp" ? 1 : - 1 )
2272
- * UserUtils . clamp ( ( ( _a = getFeature ( "arrowKeyVolumeStep" ) ) !== null && _a !== void 0 ? _a : featInfo . arrowKeyVolumeStep . default ) , isNaN ( step ) ? 5 : step , 100 ) , 0 , 100 ) ;
2273
- if ( newVol !== Number ( sliderEl . value ) ) {
2274
- sliderEl . value = String ( newVol ) ;
2275
- sliderEl . dispatchEvent ( new Event ( "change" , { bubbles : true } ) ) ;
2276
- log ( `Captured key '${ evt . code } ' - changed volume to ${ newVol } %` ) ;
2277
- }
2278
- }
2279
- //#region frame skip
2280
- /** Initializes the feature that lets users skip by a frame with the period and comma keys while the video is paused */
2281
- async function initFrameSkip ( ) {
2282
- document . addEventListener ( "keydown" , async ( evt ) => {
2283
- if ( ! getFeature ( "frameSkip" ) )
2284
- return ;
2285
- if ( ! [ "Comma" , "Period" ] . includes ( evt . code ) )
2286
- return ;
2287
- const vid = getVideoElement ( ) ;
2288
- if ( ! vid || vid . readyState === 0 )
2289
- return warn ( "Could not find video element or it hasn't loaded yet, so the keypress is ignored" ) ;
2290
- if ( ! getFeature ( "frameSkipWhilePlaying" ) && ( vid . playbackRate === 0 || ! vid . paused ) )
2291
- return ;
2292
- evt . preventDefault ( ) ;
2293
- evt . stopImmediatePropagation ( ) ;
2294
- const newTime = vid . currentTime + getFeature ( "frameSkipAmount" ) * ( evt . code === "Comma" ? - 1 : 1 ) ;
2295
- vid . currentTime = UserUtils . clamp ( newTime , 0 , vid . duration ) ;
2296
- log ( `Captured key '${ evt . code } ' and skipped to ${ Math . floor ( newTime / 60 ) } m ${ ( newTime % 60 ) . toFixed ( 1 ) } s (${ Math . floor ( newTime * 1000 % 1000 ) } ms)` ) ;
2297
- } ) ;
2298
- log ( "Added frame skip key press listener" ) ;
2299
- }
2300
- //#region num keys skip
2301
- /** Adds the ability to skip to a certain time in the video by pressing a number key (0-9) */
2302
- async function initNumKeysSkip ( ) {
2303
- document . addEventListener ( "keydown" , ( e ) => {
2304
- if ( ! getFeature ( "numKeysSkipToTime" ) )
2305
- return ;
2306
- if ( ! e . key . trim ( ) . match ( / ^ [ 0 - 9 ] $ / ) )
2307
- return ;
2308
- // discard the event when an unexpected element is currently active or in focus, like when editing a playlist or when the search bar is focused
2309
- const ignoreElement = isIgnoredInputElement ( ) ;
2310
- if ( ( document . activeElement !== document . body && ignoreElement ) || ignoreElement )
2311
- return info ( "Captured valid key to skip video to, but ignored it since this element is currently active:" , document . activeElement ) ;
2312
- const vidElem = getVideoElement ( ) ;
2313
- if ( ! vidElem || vidElem . readyState === 0 )
2314
- return warn ( "Could not find video element, so the keypress is ignored" ) ;
2315
- const newVidTime = vidElem . duration / ( 10 / Number ( e . key ) ) ;
2316
- if ( ! isNaN ( newVidTime ) ) {
2317
- log ( `Captured number key [${ e . key } ], skipping to ${ Math . floor ( newVidTime / 60 ) } m ${ ( newVidTime % 60 ) . toFixed ( 1 ) } s` ) ;
2318
- vidElem . currentTime = newVidTime ;
2319
- }
2320
- } ) ;
2321
- log ( "Added number key press listener" ) ;
2322
- }
2323
- //#region auto-like vids
2324
- let canCompress$1 = false ;
2216
+ } let canCompress$1 = false ;
2325
2217
/** DataStore instance for all auto-liked channels */
2326
2218
const autoLikeStore = new UserUtils . DataStore ( {
2327
2219
id : "bytm-auto-like-channels" ,
@@ -5612,6 +5504,112 @@ async function initWatchPageFullSize() {
5612
5504
error ( "Couldn't load stylesheet to make watch page full size" ) ;
5613
5505
else
5614
5506
log ( "Made watch page full size" ) ;
5507
+ } //#region utils
5508
+ const ignoreTagNamesInput = [ "INPUT" , "TEXTAREA" , "SELECT" , "BUTTON" , "A" ] ;
5509
+ const ignoreIdsInput = [
5510
+ "contenteditable-root" , // comment field on YT
5511
+ "volume-slider" , // volume slider on YTM
5512
+ ] ;
5513
+ const ignoreClassNamesInput = [ ] ;
5514
+ /** Returns true, if the given element (document.activeElement by default) is an input element that should make BYTM ignore keypresses */
5515
+ function isIgnoredInputElement ( el = document . activeElement ) {
5516
+ if ( ! el )
5517
+ return false ;
5518
+ return ignoreTagNamesInput . includes ( el . tagName . toUpperCase ( ) )
5519
+ || ignoreClassNamesInput . some ( ( cls ) => el . classList . contains ( cls ) )
5520
+ || ignoreIdsInput . includes ( el . id ) ;
5521
+ }
5522
+ //#region arrow key skip
5523
+ let sliderEl ;
5524
+ async function initArrowKeySkip ( ) {
5525
+ addSelectorListener ( "playerBarRightControls" , "tp-yt-paper-slider#volume-slider" , {
5526
+ listener : ( el ) => sliderEl = el ,
5527
+ } ) ;
5528
+ document . addEventListener ( "keydown" , ( evt ) => {
5529
+ var _a , _b ;
5530
+ if ( ! getFeature ( "arrowKeySupport" ) )
5531
+ return ;
5532
+ if ( [ "ArrowUp" , "ArrowDown" ] . includes ( evt . code ) && getDomain ( ) === "ytm" )
5533
+ return handleVolumeKeyPress ( evt ) ;
5534
+ if ( ! [ "ArrowLeft" , "ArrowRight" ] . includes ( evt . code ) )
5535
+ return ;
5536
+ const allowedClasses = [ "bytm-generic-btn" , "yt-spec-button-shape-next" ] ;
5537
+ // discard the event when a (text) input is currently active, like when editing a playlist or writing a comment
5538
+ if ( isIgnoredInputElement ( ) && ! allowedClasses . some ( ( cls ) => { var _a ; return ( _a = document . activeElement ) === null || _a === void 0 ? void 0 : _a . classList . contains ( cls ) ; } ) )
5539
+ return info ( `Captured valid key to skip forward or backward but the current active element is <${ ( _a = document . activeElement ) === null || _a === void 0 ? void 0 : _a . tagName . toLowerCase ( ) } >, so the keypress is ignored` ) ;
5540
+ evt . preventDefault ( ) ;
5541
+ evt . stopImmediatePropagation ( ) ;
5542
+ let skipBy = ( _b = getFeature ( "arrowKeySkipBy" ) ) !== null && _b !== void 0 ? _b : featInfo . arrowKeySkipBy . default ;
5543
+ if ( evt . code === "ArrowLeft" )
5544
+ skipBy *= - 1 ;
5545
+ log ( `Captured arrow key '${ evt . code } ' - skipping by ${ skipBy } seconds` ) ;
5546
+ const vidElem = getVideoElement ( ) ;
5547
+ if ( vidElem && vidElem . readyState > 0 )
5548
+ vidElem . currentTime = UserUtils . clamp ( vidElem . currentTime + skipBy , 0 , vidElem . duration ) ;
5549
+ } ) ;
5550
+ log ( "Added arrow key press listener" ) ;
5551
+ }
5552
+ function handleVolumeKeyPress ( evt ) {
5553
+ var _a ;
5554
+ evt . preventDefault ( ) ;
5555
+ evt . stopImmediatePropagation ( ) ;
5556
+ if ( ! getVideoElement ( ) )
5557
+ return warn ( "Couldn't find video element, so the keypress is ignored" ) ;
5558
+ if ( ! sliderEl )
5559
+ return warn ( "Couldn't find volume slider element, so the keypress is ignored" ) ;
5560
+ const step = Number ( sliderEl . step ) ;
5561
+ const newVol = UserUtils . clamp ( Number ( sliderEl . value )
5562
+ + ( evt . code === "ArrowUp" ? 1 : - 1 )
5563
+ * UserUtils . clamp ( ( ( _a = getFeature ( "arrowKeyVolumeStep" ) ) !== null && _a !== void 0 ? _a : featInfo . arrowKeyVolumeStep . default ) , isNaN ( step ) ? 5 : step , 100 ) , 0 , 100 ) ;
5564
+ if ( newVol !== Number ( sliderEl . value ) ) {
5565
+ sliderEl . value = String ( newVol ) ;
5566
+ sliderEl . dispatchEvent ( new Event ( "change" , { bubbles : true } ) ) ;
5567
+ log ( `Captured key '${ evt . code } ' - changed volume to ${ newVol } %` ) ;
5568
+ }
5569
+ }
5570
+ //#region frame skip
5571
+ /** Initializes the feature that lets users skip by a frame with the period and comma keys while the video is paused */
5572
+ async function initFrameSkip ( ) {
5573
+ document . addEventListener ( "keydown" , async ( evt ) => {
5574
+ if ( ! getFeature ( "frameSkip" ) )
5575
+ return ;
5576
+ if ( ! [ "Comma" , "Period" ] . includes ( evt . code ) )
5577
+ return ;
5578
+ const vid = getVideoElement ( ) ;
5579
+ if ( ! vid || vid . readyState === 0 )
5580
+ return warn ( "Could not find video element or it hasn't loaded yet, so the keypress is ignored" ) ;
5581
+ if ( ! getFeature ( "frameSkipWhilePlaying" ) && ( vid . playbackRate === 0 || ! vid . paused ) )
5582
+ return ;
5583
+ evt . preventDefault ( ) ;
5584
+ evt . stopImmediatePropagation ( ) ;
5585
+ const newTime = vid . currentTime + getFeature ( "frameSkipAmount" ) * ( evt . code === "Comma" ? - 1 : 1 ) ;
5586
+ vid . currentTime = UserUtils . clamp ( newTime , 0 , vid . duration ) ;
5587
+ log ( `Captured key '${ evt . code } ' and skipped to ${ Math . floor ( newTime / 60 ) } m ${ ( newTime % 60 ) . toFixed ( 1 ) } s (${ Math . floor ( newTime * 1000 % 1000 ) } ms)` ) ;
5588
+ } ) ;
5589
+ log ( "Added frame skip key press listener" ) ;
5590
+ }
5591
+ //#region num keys skip
5592
+ /** Adds the ability to skip to a certain time in the video by pressing a number key (0-9) */
5593
+ async function initNumKeysSkip ( ) {
5594
+ document . addEventListener ( "keydown" , ( e ) => {
5595
+ if ( ! getFeature ( "numKeysSkipToTime" ) )
5596
+ return ;
5597
+ if ( ! e . key . trim ( ) . match ( / ^ [ 0 - 9 ] $ / ) )
5598
+ return ;
5599
+ // discard the event when an unexpected element is currently active or in focus, like when editing a playlist or when the search bar is focused
5600
+ const ignoreElement = isIgnoredInputElement ( ) ;
5601
+ if ( ( document . activeElement !== document . body && ignoreElement ) || ignoreElement )
5602
+ return info ( "Captured valid key to skip video to, but ignored it since this element is currently active:" , document . activeElement ) ;
5603
+ const vidElem = getVideoElement ( ) ;
5604
+ if ( ! vidElem || vidElem . readyState === 0 )
5605
+ return warn ( "Could not find video element, so the keypress is ignored" ) ;
5606
+ const newVidTime = vidElem . duration / ( 10 / Number ( e . key ) ) ;
5607
+ if ( ! isNaN ( newVidTime ) ) {
5608
+ log ( `Captured number key [${ e . key } ], skipping to ${ Math . floor ( newVidTime / 60 ) } m ${ ( newVidTime % 60 ) . toFixed ( 1 ) } s` ) ;
5609
+ vidElem . currentTime = newVidTime ;
5610
+ }
5611
+ } ) ;
5612
+ log ( "Added number key press listener" ) ;
5615
5613
} //#region init
5616
5614
async function initHotkeys ( ) {
5617
5615
const promises = [ ] ;
@@ -6869,16 +6867,17 @@ const featInfo = {
6869
6867
enable : noop ,
6870
6868
textAdornment : adornments . ytmOnly ,
6871
6869
} ,
6870
+ //#region cat:autoLike
6872
6871
autoLikeChannels : {
6873
6872
type : "toggle" ,
6874
- category : "input " ,
6873
+ category : "autoLike " ,
6875
6874
supportedSites : [ "ytm" , "yt" ] ,
6876
6875
default : true ,
6877
6876
textAdornment : adornments . reload ,
6878
6877
} ,
6879
6878
autoLikeChannelToggleBtn : {
6880
6879
type : "toggle" ,
6881
- category : "input " ,
6880
+ category : "autoLike " ,
6882
6881
supportedSites : [ "ytm" , "yt" ] ,
6883
6882
default : true ,
6884
6883
reloadRequired : false ,
@@ -6889,13 +6888,13 @@ const featInfo = {
6889
6888
// TODO(v2.2):
6890
6889
// autoLikePlayerBarToggleBtn: {
6891
6890
// type: "toggle",
6892
- // category: "input ",
6891
+ // category: "autoLike ",
6893
6892
// default: false,
6894
6893
// textAdornment: adornments.reload,
6895
6894
// },
6896
6895
autoLikeTimeout : {
6897
6896
type : "slider" ,
6898
- category : "input " ,
6897
+ category : "autoLike " ,
6899
6898
supportedSites : [ "ytm" , "yt" ] ,
6900
6899
min : 3 ,
6901
6900
max : 30 ,
@@ -6909,7 +6908,7 @@ const featInfo = {
6909
6908
} ,
6910
6909
autoLikeShowToast : {
6911
6910
type : "toggle" ,
6912
- category : "input " ,
6911
+ category : "autoLike " ,
6913
6912
supportedSites : [ "ytm" , "yt" ] ,
6914
6913
default : true ,
6915
6914
reloadRequired : false ,
@@ -6919,7 +6918,7 @@ const featInfo = {
6919
6918
} ,
6920
6919
autoLikeOpenMgmtDialog : {
6921
6920
type : "button" ,
6922
- category : "input " ,
6921
+ category : "autoLike " ,
6923
6922
supportedSites : [ "ytm" , "yt" ] ,
6924
6923
click : ( ) => getAutoLikeDialog ( ) . then ( d => d . open ( ) ) ,
6925
6924
} ,
@@ -7227,18 +7226,6 @@ const featInfo = {
7227
7226
default : undefined ,
7228
7227
click : ( ) => getPluginListDialog ( ) . then ( d => d . open ( ) ) ,
7229
7228
} ,
7230
- initTimeout : {
7231
- type : "number" ,
7232
- category : "plugins" ,
7233
- supportedSites : [ "ytm" , "yt" ] ,
7234
- min : 3 ,
7235
- max : 30 ,
7236
- default : 8 ,
7237
- step : 0.1 ,
7238
- unit : "s" ,
7239
- advanced : true ,
7240
- textAdornment : ( ) => combineAdornments ( [ adornments . advanced , adornments . reload ] ) ,
7241
- } ,
7242
7229
//#region cat:general
7243
7230
locale : {
7244
7231
type : "select" ,
@@ -7307,6 +7294,18 @@ const featInfo = {
7307
7294
advanced : true ,
7308
7295
textAdornment : ( ) => combineAdornments ( [ adornments . advanced , adornments . reload ] ) ,
7309
7296
} ,
7297
+ initTimeout : {
7298
+ type : "number" ,
7299
+ category : "plugins" ,
7300
+ supportedSites : [ "ytm" , "yt" ] ,
7301
+ min : 3 ,
7302
+ max : 30 ,
7303
+ default : 8 ,
7304
+ step : 0.1 ,
7305
+ unit : "s" ,
7306
+ advanced : true ,
7307
+ textAdornment : ( ) => combineAdornments ( [ adornments . advanced , adornments . reload ] ) ,
7308
+ } ,
7310
7309
resetConfig : {
7311
7310
type : "button" ,
7312
7311
category : "general" ,
0 commit comments