YouTube Enhancer (Secret Stats)

Integrating "Secret Stats" and "Stream Stats" buttons into the channel page, directing users to detailed analytics pages for insights into the channel.

当前为 2024-10-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         YouTube Enhancer (Secret Stats)
// @description  Integrating "Secret Stats" and "Stream Stats" buttons into the channel page, directing users to detailed analytics pages for insights into the channel.
// @icon         https://raw.githubusercontent.com/exyezed/youtube-enhancer/refs/heads/main/extras/youtube-enhancer.png
// @version      1.0
// @author       exyezed
// @namespace    https://github.com/exyezed/youtube-enhancer/
// @supportURL   https://github.com/exyezed/youtube-enhancer/issues
// @license      MIT
// @match        https://www.youtube.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Button Creation and Manipulation
    function createButton(text, iconName, id) {
        const button = document.createElement('button');
        button.id = id;
        button.className = 'yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m';
        button.style.display = 'inline-flex';
        button.style.alignItems = 'center';
        button.style.justifyContent = 'center';
        button.style.minWidth = 'auto';
        button.style.padding = '0 16px';
        button.style.height = '36px';
        button.style.fontSize = '14px';
        button.style.lineHeight = '36px';
        button.style.fontWeight = '500';

        const icon = document.createElement('span');
        icon.className = 'material-symbols-outlined';
        icon.textContent = iconName;
        icon.style.marginRight = '4px';
        icon.style.fontSize = '24px';
        icon.style.fontWeight = '100';

        const buttonText = document.createTextNode(text);

        button.appendChild(icon);
        button.appendChild(buttonText);

        return button;
    }

    function createButtonWrapper(button) {
        const buttonWrapper = document.createElement('div');
        buttonWrapper.className = 'yt-flexible-actions-view-model-wiz__action';
        buttonWrapper.appendChild(button);
        return buttonWrapper;
    }

    function addStatsButtons() {
        const targetElement = document.querySelector('yt-flexible-actions-view-model');
        const lastAction = targetElement ? targetElement.querySelector('div.yt-flexible-actions-view-model-wiz__action:last-child') : null;

        if (lastAction && !document.querySelector('#YouTubeEnhancerChannelSecretStats')) {
            const secretStatsButton = createButton('Secret Stats', 'lock_open', 'YouTubeEnhancerChannelSecretStats');
            const streamStatsButton = createButton('Stream Stats', 'cell_tower', 'YouTubeEnhancerStreamStats');

            secretStatsButton.addEventListener('click', function() {
                const channelIdentifier = getChannelIdentifier();
                if (channelIdentifier) {
                    const statsUrl = `https://exyezed.vercel.app/stats/secret/${channelIdentifier}`;
                    window.open(statsUrl, '_blank');
                } else {
                    alert('Could not determine channel identifier. Please try again on a channel page.');
                }
            });

            streamStatsButton.addEventListener('click', function() {
                const channelIdentifier = getChannelIdentifier();
                if (channelIdentifier) {
                    const statsUrl = `https://exyezed.vercel.app/stats/stream/${channelIdentifier}`;
                    window.open(statsUrl, '_blank');
                } else {
                    alert('Could not determine channel identifier. Please try again on a channel page.');
                }
            });

            const secretStatsWrapper = createButtonWrapper(secretStatsButton);
            const streamStatsWrapper = createButtonWrapper(streamStatsButton);

            lastAction.insertAdjacentElement('afterend', streamStatsWrapper);
            lastAction.insertAdjacentElement('afterend', secretStatsWrapper);
        }
    }

    // Channel Identifier Functions
    function getChannelIdentifier() {
        const channelId = getChannelId();
        if (channelId) return channelId;
        return getChannelHandle();
    }

    function getChannelId() {
        const channelIdMeta = document.querySelector('meta[itemprop="channelId"]');
        if (channelIdMeta) {
            return channelIdMeta.content;
        }

        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.get('channel') || extractChannelIdFromUrl();
    }

    function getChannelHandle() {
        const path = window.location.pathname;
        const matches = path.match(/\/@([^/]+)/);
        return matches ? matches[1] : null;
    }

    function extractChannelIdFromUrl() {
        const path = window.location.pathname;
        const matches = path.match(/\/(channel|user|c)\/([^/]+)/);
        return matches ? matches[2] : null;
    }

    // Utility Functions
    function addMaterialIconsStylesheet() {
        if (!document.querySelector('#material-icons-stylesheet')) {
            const link = document.createElement('link');
            link.id = 'material-icons-stylesheet';
            link.rel = 'stylesheet';
            link.href = 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,150,0,0&icon_names=cell_tower,lock_open';
            document.head.appendChild(link);
        }
    }

    function observePageChanges() {
        const observer = new MutationObserver((mutations) => {
            const targetElement = document.querySelector('yt-flexible-actions-view-model');
            if (targetElement && targetElement.querySelector('div.yt-flexible-actions-view-model-wiz__action')) {
                addStatsButtons();
                observer.disconnect();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    // Initialization
    function init() {
        if (window.location.pathname.includes('/channel/') ||
            window.location.pathname.includes('/@') ||
            window.location.pathname.includes('/c/') ||
            window.location.pathname.includes('/user/')) {
            addMaterialIconsStylesheet();
            observePageChanges();
        }
    }

    // Run on initial page load
    init();

    // Listen for YouTube spa navigation events
    window.addEventListener('yt-navigate-finish', init);
})();