Skip to content
This repository was archived by the owner on Mar 9, 2023. It is now read-only.

Commit e498848

Browse files
committed
2.2.0: more i18n, autoplay fix, etc.
1 parent ed7d22e commit e498848

File tree

3 files changed

+129
-23
lines changed

3 files changed

+129
-23
lines changed

LOCALIZATION.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Localization
2+
Watch9 Reconstruct relies on custom strings not gathered from InnerTube, and this can cause the following for languages currently not implemented:
3+
4+
* "Subscribers" suffix not being removed from subscriber count
5+
* Strings being in English
6+
7+
If you want to help me out and add more languages, you're in the right place! Just read the rest of this document.
8+
9+
### *Note: You'll need a GitHub account to do this.*
10+
11+
## 1. Fork the repository
12+
Near the top right of this repository's GitHub page, you'll find a "Fork" button. Click that, and it'll create a copy of this repository on your account.
13+
14+
## 2. Add your language
15+
In `Watch9Reconstruct.user.js`, there is a constant variable at the beginning of the script called `w9ri18n`. This holds the localization strings.
16+
17+
**Things to keep in mind:**
18+
* `%s` is the indicator the code uses to put custom content there. This is used for example, by the publish date, which is `Published on %s` in English.
19+
* Those regexes are for matching strings from YouTube itself. Go in and get those from YouTube in your language.
20+
* The language indicator is the two-letter code that Google uses. A full list can be found [here](https://gist.github.com/JT5D/a2fdfefa80124a06f5a9).
21+
22+
## 3. Open a pull request
23+
Commit your changes to your fork of the repository, and open up a pull request in the main repository.

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
## ⚠ ONLY WORKS IN ENGLISH! ⚠
2-
## ⚠ PLEASE HELP TRANSLATE IF YOU CAN!
2+
## ⚠ PLEASE SEE [LOCALIZATION.MD](LOCALIZATION.md)
33

44
# Watch9 Reconstruct
55
Introduced in 2017, Watch9 was the Watch page's layout up until 2019. This userscript aims to restore that layout.

Watch9Reconstruct.user.js

+105-22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// ==UserScript==
22
// @name Watch9 Reconstruct
3-
// @version 2.1.2
3+
// @version 2.2.0
44
// @description Restores the old watch layout from before 2019
55
// @author Aubrey P.
66
// @icon https://www.youtube.com/favicon.ico
@@ -18,16 +18,49 @@ const w9rOptions = {
1818

1919
/**
2020
* Localization strings.
21+
*
22+
* See LOCALIZATION.md in the GitHub repo.
2123
*/
2224
const w9ri18n = {
2325
en: {
24-
subSuffixMatch: /( subscribers)|( subscriber)/, // Regex for isolating subscriber count
25-
subCntZero: "No", // When the author has 0 subscribers
26-
nonPublishMatch: /(Premier)|(Stream)|(Start)/, // Match to determine if a video was normally uploaded
27-
publishedOn: "Published on %s", // Self explanatory
26+
subSuffixMatch: /( subscribers)|( subscriber)/,
27+
subCntZero: "No",
28+
nonPublishMatch: /(Premier)|(Stream)|(Start)/,
29+
publishedOn: "Published on %s",
30+
uploadedOn: "Uploaded on %s",
2831
upNext: "Up next",
2932
autoplay: "Autoplay",
3033
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: /( subskrybentów)|( subskrybent)/,
47+
subCntZero: "No",
48+
nonPublishMatch: /(Data premiery: )|(adawane na żywo )|(Transmisja zaczęła się )/,
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: /(na)|( subscribers)|( subscriber)|(\s)/g,
57+
subCntZero: "0",
58+
nonPublishMatch: /(simula)/,
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."
3164
}
3265
};
3366

@@ -71,19 +104,20 @@ function getString(string, hl = "en") {
71104
}
72105

73106
/**
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.
75108
*
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.
78112
* @returns {string}
79113
*/
80-
function formatUploadDate(dateStr, hl = "en") {
114+
function formatUploadDate(dateStr, isPublic, hl = "en") {
81115
var nonPublishMatch = getString("nonPublishMatch", hl);
82-
var publishedOn = getString("publishedOn", hl);
116+
var string = isPublic ? getString("publishedOn", hl) : getString("uploadedOn", hl);
83117
if (nonPublishMatch.test(dateStr)) {
84118
return dateStr;
85119
} else {
86-
return publishedOn.replace("%s", dateStr);
120+
return string.replace("%s", dateStr);
87121
}
88122
}
89123

@@ -216,6 +250,25 @@ function removeBloatButtons() {
216250
}
217251
}
218252

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+
219272
/**
220273
* Build the classic compact autoplay renderer.
221274
*
@@ -227,7 +280,21 @@ function buildAutoplay() {
227280

228281
const watchFlexy = document.querySelector("ytd-watch-flexy");
229282
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+
})();
231298
const language = yt.config_.HL ?? "en";
232299
const autoplayStub = `
233300
<ytd-compact-autoplay-renderer class="style-scope ytd-watch-next-secondary-results-renderer">
@@ -241,6 +308,8 @@ function buildAutoplay() {
241308
</ytd-compact-autoplay-renderer>
242309
`;
243310

311+
console.log(sidebarItemData);
312+
244313
// Insert the autoplay stub.
245314
sidebarItems.insertAdjacentHTML("afterbegin", autoplayStub);
246315
var autoplayRenderer = sidebarItems.querySelector("ytd-compact-autoplay-renderer");
@@ -252,12 +321,21 @@ function buildAutoplay() {
252321
// Add event listener to toggle
253322
autoplayRenderer.querySelector("#toggle").addEventListener("click", clickAutoplay);
254323

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);
261339

262340
// Add the interval to update toggle if it isn't already.
263341
if (!watchFlexy.getAttribute("autoplay-interval-active")) {
@@ -292,11 +370,11 @@ function buildAutoplay() {
292370
viewCount.removeAttribute("small");
293371

294372
// Publish date
295-
var newUploadDate = formatUploadDate(primaryInfo.data.dateText.simpleText, language);
373+
var newUploadDate = formatUploadDate(primaryInfo.data.dateText.simpleText, isVideoPublic(), language);
296374
uploadDate.innerText = newUploadDate;
297375

298376
// Sub count
299-
var newSubCount = formatSubCount(secondaryInfo.data.owner.videoOwnerRenderer.subscriberCountText.simpleText);
377+
var newSubCount = formatSubCount(secondaryInfo.data.owner.videoOwnerRenderer.subscriberCountText.simpleText, language);
300378
var w9rSubCount = document.createElement("yt-formatted-string");
301379
w9rSubCount.classList.add("style-scope", "deemphasize");
302380
w9rSubCount.text = {
@@ -325,7 +403,7 @@ function updateWatch9() {
325403
const language = yt.config_.HL ?? "en";
326404

327405
// Publish date
328-
var newUploadDate = formatUploadDate(primaryInfo.data.dateText.simpleText, language);
406+
var newUploadDate = formatUploadDate(primaryInfo.data.dateText.simpleText, isVideoPublic(), language);
329407
uploadDate.innerText = newUploadDate;
330408

331409
// Sub count
@@ -435,8 +513,13 @@ document.addEventListener("DOMContentLoaded", function tmp() {
435513
margin-left: 8px;
436514
}
437515
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 > * {
439517
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;
440523
}
441524
</style>
442525
`);

0 commit comments

Comments
 (0)