1
1
// ==UserScript==
2
2
// @name Watch9 Reconstruct
3
- // @version 2.1.2
3
+ // @version 2.2.0
4
4
// @description Restores the old watch layout from before 2019
5
5
// @author Aubrey P.
6
6
// @icon https://www.youtube.com/favicon.ico
@@ -18,16 +18,49 @@ const w9rOptions = {
18
18
19
19
/**
20
20
* Localization strings.
21
+ *
22
+ * See LOCALIZATION.md in the GitHub repo.
21
23
*/
22
24
const w9ri18n = {
23
25
en : {
24
- subSuffixMatch : / ( s u b s c r i b e r s ) | ( s u b s c r i b e r ) / , // Regex for isolating subscriber count
25
- subCntZero : "No" , // When the author has 0 subscribers
26
- nonPublishMatch : / ( P r e m i e r ) | ( S t r e a m ) | ( S t a r t ) / , // Match to determine if a video was normally uploaded
27
- publishedOn : "Published on %s" , // Self explanatory
26
+ subSuffixMatch : / ( s u b s c r i b e r s ) | ( s u b s c r i b e r ) / ,
27
+ subCntZero : "No" ,
28
+ nonPublishMatch : / ( P r e m i e r ) | ( S t r e a m ) | ( S t a r t ) / ,
29
+ publishedOn : "Published on %s" ,
30
+ uploadedOn : "Uploaded on %s" ,
28
31
upNext : "Up next" ,
29
32
autoplay : "Autoplay" ,
30
33
autoplayTip : "When autoplay is enabled, a suggested video will automatically play next."
34
+ } ,
35
+ ja : {
36
+ subSuffixMatch : / ( チ ャ ン ネ ル 登 録 者 数 ) | ( 人 ) / g,
37
+ subCntZero : "0" ,
38
+ nonPublishMatch : / ( 公 開 済 ) | ( 開 始 済 ) / g,
39
+ publishedOn : "%s に公開" ,
40
+ uploadedOn : "%s にアップロード" ,
41
+ upNext : "自動再生" ,
42
+ autoplay : "次の動画" ,
43
+ autoplayTip : "自動再生を有効にすると、関連動画が自動的に再生されます。"
44
+ } ,
45
+ pl : {
46
+ subSuffixMatch : / ( s u b s k r y b e n t ó w ) | ( s u b s k r y b e n t ) / ,
47
+ subCntZero : "No" ,
48
+ nonPublishMatch : / ( D a t a p r e m i e r y : ) | ( a d a w a n e n a ż y w o ) | ( T r a n s m i s j a z a c z ę ł a s i ę ) / ,
49
+ publishedOn : "Published on %s" ,
50
+ uploadedOn : "Uploaded on %s" ,
51
+ upNext : "Up next" ,
52
+ autoplay : "Autoplay" ,
53
+ autoplayTip : "When autoplay is enabled, a suggested video will automatically play next."
54
+ } ,
55
+ fil : {
56
+ subSuffixMatch : / ( n a ) | ( s u b s c r i b e r s ) | ( s u b s c r i b e r ) | ( \s ) / g,
57
+ subCntZero : "0" ,
58
+ nonPublishMatch : / ( s i m u l a ) / ,
59
+ publishedOn : "Na-publish noong %s" ,
60
+ uploadedOn : "Na-upload noong %s" ,
61
+ upNext : "Susunod" ,
62
+ autoplay : "I-autoplay" ,
63
+ autoplayTip : "Kapag naka-enable ang autoplay, awtomatikong susunod na magpe-play ang isang iminumungkahing video."
31
64
}
32
65
} ;
33
66
@@ -71,19 +104,20 @@ function getString(string, hl = "en") {
71
104
}
72
105
73
106
/**
74
- * Format upload date string to include "Published on" if applicable.
107
+ * Format upload date string to include "Published on" or "Uploaded on" if applicable.
75
108
*
76
- * @param {string } dateStr dateText from InnerTube ("Sep 13, 2022", "Premiered 2 hours ago", etc.)
77
- * @param {string } hl Language to use.
109
+ * @param {string } dateStr dateText from InnerTube ("Sep 13, 2022", "Premiered 2 hours ago", etc.)
110
+ * @param {boolean } isPublic Is the video public?
111
+ * @param {string } hl Language to use.
78
112
* @returns {string }
79
113
*/
80
- function formatUploadDate ( dateStr , hl = "en" ) {
114
+ function formatUploadDate ( dateStr , isPublic , hl = "en" ) {
81
115
var nonPublishMatch = getString ( "nonPublishMatch" , hl ) ;
82
- var publishedOn = getString ( "publishedOn" , hl ) ;
116
+ var string = isPublic ? getString ( "publishedOn" , hl ) : getString ( "uploadedOn ", hl ) ;
83
117
if ( nonPublishMatch . test ( dateStr ) ) {
84
118
return dateStr ;
85
119
} else {
86
- return publishedOn . replace ( "%s" , dateStr ) ;
120
+ return string . replace ( "%s" , dateStr ) ;
87
121
}
88
122
}
89
123
@@ -216,6 +250,25 @@ function removeBloatButtons() {
216
250
}
217
251
}
218
252
253
+ /**
254
+ * Is the current video public? Or is it unlisted/private?
255
+ *
256
+ * @returns {boolean }
257
+ */
258
+ function isVideoPublic ( ) {
259
+ const primaryInfo = document . querySelector ( "ytd-video-primary-info-renderer" ) ;
260
+ if ( primaryInfo . data . badges == null ) return true ;
261
+ const badges = primaryInfo . data . badges ;
262
+
263
+ for ( var i = 0 ; i < badges . length ; i ++ ) {
264
+ var iconType = badges [ i ] . metadataBadgeRenderer . icon . iconType ;
265
+ if ( iconType == "PRIVACY_UNLISTED" || iconType == "PRIVACY_PRIVATE" ) {
266
+ return false ;
267
+ }
268
+ }
269
+ return true ;
270
+ }
271
+
219
272
/**
220
273
* Build the classic compact autoplay renderer.
221
274
*
@@ -227,7 +280,21 @@ function buildAutoplay() {
227
280
228
281
const watchFlexy = document . querySelector ( "ytd-watch-flexy" ) ;
229
282
const secondaryResults = watchFlexy . querySelector ( "ytd-watch-next-secondary-results-renderer" ) ;
230
- const sidebarItems = secondaryResults . querySelector ( "#items" ) ;
283
+ const sidebarItems = ( ( ) => {
284
+ var a ;
285
+ if ( a = secondaryResults . querySelector ( "#contents.ytd-item-section-renderer" ) ) {
286
+ return a ;
287
+ } else {
288
+ return secondaryResults . querySelector ( "#items.ytd-watch-next-secondary-results-renderer" ) ;
289
+ }
290
+ } ) ( ) ;
291
+ const sidebarItemData = ( ( ) => {
292
+ if ( secondaryResults . data . results [ 0 ] . relatedChipCloudRenderer ) {
293
+ return secondaryResults . data . results [ 1 ] . itemSectionRenderer . contents ;
294
+ } else {
295
+ return secondaryResults . data . results ;
296
+ }
297
+ } ) ( ) ;
231
298
const language = yt . config_ . HL ?? "en" ;
232
299
const autoplayStub = `
233
300
<ytd-compact-autoplay-renderer class="style-scope ytd-watch-next-secondary-results-renderer">
@@ -241,6 +308,8 @@ function buildAutoplay() {
241
308
</ytd-compact-autoplay-renderer>
242
309
` ;
243
310
311
+ console . log ( sidebarItemData ) ;
312
+
244
313
// Insert the autoplay stub.
245
314
sidebarItems . insertAdjacentHTML ( "afterbegin" , autoplayStub ) ;
246
315
var autoplayRenderer = sidebarItems . querySelector ( "ytd-compact-autoplay-renderer" ) ;
@@ -252,12 +321,21 @@ function buildAutoplay() {
252
321
// Add event listener to toggle
253
322
autoplayRenderer . querySelector ( "#toggle" ) . addEventListener ( "click" , clickAutoplay ) ;
254
323
255
- // And finally, place the first video in the autoplay renderer.
256
- // Recommended list loading is kinda delayed,
257
- // so we wait for the first video renderer
258
- waitForElm ( "ytd-compact-video-renderer" , sidebarItems ) . then ( ( e ) => {
259
- autoplayRenderer . querySelector ( "#contents" ) . appendChild ( e ) ;
260
- } ) ;
324
+ // Copy first video from data into autoplay renderer
325
+ var firstVideo ;
326
+ for ( var i = 0 ; i < sidebarItemData . length ; i ++ ) {
327
+ if ( sidebarItemData [ i ] . compactVideoRenderer ) {
328
+ firstVideo = sidebarItemData [ i ] ;
329
+ break ;
330
+ }
331
+ }
332
+
333
+ var videoRenderer = document . createElement ( "ytd-compact-video-renderer" ) ;
334
+ videoRenderer . data = firstVideo . compactVideoRenderer ;
335
+ videoRenderer . classList . add ( "style-scope" , "ytd-compact-autoplay-renderer" )
336
+ videoRenderer . setAttribute ( "lockup" , "true" ) ;
337
+ videoRenderer . setAttribute ( "thumbnail-width" , "168" ) ;
338
+ autoplayRenderer . querySelector ( "#contents" ) . appendChild ( videoRenderer ) ;
261
339
262
340
// Add the interval to update toggle if it isn't already.
263
341
if ( ! watchFlexy . getAttribute ( "autoplay-interval-active" ) ) {
@@ -292,11 +370,11 @@ function buildAutoplay() {
292
370
viewCount . removeAttribute ( "small" ) ;
293
371
294
372
// Publish date
295
- var newUploadDate = formatUploadDate ( primaryInfo . data . dateText . simpleText , language ) ;
373
+ var newUploadDate = formatUploadDate ( primaryInfo . data . dateText . simpleText , isVideoPublic ( ) , language ) ;
296
374
uploadDate . innerText = newUploadDate ;
297
375
298
376
// Sub count
299
- var newSubCount = formatSubCount ( secondaryInfo . data . owner . videoOwnerRenderer . subscriberCountText . simpleText ) ;
377
+ var newSubCount = formatSubCount ( secondaryInfo . data . owner . videoOwnerRenderer . subscriberCountText . simpleText , language ) ;
300
378
var w9rSubCount = document . createElement ( "yt-formatted-string" ) ;
301
379
w9rSubCount . classList . add ( "style-scope" , "deemphasize" ) ;
302
380
w9rSubCount . text = {
@@ -325,7 +403,7 @@ function updateWatch9() {
325
403
const language = yt . config_ . HL ?? "en" ;
326
404
327
405
// Publish date
328
- var newUploadDate = formatUploadDate ( primaryInfo . data . dateText . simpleText , language ) ;
406
+ var newUploadDate = formatUploadDate ( primaryInfo . data . dateText . simpleText , isVideoPublic ( ) , language ) ;
329
407
uploadDate . innerText = newUploadDate ;
330
408
331
409
// Sub count
@@ -435,8 +513,13 @@ document.addEventListener("DOMContentLoaded", function tmp() {
435
513
margin-left: 8px;
436
514
}
437
515
438
- ytd-watch-next-secondary-results-renderer #contents > .ytd-item-section-renderer:first-child {
516
+ ytd-watch-next-secondary-results-renderer #contents.ytd-item-section-renderer > * {
439
517
margin-top: 0 !important;
518
+ margin-bottom: var(--ytd-item-section-item-margin,16px);
519
+ }
520
+
521
+ ytd-watch-next-secondary-results-renderer #contents.ytd-item-section-renderer > ytd-compact-video-renderer:first-of-type {
522
+ display: none !important;
440
523
}
441
524
</style>
442
525
` ) ;
0 commit comments