!!! NEVER PASTE IN THE BROWSER’S CONSOLE CODE THAT YOU DON’T READ OR DON’T UNDERSTAND !!!
Go to your subscriptions page, scroll to the end of the page, so it loads everything, open the Inspector, go to the Console tab and paste the code below. It should load for a while, then download a file called youtube_subs.opml
PS: I don’t remember where I stole the code from, but it works, and that’s what matters.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
(async () => {
const dialog = document.createElement("dialog");
const label = document.createElement("label");
const progress = document.createElement("progress");
dialog.style.cssText = "display: flex; flex-direction: column; gap: 15px; padding: 20px;";
dialog.appendChild(label);
dialog.appendChild(progress);
document.querySelector("ytd-app").appendChild(dialog);
dialog.showModal();
label.innerText = "Loading subscriptions...";
const content = document.getElementById("content");
let contentH;
do {
contentH = content.offsetHeight;
window.scrollBy(0, 100000);
await new Promise((r) => setTimeout(r, 500));
} while (content.querySelector("#spinnerContainer.active") != null || content.offsetHeight > contentH);
try {
const channelElements = [...content.querySelectorAll("ytd-browse:not([hidden]) #main-link.channel-link")];
progress.max = channelElements.length;
progress.value = 0;
const channels = [];
const escapeHTMLPolicy = window.chrome ? trustedTypes.createPolicy("m", { createHTML: (string) => string, }) : null;
for (e of channelElements) {
label.innerText = `Fetching URLS... (${progress.value}/${progress.max})`;
try {
const channelName = e.querySelector("yt-formatted-string.ytd-channel-name").innerText;
const channelReq = await fetch(e.href);
if (!channelReq.ok) {
console.error(`Couldn't fetch channel page for ${channelName}`);
continue;
}
let channelHTML = await channelReq.text();
if (window.chrome) channelHTML = escapeHTMLPolicy.createHTML(channelHTML);
const channelPageDoc = Document.parseHTMLUnsafe(channelHTML);
const links = channelPageDoc.querySelectorAll("body > link[rel=alternate], body > link[rel=canonical]");
const channelIdMatch = [...links].map((e) => e.href.match("/channel/([a-zA-Z0-9_-]+?)$")).find((e) => e != null);
if (channelIdMatch == null) {
console.error(`Couldn't find channel id for ${channelName}`);
continue;
}
channels.push([`https://www.youtube.com/feeds/videos.xml?channel_id=${channelIdMatch[1]}`, channelName, e.href]);
} finally {
progress.value++;
progress.replaceWith(progress);
}
}
if (channelElements.length == 0) alert("Couldn't find any subscriptions");
const missedChannels = channelElements.length - channels.length;
if (missedChannels > 0)
alert(`${missedChannels} channel${missedChannels > 1 ? "s" : ""} couldn't be fetched. Check the console for more info.`);
const escapeXML = (str) =>
str.replace(/[<>&'"]/g, (c) => ({ "<": "<", ">": ">", "&": "&", "'": "'", '"': """ }[c]));
if (channels.length > 0) {
// console.log(channels.map(([feed]) => feed).join("\n")); // uncomment this if you want to see what links it detected
let opmlText = `<?xml version="1.0" encoding="UTF-8"?>\n<opml version="1.0">\n\t<head>\n\t\t<title>YouTube Subscriptions as RSS</title>\n\t</head>\n\t<body>\n\t\t<outline text="YouTube Subscriptions">${channels
.map(
([feed, channelName, channelUrl]) =>
`\n\t\t\t<outline type="rss" text="${escapeXML(channelName)}" title="${escapeXML(
channelName
)}" xmlUrl="${feed}" htmlUrl="${channelUrl}"/>`
)
.join("")}\n\t\t</outline>\n\t</body>\n</opml>`;
const url = window.URL.createObjectURL(new Blob([opmlText], { type: "text/plain" }));
const anchorTag = document.createElement("a");
anchorTag.setAttribute("download", "youtube_subs.opml");
anchorTag.setAttribute("href", url);
anchorTag.dataset.downloadurl = `text/plain:youtube_subs.opml:${url}`;
anchorTag.click();
}
} catch (e) {
console.error(e);
alert("Something went wrong. Check the console for more info.");
} finally {
dialog.close();
dialog.remove();
}
})();
|
Source of the featured image: Uniting Nations - Out of Touch