Youtube Logo - Link to subscriptions feed

Change YouTube logo link to user's subscription feed instead of homepage, when logged in, for 2017 and later YouTube layout.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name            Youtube Logo - Link to subscriptions feed
// @namespace       Youtube Logo - Link to subscriptions feed
// @description     Change YouTube logo link to user's subscription feed instead of homepage, when logged in, for 2017 and later YouTube layout.
// @version         2.1.5
// @include         *://*.youtube.tld/*
// @supportURL      https://greasyfork.org/en/scripts/13582/feedback
// @author          aciid
// @license         MIT
// @run-at          document-start
// ==/UserScript==

(function() {
    "use strict";

    var SUBSCRIPTIONS_PATH = "/feed/subscriptions";
    var SUBSCRIPTIONS_BROWSE_ID = "FEsubscriptions";
    var DEFAULT_SUBSCRIPTIONS_NAVIGATION_ENDPOINT = {
        clickTrackingParams: "",
        commandMetadata: {
            webCommandMetadata: {
                url: SUBSCRIPTIONS_PATH,
                webPageType: "WEB_PAGE_TYPE_BROWSE",
                rootVe: 96368,
                apiUrl: "/youtubei/v1/browse"
            }
        },
        browseEndpoint: {
            browseId: SUBSCRIPTIONS_BROWSE_ID
        }
    };
    var LOGO_SELECTOR = "a#logo[href]";
    var SUBSCRIPTIONS_ENDPOINT_SELECTOR = "a#endpoint[href]";
    var ORIGINAL_HREF_ATTRIBUTE = "data-ytltsf-original-href";
    var updateScheduled = false;
    var observedMasthead = null;
    var cachedSubscriptionsNavigationEndpoint = null;
    var bootstrapObserver = new MutationObserver(ScheduleUpdate);
    var mastheadObserver = new MutationObserver(ScheduleUpdate);

    function NormalizePath(pathname) {
        return pathname.replace(/\/+$/, "") || "/";
    }

    function IsSubscriptionsUrl(url) {
        try {
            return NormalizePath(new URL(url, location.origin).pathname) === SUBSCRIPTIONS_PATH;
        } catch (error) {
            return false;
        }
    }

    function IsLoggedIn() {
        return document.querySelector("button#avatar-btn") !== null;
    }

    function IsTopbarLogo(node) {
        return node instanceof HTMLAnchorElement &&
            node.id === "logo" &&
            node.closest("ytd-masthead, ytd-topbar-logo-renderer, ytd-yoodle-renderer") !== null;
    }

    function FindLogoFromEvent(event) {
        if (typeof event.composedPath === "function") {
            var path = event.composedPath();
            for (var i = 0; i < path.length; i++) {
                var node = path[i];
                if (IsTopbarLogo(node)) {
                    return node;
                }
            }
        }

        if (event.target instanceof Element) {
            var logo = event.target.closest(LOGO_SELECTOR);
            if (IsTopbarLogo(logo)) {
                return logo;
            }
        }

        return null;
    }

    function IsPlainLeftClick(event) {
        return event.button === 0 &&
            !event.defaultPrevented &&
            !event.altKey &&
            !event.ctrlKey &&
            !event.metaKey &&
            !event.shiftKey;
    }

    function FindSubscriptionsEndpoint() {
        var endpoints = document.querySelectorAll(SUBSCRIPTIONS_ENDPOINT_SELECTOR);

        for (var i = 0; i < endpoints.length; i++) {
            if (endpoints[i] instanceof HTMLAnchorElement && IsSubscriptionsUrl(endpoints[i].href)) {
                return endpoints[i];
            }
        }

        return null;
    }

    function DeepClone(value) {
        if (typeof structuredClone === "function") {
            return structuredClone(value);
        }

        return JSON.parse(JSON.stringify(value));
    }

    function GetRendererData(element) {
        if (element === null || element === undefined) {
            return null;
        }

        return element.data || element.polymerController?.data || element.inst?.data || null;
    }

    function FindSubscriptionsNavigationEndpointInData() {
        var renderers = document.querySelectorAll("ytd-guide-entry-renderer, ytd-guide-collapsible-section-entry-renderer, ytd-mini-guide-entry-renderer");

        for (var i = 0; i < renderers.length; i++) {
            var data = GetRendererData(renderers[i]);
            var endpoint = data?.navigationEndpoint || data?.endpoint || null;

            if (endpoint?.browseEndpoint?.browseId === SUBSCRIPTIONS_BROWSE_ID ||
                NormalizePath(endpoint?.commandMetadata?.webCommandMetadata?.url || "") === SUBSCRIPTIONS_PATH) {
                return endpoint;
            }
        }

        return null;
    }

    function GetSubscriptionsNavigationEndpoint() {
        var discoveredEndpoint = FindSubscriptionsNavigationEndpointInData();

        if (discoveredEndpoint !== null) {
            cachedSubscriptionsNavigationEndpoint = DeepClone(discoveredEndpoint);
        }

        return DeepClone(cachedSubscriptionsNavigationEndpoint || DEFAULT_SUBSCRIPTIONS_NAVIGATION_ENDPOINT);
    }

    function GetNavigationTargets() {
        var app = document.querySelector("ytd-app");
        var targets = [app];

        if (app !== null) {
            targets.push(app.polymerController, app.inst);
        }

        return targets.filter(function(target, index) {
            return target !== null && target !== undefined && targets.indexOf(target) === index;
        });
    }

    function HandleSubscriptionsNavigationWithApp() {
        var targets = GetNavigationTargets();
        var endpoint = GetSubscriptionsNavigationEndpoint();
        var requestFactories = [
            function() {
                return {
                    type: 0,
                    command: DeepClone(endpoint)
                };
            },
            function() {
                return {
                    type: 0,
                    endpoint: DeepClone(endpoint),
                    command: DeepClone(endpoint)
                };
            }
        ];

        for (var i = 0; i < targets.length; i++) {
            var target = targets[i];

            for (var j = 0; j < requestFactories.length; j++) {
                try {
                    if (typeof target.handleNavigate === "function") {
                        target.handleNavigate(requestFactories[j]());
                        return true;
                    }
                } catch (error) {
                    // Try the next request shape or target.
                }
            }
        }

        return false;
    }

    function NavigateToSubscriptions(attempt) {
        var endpoint = FindSubscriptionsEndpoint();

        if (endpoint !== null) {
            endpoint.click();
            return;
        }

        if (attempt === 0 || attempt === 10) {
            HandleSubscriptionsNavigationWithApp();
        }

        if (attempt < 20 && NormalizePath(location.pathname) !== SUBSCRIPTIONS_PATH) {
            requestAnimationFrame(function() {
                NavigateToSubscriptions(attempt + 1);
            });
        }
    }

    function UpdateLogoHref(logo, loggedIn) {
        if (!logo.hasAttribute(ORIGINAL_HREF_ATTRIBUTE)) {
            var originalHref = logo.getAttribute("href");

            if (originalHref !== null) {
                logo.setAttribute(ORIGINAL_HREF_ATTRIBUTE, originalHref);
            }
        }

        if (loggedIn) {
            if (!IsSubscriptionsUrl(logo.getAttribute("href") || "")) {
                logo.setAttribute("href", SUBSCRIPTIONS_PATH);
            }

            return;
        }

        if (logo.hasAttribute(ORIGINAL_HREF_ATTRIBUTE)) {
            logo.setAttribute("href", logo.getAttribute(ORIGINAL_HREF_ATTRIBUTE));
        }
    }

    function UpdateLogos() {
        updateScheduled = false;
        RefreshObservedMasthead();
        GetSubscriptionsNavigationEndpoint();

        var logos = Array.from(document.querySelectorAll(LOGO_SELECTOR)).filter(IsTopbarLogo);
        if (logos.length === 0) {
            return;
        }

        var loggedIn = IsLoggedIn();

        logos.forEach(function(logo) {
            UpdateLogoHref(logo, loggedIn);
        });
    }

    function RefreshObservedMasthead() {
        var nextMasthead = document.querySelector("#masthead-container") || document.querySelector("ytd-masthead");

        if (nextMasthead === observedMasthead) {
            return;
        }

        mastheadObserver.disconnect();
        observedMasthead = nextMasthead;

        if (observedMasthead !== null) {
            bootstrapObserver.disconnect();
            mastheadObserver.observe(observedMasthead, {
                childList: true,
                subtree: true
            });
        }
    }

    function ScheduleUpdate() {
        if (updateScheduled) {
            return;
        }

        updateScheduled = true;
        requestAnimationFrame(UpdateLogos);
    }

    function OnDocumentClick(event) {
        var logo = FindLogoFromEvent(event);

        if (logo === null || !IsLoggedIn() || !IsPlainLeftClick(event)) {
            return;
        }

        event.preventDefault();
        event.stopImmediatePropagation();
        NavigateToSubscriptions(0);
    }

    document.addEventListener("click", OnDocumentClick, true);
    document.addEventListener("DOMContentLoaded", ScheduleUpdate, { once: true });

    ["yt-navigate-finish", "yt-page-data-updated"].forEach(function(eventName) {
        document.addEventListener(eventName, ScheduleUpdate, true);
        window.addEventListener(eventName, ScheduleUpdate, true);
    });

    bootstrapObserver.observe(document.documentElement, {
        childList: true,
        subtree: true
    });

    ScheduleUpdate();
})();