Skip to content

Instantly share code, notes, and snippets.

@mkwsnyder
Created December 5, 2023 19:38
Show Gist options
  • Save mkwsnyder/653f1e8df008af4c262bf296daa5d471 to your computer and use it in GitHub Desktop.
Save mkwsnyder/653f1e8df008af4c262bf296daa5d471 to your computer and use it in GitHub Desktop.
YouTube RSS Feed Generator
// @ts-nocheck
/**
* Build an RSS Feed from your YouTube Subscriptions
*
* It runs a little slow to prevent YouTube from blocking the requests.
* The entire process will take as many seconds as you have subscriptions (you can shorten this by changing the delay in getRssFeeds()).
*
* How to use:
* 1. Go to https://www.youtube.com/ (while signed in
* 2. Under Subscriptions click "Show more"
* 3. Open the console (F12)
* 4. Paste this script and run it
* 5. A file named "youtube-feed.opml" will be downloaded
*/
async function buildRssFeed() {
let channels = getChannelList();
await getRssFeeds(channels);
let rss = channelsToRssFeed(channels);
writeRssToFile(rss);
}
function getChannelList() {
let channels = [];
for (let e of Array.from(
document.querySelectorAll('.yt-simple-endpoint.style-scope.ytd-guide-entry-renderer'),
).filter((e) => e.href.includes('@'))) {
channels.push({
title: e.title,
htmlUrl: e.href,
htmlUrlImg: e.querySelector('img').src,
});
}
return channels;
}
async function getRssFeeds(channels) {
const delay = 1000;
let index = 0;
const processNextChannel = () => {
if (index < channels.length) {
return getFeed(channels[index++])
.then(() => {
return new Promise((resolve) => setTimeout(resolve, delay));
})
.then(processNextChannel);
} else return Promise.resolve();
};
return processNextChannel();
}
async function getFeed(channel) {
return fetch(channel.htmlUrl).then(async (response) => {
let html = await response.text();
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
for (let arrScripts = doc.getElementsByTagName('script'), i = 0; i < arrScripts.length; i++) {
if (arrScripts[i].textContent.indexOf('externalId') != -1) {
let channelId = arrScripts[i].textContent.match(/\"externalId\"\s*\:\s*\"(.*?)\"/)[1];
let channelRss = 'https://www.youtube.com/feeds/videos.xml?channel_id=' + channelId;
let channelTitle = doc.title.match(/\(?\d*\)?\s?(.*?)\s\-\sYouTube/)[1];
console.log(`Acquired RSS feed for '${channelTitle}' (\n${channelRss})`);
channel.xmlUrl = channelRss;
break;
}
}
});
}
function channelsToRssFeed(channels) {
return `<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
<head>
<title>Script Export</title>
</head>
<body>
${channels.map(channelToString).join('\n')}
</body>
</opml>`;
}
function channelToString(channel) {
return ` <outline text="${channel.title}" type="rss" xmlUrl="${channel.xmlUrl}" htmlUrl="${channel.htmlUrl}" htmlUrlImg="${channel.htmlUrlImg}" />`;
}
function writeRssToFile(rss) {
const blob = new Blob([rss], { type: 'text/plain;charset=utf-8' });
const link = document.createElement('a');
link.download = 'youtube-feed.opml';
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
buildRssFeed();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment