CrunchyMAL Cross Search

Add MyAnimeList button to Crunchyroll pages and vice-versa.

// ==UserScript==
// @name         CrunchyMAL Cross Search
// @namespace    CrunchyMAL-CS
// @version      2.3
// @description  Add MyAnimeList button to Crunchyroll pages and vice-versa.
// @author       Mattari
// @match        *://*.crunchyroll.com/*
// @match        *://*.myanimelist.net/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // General function to create buttons
    function createButton(text, url, bgColor, textColor) {
        const button = document.createElement('button');
        button.textContent = text;
        button.style.fontWeight = 'bold';
        button.style.marginLeft = '10px';
        button.style.padding = '5px 10px';
        button.style.borderRadius = '5px';
        button.style.border = 'none';
        button.style.outline = 'none';
        button.style.color = textColor;
        button.style.backgroundColor = bgColor;
        button.style.whiteSpace = 'nowrap';
        button.onclick = () => {
            window.open(url, '_blank');
        };
        return button;
    }

    // Function to process Crunchyroll page
    function processCrunchyrollPage() {
        try {
            const targetElement = document.querySelector('div.erc-ratings');
            if (targetElement && !targetElement.nextElementSibling?.textContent.includes('MyAnimeList')) { // Check if the button is already added
                console.log("CrunchyMAL [Info]: Found target location for button.");

                const crURL = window.location.href;
                const titleText = crURL.substring(crURL.lastIndexOf('/') + 1).replace(/-/g, ' ');
                const button = createButton('Find\u00A0on\u00A0MyAnimeList', `https://myanimelist.net/search/all?q=${encodeURIComponent(titleText)}`, '#2e4f9e', 'white');
                targetElement.insertAdjacentElement('afterend', button);

                // Unload script and clean up
                unloadScript();
            }
        } catch (error) {
            console.error('CrunchyMAL [Error]: ', error);
        }
    }

    // Function to process MyAnimeList page
    function processMyAnimeListPage() {
        try {
            const titleDiv = document.querySelector('div.h1-title');
            if (titleDiv && !titleDiv.nextElementSibling?.textContent.includes('CrunchyRoll')) { // Check if the button is already added
                console.log("CrunchyMAL [Info]: Found target location for button.");
                const titleText = document.querySelector('div.h1-title p.title-english').textContent.trim();
                const button = createButton('Find\u00A0on\u00A0CrunchyRoll', `https://www.crunchyroll.com/search?from=&q=${encodeURIComponent(titleText)}`, '#ff7b2e', 'white');
                titleDiv.insertAdjacentElement('afterend', button);

                // Unload script and clean up
                unloadScript(null);
            }
        } catch (error) {
            console.error('CrunchyMAL [Error]: ', error);
        }
    }

    // Function to observe DOM changes for Crunchyroll
    function observeCrunchyrollDOMChanges() {
        let timeoutId;
        const observer = new MutationObserver(() => {
            clearTimeout(timeoutId);
            processCrunchyrollPage();
            timeoutId = setTimeout(() => {
                processCrunchyrollPage();
                observer.disconnect();
                console.log("CrunchyMAL [Info]: CrunchyMAL page observer safely removed, hopfully without the button disappearing.");
            }, 5000); // Adjust the timeout as needed
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    // Function to unload the script and clean up
    function unloadScript() {
        window.removeEventListener('load', onLoadHandler);
        if (window.MutationObserver) delete window.MutationObserver;
        if (window.document) delete window.document;
        console.log("CrunchyMAL [Info]: Script unloaded and memory cleaned up.");
    }

    // Load handler function
    function onLoadHandler() {
        try {
            const hostname = window.location.hostname;
            const pathname = window.location.pathname;
            if (hostname.includes('crunchyroll.com')) {
                observeCrunchyrollDOMChanges();
            } else if (hostname.includes('myanimelist.net') && pathname.startsWith('/anime/')) {
                processMyAnimeListPage();
            }
        } catch (error) {
            console.error('CrunchyMAL [Error]: ', error);
        }
    }

    // Ensure the script runs after the page has fully loaded
    window.addEventListener('load', onLoadHandler);

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址