asp

Adds a custom button and sends data to a server using fetch API with extra permissions.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         asp
// @namespace    http://tampermonkey.net/
// @version      1.9
// @description  Adds a custom button and sends data to a server using fetch API with extra permissions.
// @author       You
// @match        https://www.youtube.com/watch*
// @grant        none
// @connect      localhost
// ==/UserScript==

(function () {
    'use strict';

    const BUTTON_ID = 'custom-tm-xpath-button';

    // Create and inject the button
    function createButton() {
        const button = document.createElement('button');
        button.id = BUTTON_ID;
        button.textContent = 'Soundpad';
        button.style.marginLeft = '10px';
        button.style.padding = '6px 12px';
        button.style.fontSize = '14px';
        button.style.border = 'none';
        button.style.backgroundColor = '#272727';
        button.style.color = '#fff';
        button.style.cursor = 'pointer';
        button.style.fontFamily = '"Roboto","Arial",sans-serif';
        button.style.fontWeight = 500;
        button.style.borderRadius = '99999px';
        button.onclick = () => sendDataToServer(window.location.href); // Send current video URL
        return button;
    }

    // Function to send data to the server using fetch
    function sendDataToServer(videoUrl) {
        fetch('http://localhost:8955/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ url: videoUrl }),
        })
        .then(response => response.text())
        .then(data => {
            console.log('Response from server:', data);
        })
        .catch(error => {
            console.error('Error sending data to server:', error);
        });
    }

    // Inject custom styles
    function injectStyles() {
        const styles = `
            #${BUTTON_ID}:hover {
                background-color: #3f3f3f;
            }
        `;

        const styleSheet = document.createElement("style");
        styleSheet.type = "text/css";
        styleSheet.innerText = styles;
        document.head.appendChild(styleSheet);
    }

    // Function to inject both the button and styles
    function injectButtonAndStyles() {
        const xpath = '/html/body/ytd-app/div[1]/ytd-page-manager/ytd-watch-flexy/div[5]/div[1]/div/div[2]/ytd-watch-metadata/div/div[2]/div[2]/div/div/ytd-menu-renderer';
        const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

        const targetElement = result.singleNodeValue;

        if (!targetElement || document.getElementById(BUTTON_ID)) return;

        // Inject styles first
        injectStyles();

        // Inject button
        const button = createButton();
        targetElement.appendChild(button);

        console.log('[YouTubeButton] Custom button and stylesheet added to target XPath');
    }

    // Ensure the page is fully loaded before trying to inject the button and styles
    window.onload = function () {
        // First try after the window has fully loaded
        injectButtonAndStyles();

        // Fallback for dynamic page updates (SPA)
        const observer = new MutationObserver(() => {
            injectButtonAndStyles();
        });

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

})();