Greasy Fork

★一键查看Bangumi动画详情★

该脚本适配Bilibili,次元城动漫,稀饭动漫,mutefun,风铃动漫,NT动漫,Age动漫等动画网站,可一键跳转到Bangumi查看动画详情

// ==UserScript==
// @name         ★一键查看Bangumi动画详情★
// @namespace    http://tampermonkey.net/
// @version      0.1.4
// @description  该脚本适配Bilibili,次元城动漫,稀饭动漫,mutefun,风铃动漫,NT动漫,Age动漫等动画网站,可一键跳转到Bangumi查看动画详情
// @author       Aomine
// @match        *://www.agefans.la/play*
// @match        *://www.cycani.org/watch*
// @match        *://www.mutean.com/vodplay*
// @match        *://www.aafun.cc/f*
// @match        *://www.ntdm8.com/play*
// @match        *://www.mwcy.net/play*
// @match        *://dick.xfani.com/watch*
// @match        *://anich.emmmm.eu.org/b*
// @match        *://www.bilibili.com/bangumi/play*
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      bgm.tv
// @license      GPL License
// @icon         https://bgm.tv/img/favicon.ico
// ==/UserScript==

(function() {
    'use strict';

    // 初始化设置
    const config = {
        showButton: GM_getValue('showButton', true),  // 默认显示按钮
        excludedSites: GM_getValue('excludedSites', [])  // 默认不排除任何站点
    };

    // 注册菜单命令
    GM_registerMenuCommand("⚙️ 脚本设置", openSettings);
    GM_registerMenuCommand(config.showButton ? "🔘 按钮开关" :"❌ 隐藏按钮" , toggleButton);

    // 各网站标题选择器配置
    const siteSelectors = {
        'www.agefans.la': '.card-body .card-title',
        'www.cycani.org':'h2.top20 a.player-title-link',
        'www.mutean.com': '.module-info-heading h1 a',
        'anich.emmmm.eu.org': 'section[player-info] a[href^="/b/"]',
        'www.ntdm8.com': 'h4#detailname a:first-child',
        'www.mwcy.net': 'h2.top20 a.player-title-link',
        'dick.xfani.com': 'h2.top20 a.player-title-link',
        'www.aafun.cc': [
                         'h2.play-title .hl-infos-title',
                          '.hl-dc-title .hl-data-menu'
                         ],
        'www.bilibili.com': [
            '.mediainfo_mediaTitle__Zyiqh',
            '[class*="mediaTitle"]',
            '.video-info .video-title',
            '.media-title',
            'h1.title'
        ].join(', ')
    };

    // 切换按钮显示状态
    function toggleButton() {
        config.showButton = !config.showButton;
        GM_setValue('showButton', config.showButton);

        const button = document.querySelector('#bangumiJumpButton');
        if (button) {
            if (config.showButton) {
                button.style.display = 'block';
                setTimeout(() => { button.style.opacity = '1'; }, 10);
            } else {
                button.style.opacity = '0';
                setTimeout(() => { button.style.display = 'none'; }, 300);
            }
        } else if (config.showButton && shouldShowButton()) {
            createJumpButton();
        }
    }

    // 打开设置界面
    function openSettings() {
        const settings = `
            <div style="padding:10px;font-family:Arial,sans-serif;max-width:500px">
                <h3>Bangumi跳转脚本设置</h3>
                <label style="display:block;margin:10px 0">
                    <input type="checkbox" ${config.showButton ? 'checked' : ''}
                           id="showButtonCheckbox">
                    显示右下角"查看详情"按钮
                </label>
                <h4>排除网站:</h4>
                ${Object.keys(siteSelectors).map(domain => `
                    <label style="display:block;margin:5px 0">
                        <input type="checkbox" ${config.excludedSites.includes(domain) ? 'checked' : ''}
                               class="excludeCheckbox" data-domain="${domain}">
                        ${domain}
                    </label>
                `).join('')}
            </div>
            <script>
                document.getElementById('showButtonCheckbox').addEventListener('change', function() {
                    window.opener.postMessage({
                        type: 'updateShowButton',
                        value: this.checked
                    }, '*');
                });

                document.querySelectorAll('.excludeCheckbox').forEach(checkbox => {
                    checkbox.addEventListener('change', function() {
                        window.opener.postMessage({
                            type: 'updateExcludedSite',
                            domain: this.dataset.domain,
                            value: this.checked
                        }, '*');
                    });
                });
            </script>
        `;

        const win = window.open('', '_blank', 'width=500,height=400');
        win.document.write(settings);

        // 监听设置窗口的消息
        window.addEventListener('message', function(event) {
            if (event.data.type === 'updateShowButton') {
                config.showButton = event.data.value;
                GM_setValue('showButton', config.showButton);
                toggleButton(); // 直接调用切换函数更新按钮状态
            } else if (event.data.type === 'updateExcludedSite') {
                const excluded = GM_getValue('excludedSites', []);
                if (event.data.value && !excluded.includes(event.data.domain)) {
                    excluded.push(event.data.domain);
                } else {
                    const index = excluded.indexOf(event.data.domain);
                    if (index > -1) excluded.splice(index, 1);
                }
                GM_setValue('excludedSites', excluded);
                config.excludedSites = excluded;

                // 检查当前站点是否被排除
                const button = document.querySelector('#bangumiJumpButton');
                if (button) {
                    if (shouldShowButton()) {
                        button.style.display = 'block';
                        setTimeout(() => { button.style.opacity = '1'; }, 10);
                    } else {
                        button.style.opacity = '0';
                        setTimeout(() => { button.style.display = 'none'; }, 300);
                    }
                }
            }
        });
    }

    // 判断是否显示按钮
    function shouldShowButton() {
        // 如果全局关闭按钮或当前站点被排除
        if (!config.showButton || config.excludedSites.includes(window.location.hostname)) {
            return false;
        }

        const path = window.location.pathname;
        return (
            (window.location.hostname === 'www.mutean.com' && path.includes('/vodplay')) ||
            (window.location.hostname === 'www.aafun.cc' && path.includes('/f')) ||
            (window.location.hostname === 'www.cycani.org' && path.includes('/watch')) ||
            (window.location.hostname === 'www.agefans.la' && path.includes('/play')) ||
            (window.location.hostname === 'www.ntdm8.com' && path.includes('/play')) ||
            (window.location.hostname === 'www.mwcy.net' && path.includes('/play')) ||
            (window.location.hostname === 'dick.xfani.com' && path.includes('/watch')) ||
            (window.location.hostname === 'www.bilibili.com' && path.includes('/play')) ||
            (window.location.hostname === 'anich.emmmm.eu.org' && path.includes('/b')) ||
            !!getAnimeTitle()
        );
    }

    // 获取动画标题
    function getAnimeTitle() {
        const domain = window.location.hostname;
        const selector = siteSelectors[domain];

        if (!selector) {
            console.warn(`当前网站 ${domain} 未配置标题选择器`);
            return null;
        }

        const titleElement = document.querySelector(selector);
        if (titleElement) {
            let title = titleElement.textContent.trim();
            title = title.replace(/^【.+?】/, '')
                        .replace(/^《|》$/g, '')
                        .replace(/^"|"$/g, '')
                        .trim();
            return title;
        }
        return null;
    }

    // 使用Bangumi API获取动画ID
    function getBangumiId(title) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: `https://api.bgm.tv/search/subject/${encodeURIComponent(title)}?type=2&responseGroup=small`,
                headers: {
                    "User-Agent": "Mozilla/5.0 (BangumiScript)"
                },
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.list && data.list.length > 0) {
                            resolve(data.list[0].id);
                        } else {
                            reject('未找到匹配的动画');
                        }
                    } catch (e) {
                        reject('解析API响应失败');
                    }
                },
                onerror: function(error) {
                    reject('API请求失败');
                }
            });
        });
    }

    // 跳转到Bangumi详情页
    async function jumpToBangumi() {
        const animeTitle = getAnimeTitle();
        if (!animeTitle) {
            alert('无法获取动画标题');
            return;
        }

        try {
            const subjectId = await getBangumiId(animeTitle);
            window.open(`https://bgm.tv/subject/${subjectId}`, '_blank');
            console.log(`跳转到Bangumi详情页: ${animeTitle}`);
        } catch (error) {
            console.warn(`直接跳转失败: ${error}, 改用搜索页`);
            const encodedTitle = encodeURIComponent(animeTitle);
            window.open(`https://bgm.tv/subject_search/${encodedTitle}?cat=2`, '_blank');
        }
    }

    // 跳转到Bangumi搜索页(右击功能)
    function jumpToBangumiSearch() {
        const animeTitle = getAnimeTitle();
        if (!animeTitle) {
            alert('无法获取动画标题');
            return;
        }
        const encodedTitle = encodeURIComponent(animeTitle);
        window.open(`https://bgm.tv/subject_search/${encodedTitle}?cat=2`, '_blank');
        console.log(`跳转到Bangumi搜索页: ${animeTitle}`);
    }

    // 创建右下角按钮
    function createJumpButton() {
        if (!shouldShowButton()) return;

        const button = document.createElement('button');
        button.id = 'bangumiJumpButton';
        button.textContent = '查看详情';
        button.style.position = 'fixed';
        button.style.bottom = '20px';
        button.style.right = '20px';
        button.style.zIndex = '9999';
        button.style.padding = '8px 16px';
        button.style.backgroundColor = '#1E88E5';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.borderRadius = '4px';
        button.style.cursor = 'pointer';
        button.style.fontSize = '14px';
        button.style.fontWeight = '500';
        button.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)';
        button.style.transition = 'all 0.3s ease';
        button.style.opacity = config.showButton ? '1' : '0';
        button.style.display = config.showButton ? 'block' : 'none';

        // 添加title属性用于悬停提示
        button.title = '搜索错误时右击';

        // 悬停效果
        button.addEventListener('mouseover', () => {
            button.style.backgroundColor = '#1565C0';
            button.style.transform = 'translateY(-2px)';
        });
        button.addEventListener('mouseout', () => {
            button.style.backgroundColor = '#1E88E5';
            button.style.transform = 'translateY(0)';
        });

        // 左键点击事件
        button.addEventListener('click', jumpToBangumi);

        // 右键点击事件
        button.addEventListener('contextmenu', (e) => {
            e.preventDefault();
            jumpToBangumiSearch();
        });

        document.body.appendChild(button);
    }

    // 键盘事件处理
    function handleKeyPress(e) {
        const isShiftF8 = (e.key === 'F8' && e.shiftKey) ||
                         (e.keyCode === 119 && e.shiftKey);
        if (isShiftF8) {
            e.preventDefault();
            e.stopPropagation();
            jumpToBangumi();
            return false;
        }
    }

    // 添加键盘监听
    function addKeyListener() {
        document.addEventListener('keydown', handleKeyPress);
        window.addEventListener('keydown', handleKeyPress);
    }

    // 主函数
    function main() {
        addKeyListener();
        if (shouldShowButton()) {
            createJumpButton();
        }
        console.log('Bangumi跳转脚本已加载',
                   config.showButton ? '按钮已启用' : '按钮已禁用');
    }

    // 页面加载完成后初始化
    if (document.readyState === 'complete') {
        main();
    } else {
        window.addEventListener('load', main);
    }
})();