Adds an RSS feed button to YouTube channels next to the subscribe button. Continuation of script by Doodles: https://greasyfork.org/en/scripts/1760-youtube-rss-feed
// ==UserScript== // @name YouTube RSS Feed // @namespace https://greasyfork.org/en/users/4612-gdorn // @author GDorn // @version 1 // @description Adds an RSS feed button to YouTube channels next to the subscribe button. Continuation of script by Doodles: https://greasyfork.org/en/scripts/1760-youtube-rss-feed // @icon http://i.imgur.com/Ty5HNbT.png // @icon64 http://i.imgur.com/1FfVvNr.png // @match *://www.youtube.com/* // @match *://youtube.com/* // @run-at document-end // @grant none // @require https://code.jquery.com/jquery-3.3.1.min.js // ==/UserScript== $(function () { "use strict"; $(document).ready(addRssFeedSupport); document.body.addEventListener("iron-a11y-announcer", function (event) { addRssFeedSupport(false); }); document.body.addEventListener("meta-contents", function(event) { addRssFeedSupport(true); }); }); function addRssFeedSupport(firstLoad) { console.log("Adding RSS Feed Support"); if (isPlaylistPage()) { console.log("Playlist Page"); waitForElement("meta-contents", function () { var playlistFeedLink = getPlaylistFeed(getPlaylistId()); console.log("RSS link:", playlistFeedLink); addRssLink(playlistFeedLink); addRssButtonPlaylist(playlistFeedLink); }, 330); } else if (isVideoPage()) { console.log("Video Page"); waitForElement(getChannelIdFromVideoPage, function () { var channelId = getChannelIdFromVideoPage(); console.log("Channel ID:", channelId); removeRssLink(); addRssLink(channelId); addRssButton(channelId); }, 330); } else if (isChannelPage()) { console.log("Channel Page"); waitForElement("subscribe-button", function () { var channelId = getChannelIdFromChannelPage(firstLoad); if (channelId === false) { removeRssLink(); addRefreshButton(); } else { var channelFeedLink = getChannelFeed(channelId); removeRssLink(); addRssLink(channelId); addRssButton(channelId); } }, 330); } } function isPlaylistPage() { return document.URL.indexOf("/playlist?list=") !== -1; } function isVideoPage() { return document.URL.indexOf("/watch") !== -1 && document.URL.indexOf("v=") !== -1; } function isChannelPage() { return $("#channel-header").length > 0; } function getPlaylistId() { var playlistId = document.URL.split("list=")[1].split("&")[0]; if (!playlistId.startsWith("PL")) { playlistId = "PL" + playlistId; } return playlistId; } function getChannelIdFromVideoPage() { /** * Update #meta-contents to point to whatever unique-looking element contains a link to the creator's channel page. Can be an outer container. **/ var links = $("#meta-contents").find("a"); console.log("Possible links to channel:", links); for (var i = 0; i < links.length; i++){ var href = links[i].href; if (href.indexOf('/channel/') !== -1){ return href.split('/channel/')[1]; } } return False; } function getChannelIdFromChannelPage(firstLoad) { if (document.URL.indexOf("/channel/") !== -1) { return document.URL.split("/channel/")[1].split("/")[0].split("?")[0]; } else if (firstLoad) { return $("meta[property='og:url']").attr("content").split("/channel/")[1]; } else { return false; } } function getChannelFeed(channelId) { return "http://www.youtube.com/feeds/videos.xml?channel_id=" + channelId; } function getPlaylistFeed(playlistId) { return "http://www.youtube.com/feeds/videos.xml?playlist_id=" + playlistId; } function addRssLink(channelId) { var link = getChannelFeed(channelId); $("head").append('<link rel="alternate" type="application/rss+xml" title="RSS" href="' + link + '" />'); } function removeRssLink() { if ($("link[type='application/rss+xml']").length > 0) { $("link[type='application/rss+xml']").remove(); } } function waitForElement(finderFunction, callbackFunction, intervalLength = 330) { var waitCount = 15000 / intervalLength; // wait 15 seconds maximum var wait = setInterval(function () { waitCount--; if (finderFunction) { callbackFunction(); clearInterval(wait); } else if (waitCount <= 0) { console.log("Never found anything with finder function"); clearInterval(wait); } else { console.log("Element not (yet) found"); } }, intervalLength); } function addRssButton(channelId) { var link = getChannelFeed(channelId); if ($("#rssSubButton").length > 0) { $("#rssSubButton").remove(); } var selector = "a[href*='/channel/" + channelId + "']"; console.log("Selector to find targets:", selector); var targets = $(selector); console.log("Targets for adding RSS button:", targets); targets.prepend(makeRssButton(link)); } function addRssButtonPlaylist(link) { if ($("#rssSubButton").length === 0) { $("#owner-container > #button") .css({ "display": "flex", "flex-flow": "nowrap", "height": "37px" }) .prepend(makeRssButton(link)); } } function makeRssButton(link) { return $("<a>RSS</a>") .attr("id", "rssSubButton") .attr("target", "_blank") .attr("href", link) .attr("class", 'ytd-channel-name') .css({'padding-right': '10px'}) .css({'padding-left': '10px'}); // .css({ // "background-color": "#fd9b12", // "border-radius": "3px", // "padding": "10px 16px", // "color": "#ffffff", // "font-size": "14px", // "text-decoration": "none", // "text-transform": "uppercase", // "margin-right": "5px" // } // ); // those lines for debugging } function addRefreshButton() { var refreshButton = $("<a>Refresh</a>") .attr("id", "rssSubButton") .attr("href", "#") .css({ "background-color": "#fd9b12", "border-radius": "3px", "padding": "10px 16px", "color": "#ffffff", "font-size": "14px", "text-decoration": "none", "text-transform": "uppercase", "margin-right": "5px" }); $(refreshButton).click(function (e) { e.preventDefault(); var r = confirm("Due to how YouTube load pages, there isn't a reliable way to get channel" + " IDs from channel pages if you've navigated to them from another YouTube page." + " The solution is to reload the page.\n\nWould you like to reload the page?"); if (r === true) { window.location.reload(); } }); if ($("#rssSubButton").length > 0) { $("#rssSubButton").remove(); } $("#subscribe-button") .css({ "display": "flex", "flex-flow": "nowrap", "height": "37px" }) .prepend(refreshButton); }