YouTube RSS Feed

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