Greasy Fork

来自缓存

Greasy Fork is available in English.

影巢 Emby&115 转存助手

影巢显示emby已入库以及未入库 支持主页,详情页,用户页面,合集页面,添加一键转存 115 按钮转存到 115 网盘,ui 可选文件夹 id 支持日志显示, 支持并适配移动端与pc端

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         影巢 Emby&115 转存助手
// @version      1.6.3
// @description  影巢显示emby已入库以及未入库 支持主页,详情页,用户页面,合集页面,添加一键转存 115 按钮转存到 115 网盘,ui 可选文件夹 id  支持日志显示, 支持并适配移动端与pc端
// @author       楠
// @match        *://hdhive.com/*
// @match        *://www.hdhive.com/*
// @match        *://115.com/s/*
// @match        *://115cdn.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        window.close
// @grant        window.opener
// @license      MIT
// @icon         https://hdhive.com/apple-touch-icon.png
// @namespace    http://greasyfork.icu/users/1514724
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    const CONFIG = {
        targetDomain: 'hdhive.com',
        autoCloseDelay: 1500,
        maxWaitTime: 15000,
        api115: 'https://115cdn.com/webapi/share/receive',
        snap115: 'https://115cdn.com/webapi/share/snap',
        symediaApiPath: '/api/v1/plugin/cloud_helper/add_share_urls_115'
    };

    let EMBY_CONFIG = {
        HOST: GM_getValue("embyHost", ""),
        API_KEY: GM_getValue("embyApiKey", "")
    };

    const state = {
        processingItems: new Set(),
        processedItems: new Set(),
        embyCache: new Map(),
        transferButtonsInitialized: false,
        currentFilter: 'all'
    };

    const BUTTON_STYLES = {
        posterBtn: {
            size: '25px',
            position: { top: '10px', right: '10px' },
            has: {
                bg: 'linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%)',
                icon: '✓',
                border: '2px solid rgba(255,255,255,0.8)'
            },
            notHas: {
                bg: 'linear-gradient(135deg, #F44336 0%, #C62828 100%)',
                icon: '✗',
                border: '2px solid rgba(255,255,255,0.8)'
            },
            hoverEffect: 'scale(1.1)'
        },
        nameBtn: {
            padding: '3px 10px',
            marginTop: '5px',
            fontSize: '11px',
            has: {
                bg: 'rgba(76, 175, 80, 0.15)',
                text: '已入库',
                textColor: '#4CAF50',
                border: '1px solid rgba(76, 175, 80, 0.3)'
            },
            notHas: {
                bg: 'rgba(244, 67, 54, 0.15)',
                text: '未入库',
                textColor: '#F44336',
                border: '1px solid rgba(244, 67, 54, 0.3)'
            },
            hoverEffect: 'translateY(-1px)'
        },
        detailBtn: {
            posterBtn: {
                size: '30px',
                position: { top: '15px', right: '15px' },
                has: {
                    bg: 'linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%)',
                    icon: '✓',
                    border: '2px solid rgba(255,255,255,0.9)'
                },
                notHas: {
                    bg: 'linear-gradient(135deg, #F44336 0%, #C62828 100%)',
                    icon: '✗',
                    border: '2px solid rgba(255,255,255,0.9)'
                },
                hoverEffect: 'scale(1.15)'
            },
            titleBtn: {
                padding: '5px 15px',
                marginLeft: '10px',
                fontSize: '12px',
                has: {
                    bg: 'rgba(76, 175, 80, 0.15)',
                    text: '已入库',
                    textColor: '#4CAF50',
                    border: '1px solid rgba(76, 175, 80, 0.4)'
                },
                notHas: {
                    bg: 'rgba(244, 67, 54, 0.15)',
                    text: '未入库',
                    textColor: '#F44336',
                    border: '1px solid rgba(244, 67, 54, 0.4)'
                },
                hoverEffect: 'translateY(-1px)'
            }
        },
        searchYearBtn: {
            padding: '3px 10px',
            marginLeft: '10px',
            fontSize: '11px',
            has: {
                bg: 'rgba(76, 175, 80, 0.15)',
                text: '已入库',
                textColor: '#4CAF50',
                border: '1px solid rgba(76, 175, 80, 0.3)'
            },
            notHas: {
                bg: 'rgba(244, 67, 54, 0.15)',
                text: '未入库',
                textColor: '#F44336',
                border: '1px solid rgba(244, 67, 54, 0.3)'
            },
            hoverEffect: 'translateY(-1px)'
        },
        userPageBtn: {
            padding: '3px 10px',
            marginLeft: '8px',
            fontSize: '11px',
            has: {
                bg: 'rgba(76, 175, 80, 0.35)',
                text: '已入库',
                textColor: '#4CAF50',
                border: '1px solid rgba(76, 175, 80, 0.4)'
            },
            notHas: {
                bg: 'rgba(244, 67, 54, 0.35)',
                text: '未入库',
                textColor: '#F44336',
                border: '1px solid rgba(244, 67, 54, 0.4)'
            },
            hoverEffect: 'translateY(-1px)'
        },
        collectionBtn: {
            padding: '3px 10px',
            marginLeft: '10px',
            fontSize: '11px',
            has: {
                bg: 'rgba(76, 175, 80, 0.15)',
                text: '已入库',
                textColor: '#4CAF50',
                border: '1px solid rgba(76, 175, 80, 0.3)'
            },
            notHas: {
                bg: 'rgba(244, 67, 54, 0.15)',
                text: '未入库',
                textColor: '#F44336',
                border: '1px solid rgba(244, 67, 54, 0.3)'
            },
            hoverEffect: 'translateY(-1px)'
        },
        settingBtn: {
            padding: '6px 16px',
            marginRight: '10px',
            fontSize: '12px',
            has: {
                bg: 'rgba(100, 181, 246, 0.35)',
                text: '设置',
                textColor: '#64B5F6',
                border: '1px solid rgba(100, 181, 246, 0.4)'
            },
            hoverEffect: 'translateY(-1px)',
            iconSize: '16px'
        },
        transferBtn: {
            padding: '3px 10px',
            marginLeft: '4px',
            fontSize: '11px',
            bg: 'rgba(227, 242, 253, 1)',
            textColor: '#0d47a1',
            border: '1px solid rgba(13, 71, 161, 0.3)',
            hoverEffect: 'translateY(-1px)',
            iconSize: '16px'
        }
    };

    const Utils = {
        normalizeText: (t = '') => String(t).replace(/\s+/g, '').trim().toLowerCase(),

        isSafari: (() => {
            try {
                const ua = navigator.userAgent;
                return /Safari/.test(ua) && !/Chrome|Chromium|Edg|OPR|Android/.test(ua);
            } catch (e) {
                return false;
            }
        })(),

        isDetailPage: () => {
            const path = window.location.pathname;
            return /^\/(movie|tv)\/[\w-]+/.test(path);
        },

        isUserPage: () => window.location.pathname.startsWith('/user/'),

        isCollectionPage: () => window.location.pathname.startsWith('/collection/'),

        isResourcePage: () => /\/resource\/(115\/)?[\w-]+/.test(location.pathname),

        isFinal115Page: () => location.href.includes('115cdn.com') || location.href.includes('115.com/s/'),

        isParentPage: () => {
            const href = location.href;
            const isDetailPage =
                (href.includes('/movie/') && href.split('/movie/').length > 1) ||
                (href.includes('/tv/') && href.split('/tv/').length > 1);
            return href.includes(CONFIG.targetDomain) && isDetailPage && !href.includes('/resource/');
        },

        isHDHiveSite: () => {
            return location.hostname.includes('hdhive.com') &&
                   !Utils.isResourcePage() &&
                   !Utils.isFinal115Page();
        },

        verifyAndFormatUrl: (rawUrl) => {
            try {
                if (!rawUrl) return { success: false, msg: "链接为空" };
                const urlObj = new URL(rawUrl);
                if (!urlObj.hostname.includes('115')) return { success: false, msg: "非115域名" };
                
                const pickcode = urlObj.pathname.split('/').pop();
                if (!pickcode) return { success: false, msg: "无法提取Pickcode" };
                
                const search = urlObj.search;
                if (!search || !search.includes('=')) return { success: false, msg: "链接未包含密码(Key)" };
                
                const lastEqualIndex = rawUrl.lastIndexOf('=');
                let potentialPass = rawUrl.substring(lastEqualIndex + 1);
                
                if (potentialPass.length >= 4) {
                    var password = potentialPass.substring(0, 4);
                } else {
                    return { success: false, msg: "密码长度不足" };
                }
                
                return { success: true, url: `https://115.com/s/${pickcode}?password=${password}`, msg: "格式化成功" };
            } catch (e) { return { success: false, msg: `解析异常: ${e.message}` }; }
        },

        parseShareLink: (shareLink) => {
            const shareCodeMatch = shareLink.match(/\/s\/([^?]+)/);
            const passwordMatch = shareLink.match(/password=(\w{4})/);
            if (!shareCodeMatch || !passwordMatch) return { success: false };
            return {
                success: true,
                shareCode: shareCodeMatch[1],
                receiveCode: passwordMatch[1]
            };
        },

        humanReadable: (size) => {
            if (size < 1024) return `${size}B`;
            else if (size < 1024**2) return `${(size/1024).toFixed(2)}KB`;
            else if (size < 1024**3) return `${(size/1024/1024).toFixed(2)}MB`;
            else if (size < 1024**4) return `${(size/1024/1024/1024).toFixed(2)}GB`;
            else if (size < 1024**5) return `${(size/1024/1024/1024/1024).toFixed(2)}TB`;
            else return `${(size/1024/1024/1024/1024/1024).toFixed(2)}PB`;
        },

        normalizeUrl: (url) => {
            if (!url) return '';
            return url.replace(/\/+$/, '');
        },

        getDiskType: (el) => {
            const html = el.innerHTML;
            if (html.includes('M34.694') || html.includes('115网盘') || html.includes('一生相伴')) return '115';
            if (html.includes('M4.240')) return '123';
            if (html.includes('M833.399') || html.includes('天翼')) return 'tianyi';
            if (html.includes('M513.465')) return 'baidu';
            if (html.includes('M466.483') || html.includes('夸克')) return 'quark';
            if (html.includes('M841.984') || el.innerText.includes('阿里')) return 'ali';
            return 'other';
        }
    };

    const Logger = {
        stats: { free: 0, paid: 0, unlocked: 0 },
        processedLinks: new Set(),
        currentTaskId: null,
        logPanel: null,
        logContent: null,

        init: () => {
            Logger.createLogPanel();
        },

        createLogPanel: () => {
            const logPanel = document.createElement('div');
            logPanel.id = 'hdhive-log-panel';
            Object.assign(logPanel.style, {
                position: 'fixed',
                bottom: '85px',
                right: '20px',
                width: '380px',
                height: '380px',
                backgroundColor: 'white',
                boxShadow: '0 4px 15px rgba(0,0,0,0.2)',
                borderRadius: '8px',
                zIndex: 99999,
                display: 'none',
                flexDirection: 'column',
                fontFamily: 'sans-serif',
                border: '1px solid #ddd',
                fontSize: '12px'
            });

            logPanel.innerHTML = `
                <div style="padding:10px;border-bottom:1px solid #eee;background:#f1f3f5;
                    border-radius:8px 8px 0 0;font-weight:bold;display:flex;justify-content:space-between;">
                    <span>🤖 115转存助手日志</span>
                    <span style="cursor:pointer;user-select:none;" onclick="document.getElementById('hdhive-log-panel').style.display='none';">关闭</span>
                </div>
                <div id="log-stats" style="padding:8px;border-bottom:1px solid #eee;display:flex;gap:10px;background:#fff;flex-wrap:wrap;">
                    <span id="stat-free" style="color:#2e7d32;display:none;">免费: 0</span>
                    <span id="stat-paid" style="color:#d32f2f;display:none;">付费: 0</span>
                    <span id="stat-unlocked" style="color:#1976d2;display:none;">已解锁: 0</span>
                </div>
                <div id="log-content" style="flex:1;overflow-y:auto;padding:10px;line-height:1.6;background:#fafafa;"></div>
            `;

            document.body.appendChild(logPanel);
            Logger.logPanel = logPanel;
            Logger.logContent = document.getElementById('log-content');
        },

        showLogPanel: () => {
            if (Logger.logPanel) {
                Logger.logPanel.style.display = 'flex';
            }
        },

        hideLogPanel: () => {
            if (Logger.logPanel) {
                Logger.logPanel.style.display = 'none';
            }
        },

        toggleLogPanel: () => {
            if (Logger.logPanel.style.display === 'flex') {
                Logger.hideLogPanel();
            } else {
                Logger.showLogPanel();
            }
        },

        startNewTask: (resourceUrl) => {
            const taskId = Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            Logger.currentTaskId = taskId;
            return taskId;
        },

        endCurrentTask: (status = 'completed') => {
            if (Logger.currentTaskId) {
                Logger.currentTaskId = null;
            }
        },

        addLog: (msg, type = 'info') => {
            if (!Logger.logContent) return;

            const entry = document.createElement('div');
            entry.style.borderBottom = '1px dashed #eee';
            entry.style.padding = '2px 0';
            const time = new Date().toLocaleTimeString();
            let color = ({error:'#d32f2f',success:'#2e7d32',process:'#0288d1'})[type]||'#333';

            entry.innerHTML = `<span style="color:#999">[${time}]</span> <span style="color:${color}">${msg}</span>`;
            Logger.logContent.appendChild(entry);
            Logger.logContent.scrollTop = Logger.logContent.scrollHeight;
        },

        updateStats: (type) => {
            const statElement = document.getElementById(`stat-${type}`);
            if (Logger.stats[type]!==undefined && statElement) {
                Logger.stats[type]++;
                statElement.textContent = `${type==='free'?'免费':(type==='paid'?'付费':'已解锁')}: ${Logger.stats[type]}`;
                statElement.style.display='inline';
            }
        },

        isLinkProcessed: (link) => {
            return Logger.processedLinks.has(link);
        },

        markLinkAsProcessed: (link) => {
            Logger.processedLinks.add(link);
        }
    };

    const Transfer115 = {
        transfer: async (shareLink, cookie, targetCid) => {
            const parseResult = Utils.parseShareLink(shareLink);
            if (!parseResult.success) {
                return {
                    success: false,
                    message: '无法解析分享链接或密码',
                    file_size: ''
                };
            }

            const { shareCode, receiveCode } = parseResult;

            return new Promise((resolve) => {
                const postData = new URLSearchParams({
                    share_code: shareCode,
                    receive_code: receiveCode,
                    cid: targetCid,
                    is_check: 0
                });

                GM_xmlhttpRequest({
                    method: "POST",
                    url: CONFIG.api115,
                    headers: {
                        "Cookie": cookie,
                        "Content-Type": "application/x-www-form-urlencoded"
                    },
                    data: postData.toString(),
                    onload: (response) => {
                        try {
                            const respJson = JSON.parse(response.responseText);

                            if (respJson.state === true) {
                                Transfer115.getFileSize(shareCode, receiveCode, cookie).then(fileSize => {
                                    resolve({
                                        success: true,
                                        message: `✅ 115转存成功[${fileSize}]`,
                                        file_size: fileSize
                                    });
                                }).catch(err => {
                                    resolve({
                                        success: true,
                                        message: '✅ 115转存成功[大小未知]',
                                        file_size: ''
                                    });
                                });
                            } else if (respJson.errno === 4100024) {
                                resolve({
                                    success: false,
                                    message: '⚠️ 转存失败:你已经转存过该文件',
                                    file_size: ''
                                });
                            } else if (respJson.errno === 4100008) {
                                resolve({
                                    success: false,
                                    message: '❌ 转存失败:分享链接密码错误',
                                    file_size: ''
                                });
                            } else if (respJson.errno === 4100010) {
                                resolve({
                                    success: false,
                                    message: '❌ 转存失败:分享已取消',
                                    file_size: ''
                                });
                            } else if (respJson.errno === 4100018) {
                                resolve({
                                    success: false,
                                    message: '❌ 转存失败:链接已过期',
                                    file_size: ''
                                });
                            } else {
                                resolve({
                                    success: false,
                                    message: `❌ 转存失败: ${respJson.error || '未知错误'}`,
                                    file_size: ''
                                });
                            }
                        } catch (e) {
                            resolve({
                                success: false,
                                message: `❌ 转存异常: ${e.message}`,
                                file_size: ''
                            });
                        }
                    },
                    onerror: (error) => {
                        resolve({
                            success: false,
                            message: '❌ 转存接口调用失败',
                            file_size: ''
                        });
                    }
                });
            });
        },

        getFileSize: async (shareCode, receiveCode, cookie) => {
            return new Promise((resolve, reject) => {
                const snapParams = {
                    "_v": 2,
                    "share_code": shareCode,
                    "receive_code": receiveCode,
                    "offset": 0,
                    "limit": 20,
                    "cid": ""
                };

                const queryString = new URLSearchParams(snapParams).toString();

                GM_xmlhttpRequest({
                    method: "GET",
                    url: `${CONFIG.snap115}?${queryString}`,
                    headers: {
                        "Cookie": cookie,
                        "Referer": "https://115.com/",
                        "Origin": "https://115.com",
                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
                    },
                    onload: (response) => {
                        try {
                            const fileInfoJson = JSON.parse(response.responseText);
                            if (fileInfoJson.state && fileInfoJson.data && fileInfoJson.data.list && fileInfoJson.data.list[0]) {
                                const fileSize = fileInfoJson.data.list[0].s || 0;
                                resolve(Utils.humanReadable(fileSize));
                            } else {
                                if (fileInfoJson.data && fileInfoJson.data[0]) {
                                    const fileSize = fileInfoJson.data[0].s || fileInfoJson.data[0].size || 0;
                                    resolve(Utils.humanReadable(fileSize));
                                } else {
                                    reject(new Error('无法获取文件大小'));
                                }
                            }
                        } catch (e) {
                            reject(e);
                        }
                    },
                    onerror: (error) => {
                        reject(error);
                    }
                });
            });
        },

        transferBySymedia: async (shareLink, symediaUrl, symediaToken, targetCid) => {
            if (!symediaUrl || !symediaToken) {
                return {
                    success: false,
                    message: 'Symedia配置不完整'
                };
            }

            const normalizedUrl = Utils.normalizeUrl(symediaUrl);
            const apiUrl = `${normalizedUrl}${CONFIG.symediaApiPath}?token=${symediaToken}`;

            return new Promise((resolve) => {
                const postData = JSON.stringify({
                    urls: [shareLink],
                    parent_id: targetCid ? String(targetCid) : '0'
                });

                GM_xmlhttpRequest({
                    method: "POST",
                    url: apiUrl,
                    headers: {
                        "Content-Type": "application/json"
                    },
                    data: postData,
                    onload: (response) => {
                        try {
                            const respJson = JSON.parse(response.responseText);
                            if (response.status === 200 && respJson.success === true) {
                                if (respJson.message && respJson.message.includes('转存失败')) {
                                    resolve({
                                        success: false,
                                        message: `❌ Symedia转存失败: ${respJson.message}`
                                    });
                                } else {
                                    resolve({
                                        success: true,
                                        message: `✅ Symedia转存: ${respJson.message}`
                                    });
                                }
                            } else {
                                resolve({
                                    success: false,
                                    message: `❌ Symedia转存失败: ${respJson.message || '未知错误'}`
                                });
                            }
                        } catch (e) {
                            resolve({
                                success: false,
                                message: `❌ Symedia转存异常: ${e.message}`
                            });
                        }
                    },
                    onerror: (error) => {
                        resolve({
                            success: false,
                            message: '❌ Symedia接口调用失败'
                        });
                    }
                });
            });
        }
    };

    const FilterManager = {
        injectBar: () => {
            if (!Utils.isUserPage() || document.getElementById('hdhive-filter-bar')) return;
            const anyResource = document.querySelector('a[href*="/resource/"]');
            const grid = anyResource?.closest('.MuiGrid-container');
            if (grid && grid.parentElement) {
                const bar = document.createElement('div'); bar.id = 'hdhive-filter-bar';
                bar.style.cssText = 'display:inline-flex; align-items:center; gap:6px; margin:0 0 20px 0; padding:10px; background:rgba(128,128,128,0.1); border-radius:12px; box-sizing:border-box; width:fit-content; flex-wrap:wrap; backdrop-filter:blur(4px);';

                const opts = [{l:'全部', id:'all'}, {l:'115', id:'115'}, {l:'123', id:'123'}, {l:'天翼', id:'tianyi'}, {l:'百度', id:'baidu'}, {l:'夸克', id:'quark'}, {l:'阿里', id:'ali'}, {l:'其他', id:'other'}];
                opts.forEach(opt => {
                    const btn = document.createElement('div'); btn.className = 'hd-filter-btn';
                    btn.innerHTML = `<span style="line-height:20px;">${opt.l}</span>`;
                    btn.style.cssText = `padding:6px 16px; border-radius:8px; font-size:13px; font-weight:bold; cursor:pointer; transition:0.2s; color:${state.currentFilter===opt.id?'#fff':'#555'}; background:${state.currentFilter===opt.id?'#1890ff':'transparent'};`;
                    btn.onclick = async () => {
                        state.currentFilter = opt.id;
                        document.querySelectorAll('.hd-filter-btn').forEach(b => { b.style.background='transparent'; b.style.color='#555'; });
                        btn.style.background='#1890ff'; btn.style.color='#fff';
                        FilterManager.apply();
                        
                        state.processedItems.clear();
                        state.processingItems.clear();
                        
                        document.querySelectorAll('.emby-user-page-btn, .emby-poster-btn, .one-click-transfer-btn').forEach(b => b.remove());
                        
                        await processUserPageButtons();
                    };
                    btn.title = opt.l;
                    bar.appendChild(btn);
                });
                grid.parentElement.insertBefore(bar, grid);
                FilterManager.apply();
            }
        },
        apply: () => {
            document.querySelectorAll('a[href*="/resource/"]').forEach(link => {
                const card = link.closest('div[class*="Grid"] > div');
                if(!card) return;
                const type = Utils.getDiskType(card);
                if (state.currentFilter === 'all' || state.currentFilter === type) {
                    card.style.display = '';
                } else {
                    card.style.display = 'none';
                }
            });
        }
    };

    const EmbyHelper = {
        checkEmbyResource: (name, year) => {
            return new Promise((resolve) => {
                const cacheKey = `${name}-${year}`;
                if (state.embyCache.has(cacheKey)) {
                    resolve(state.embyCache.get(cacheKey));
                    return;
                }
                const searchUrl = `${EMBY_CONFIG.HOST}/emby/Items?api_key=${EMBY_CONFIG.API_KEY}&SearchTerm=${encodeURIComponent(name)}&IncludeItemTypes=Movie,Series&Recursive=true&Fields=ProductionYear,OriginalTitle&Limit=20`;
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: searchUrl,
                    onload: function(response) {
                        try {
                            const data = JSON.parse(response.responseText);
                            let hasResource = false;
                            if (data.Items && data.Items.length > 0) {
                                const chineseMatch = data.Items.find(item => {
                                    const itemName = item.Name;
                                    const itemYear = item.ProductionYear;
                                    return itemName === name && itemYear === year;
                                });
                                if (chineseMatch) {
                                    hasResource = true;
                                } else {
                                    const englishMatch = data.Items.find(item => {
                                        const itemOriginalTitle = item.OriginalTitle;
                                        const itemYear = item.ProductionYear;
                                        return itemOriginalTitle && itemOriginalTitle === name && itemYear === year;
                                    });
                                    hasResource = !!englishMatch;
                                }
                            }
                            state.embyCache.set(cacheKey, hasResource);
                            resolve(hasResource);
                        } catch (error) {
                            state.embyCache.set(cacheKey, false);
                            resolve(false);
                        }
                    },
                    onerror: function(error) {
                        state.embyCache.set(cacheKey, false);
                        resolve(false);
                    }
                });
            });
        },

        extractInfoFromPoster: (poster) => {
            const nameElement = poster.querySelector('p[class*="MuiTypography-body1"][class*="mui-"]');
            const yearElement = Array.from(poster.querySelectorAll('p[class*="MuiTypography-body1"][class*="mui-"]')).find(p => /^\d{4}$/.test(p.textContent.trim()));
            
            if (nameElement && yearElement && nameElement !== yearElement) {
                const name = nameElement.textContent.trim();
                const year = parseInt(yearElement.textContent.trim(), 10);
                if (name && !isNaN(year)) {
                    return { name, year, element: poster };
                }
            }
            return null;
        },

        extractInfoFromDetail: () => {
            const titleElement = document.querySelector('h1[class*="MuiTypography-h1"]');
            if (titleElement) {
                const name = titleElement.childNodes[0]?.textContent?.trim() || 
                           titleElement.textContent.replace(/\(\d{4}\).*$/, '').trim();
                
                const yearSpan = titleElement.querySelector('span[class*="MuiTypography"]');
                let year = null;
                
                if (yearSpan) {
                    const yearMatch = yearSpan.textContent.match(/\((\d{4})\)/);
                    if (yearMatch) {
                        year = parseInt(yearMatch[1], 10);
                    }
                }
                
                if (!year) {
                    const directMatch = titleElement.textContent.match(/\((\d{4})\)/);
                    if (directMatch) {
                        year = parseInt(directMatch[1], 10);
                    }
                }
                
                if (name && year) {
                    return { name, year };
                }
            }
            return null;
        },

        extractInfoFromUserPage: (element) => {
            const text = element.textContent.trim();
            const match = text.match(/(.+?)\s*\((\d{4})\)/);
            if (match) {
                const name = match[1].trim();
                const year = parseInt(match[2], 10);
                return { name, year, element };
            }
            return null;
        },

        extractInfoFromSearchYear: (element) => {
            const text = element.textContent.trim();
            const match = text.match(/\((\d{4})\)/);
            if (match) {
                const year = parseInt(match[1], 10);
                const nameElement = element.previousElementSibling;
                if (nameElement) {
                    const name = nameElement.textContent.trim();
                    return { name, year, element };
                }
            }
            return null;
        },

        extractInfoFromCollection: (element) => {
            const nameElement = element.querySelector('p[class*="MuiTypography-body1"][class*="mui-"]');
            const yearElement = Array.from(element.querySelectorAll('p[class*="MuiTypography-body1"][class*="mui-"]')).find(p => /^\d{4}$/.test(p.textContent.trim()));
            
            if (nameElement && yearElement && nameElement !== yearElement) {
                const name = nameElement.textContent.trim();
                const year = parseInt(yearElement.textContent.trim(), 10);
                if (name && !isNaN(year)) {
                    return { name, year, element };
                }
            }
            return null;
        },

        createPosterButton: (hasResource) => {
            const btn = document.createElement('div');
            btn.className = `emby-poster-btn ${hasResource ? 'has' : 'not-has'}`;
            btn.textContent = hasResource ? '✓' : '✗';
            btn.title = hasResource ? '已入库' : '未入库';
            return btn;
        },

        createNameButton: (hasResource) => {
            const btn = document.createElement('span');
            btn.className = `emby-name-btn ${hasResource ? 'has' : 'not-has'}`;
            const state = hasResource ? BUTTON_STYLES.nameBtn.has : BUTTON_STYLES.nameBtn.notHas;
            btn.textContent = state.text;
            btn.title = hasResource ? '已入库' : '未入库';
            return btn;
        },

        createDetailPosterButton: (hasResource) => {
            const btn = document.createElement('div');
            btn.className = `emby-detail-poster-btn ${hasResource ? 'has' : 'not-has'}`;
            btn.textContent = hasResource ? '✓' : '✗';
            btn.title = hasResource ? '已入库' : '未入库';
            return btn;
        },

        createDetailTitleButton: (hasResource) => {
            const btn = document.createElement('span');
            btn.className = `emby-detail-title-btn ${hasResource ? 'has' : 'not-has'}`;
            const state = hasResource ? BUTTON_STYLES.detailBtn.titleBtn.has : BUTTON_STYLES.detailBtn.titleBtn.notHas;
            btn.textContent = state.text;
            btn.title = hasResource ? '已入库' : '未入库';
            return btn;
        },

        createSearchYearButton: (hasResource) => {
            const btn = document.createElement('span');
            btn.className = `emby-search-year-btn ${hasResource ? 'has' : 'not-has'}`;
            const state = hasResource ? BUTTON_STYLES.searchYearBtn.has : BUTTON_STYLES.searchYearBtn.notHas;
            btn.textContent = state.text;
            btn.title = hasResource ? '已入库' : '未入库';
            return btn;
        },

        createUserPageButton: (hasResource) => {
            const btn = document.createElement('span');
            btn.className = `emby-user-page-btn ${hasResource ? 'has' : 'not-has'}`;
            const state = hasResource ? BUTTON_STYLES.userPageBtn.has : BUTTON_STYLES.userPageBtn.notHas;
            btn.textContent = state.text;
            btn.title = hasResource ? 'Emby库中有此资源' : 'Emby库中无此资源';
            btn.disabled = true;
            return btn;
        },

        createCollectionButton: (hasResource) => {
            const btn = document.createElement('span');
            btn.className = `emby-collection-btn ${hasResource ? 'has' : 'not-has'}`;
            const state = hasResource ? BUTTON_STYLES.collectionBtn.has : BUTTON_STYLES.collectionBtn.notHas;
            btn.textContent = state.text;
            btn.title = hasResource ? '已入库' : '未入库';
            return btn;
        },

        createSettingButton: () => {
            const btn = document.createElement('span');
            btn.className = 'emby-setting-btn';
            btn.innerHTML = `
                <span style="display:inline-block;width:16px;height:16px;margin-right:8px;
                    background-image:url('https://raw.githubusercontent.com/lige47/QuanX-icon-rule/main/icon/04ProxySoft/emby.png');
                    background-size:contain;background-repeat:no-repeat;background-position:center;
                    filter:brightness(0.9);"></span>
                <span>设置</span>
                <span style="display:inline-block;width:16px;height:16px;margin-left:8px;
                    background-image:url('https://115.com/favicon.ico');
                    background-size:contain;background-repeat:no-repeat;background-position:center;"></span>
            `;
            btn.title = '多功能设置';
            return btn;
        },

        createTransferButton: () => {
            const btn = document.createElement('div');
            btn.className = 'one-click-transfer-btn';
            btn.style.cssText = 'cursor:pointer;margin-left:auto;background:rgba(128,128,128,0.15);color:#0d47a1;display:inline-flex;align-items:center;padding:0 12px;height:32px;border-radius:16px;font-weight:bold;font-size:14px;';
            btn.innerHTML = '<img src="https://115.com/favicon.ico" style="width:16px;height:16px;margin-right:6px;">一键转存';
            return btn;
        }
    };

    const SettingsManager = {
        showSettingsModal: () => {
             if (document.querySelector('#tm-settings-modal')) return;

            const embyHost = EMBY_CONFIG.HOST || '';
            const embyApiKey = EMBY_CONFIG.API_KEY || '';
            const cookie115 = GM_getValue('115_cookie') || '';
            const cid115 = GM_getValue('115_cid') || '0';
            const transferMethod = GM_getValue('115_transfer_method', 'cookie');
            const symediaUrl = GM_getValue('symedia_url', '');
            const symediaToken = GM_getValue('symedia_token', 'symedia');
            const enableTransfer = GM_getValue('115_enable_transfer', true);

            const overlay = document.createElement('div');
            overlay.id = 'tm-settings-modal';
            Object.assign(overlay.style, {
                position: 'fixed',
                top: '0',
                left: '0',
                width: '100%',
                height: '100%',
                background: 'rgba(0, 0, 0, 0.3)',
                backdropFilter: 'blur(12px) saturate(150%)',
                WebkitBackdropFilter: 'blur(12px) saturate(150%)',
                zIndex: 10001,
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                animation: 'tmOverlayIn 0.25s ease'
            });

            const modal = document.createElement('div');
            Object.assign(modal.style, {
                background: 'rgba(255, 255, 255, 0.58)',
                backdropFilter: 'blur(40px) saturate(200%)',
                WebkitBackdropFilter: 'blur(40px) saturate(200%)',
                padding: '0',
                borderRadius: '24px',
                width: '520px',
                boxShadow: '0 24px 80px rgba(0, 0, 0, 0.08), 0 8px 32px rgba(0, 0, 0, 0.06), inset 0 1px 0 rgba(255, 255, 255, 0.8), inset 0 -1px 0 rgba(255, 255, 255, 0.3)',
                fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif',
                height: '85vh',
                overflow: 'hidden',
                border: '1px solid rgba(255, 255, 255, 0.65)',
                animation: 'tmModalIn 0.35s cubic-bezier(0.16, 1, 0.3, 1)',
                display: 'flex',
                flexDirection: 'column'
            });

            modal.innerHTML = `
                <div style="display:flex;justify-content:space-between;align-items:center;padding:28px 32px 16px 32px;border-bottom:1px solid rgba(0,0,0,0.06);flex-shrink:0;">
                    <h3 style="margin:0;font-size:17px;font-weight:700;color:#1a1a2e;letter-spacing:-0.3px;">HDHive</h3>
                    <button id="tm-settings-close" class="tm-close-btn" style="width:30px;height:30px;border-radius:50%;border:none;background:rgba(0,0,0,0.05);color:#888;font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.2s ease;line-height:1;">×</button>
                </div>

                <div style="display:flex;gap:6px;padding:16px 32px 0 32px;flex-shrink:0;"><div style="display:flex;gap:6px;padding:4px;background:rgba(0,0,0,0.08);border-radius:14px;width:100%;">
                    <button class="tm-tab-btn active" data-tab="emby">Emby设置</button>
                    <button class="tm-tab-btn" data-tab="115">115网盘设置</button>
                    <button class="tm-tab-btn" data-tab="logs">日志</button>
                </div></div>

                <div style="flex:1;min-height:0;overflow-y:auto;padding:22px 32px 22px 32px;">

                <div id="tm-tab-emby" class="tm-tab-content active">
                    <div style="margin-bottom:20px;">
                        <h4 style="margin-top:0;margin-bottom:10px;color:#444;">Emby服务器设置</h4>
                        <div style="margin-bottom:10px;">
                            <label style="display:block;margin-bottom:5px;color:#555;font-weight:bold;font-size:13px;">Emby地址:</label>
                            <input id="tm-emby-host" type="text" value="${embyHost}" placeholder="http/s://emby地址" style="width:100%;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:12px;">
                        </div>
                        <div style="margin-bottom:10px;">
                            <label style="display:block;margin-bottom:5px;color:#555;font-weight:bold;font-size:13px;">API密钥:</label>
                            <div style="display:flex;align-items:center;gap:8px;">
                                <input id="tm-emby-apikey" type="password" value="${embyApiKey}" placeholder="输入您的Emby API密钥" style="flex:1;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:12px;">
                                <button id="tm-toggle-emby-apikey" style="padding:6px 10px;border:none;border-radius:4px;background:#666;color:#fff;cursor:pointer;white-space:nowrap;font-size:12px;">显示</button>
                            </div>
                        </div>
                        <div style="margin-top:15px;padding-top:10px;border-top:1px dashed #eee;">
                            <button id="tm-emby-refresh" style="width:100%;padding:8px;border:none;border-radius:4px;background:#2196F3;color:#fff;cursor:pointer;font-size:12px;font-weight:bold;">🔄 刷新 Emby 缓存并重新扫描</button>
                        </div>
                    </div>
                </div>

                <div id="tm-tab-115" class="tm-tab-content">
                    <div style="margin-bottom:20px;">
                        <h4 style="margin-top:0;margin-bottom:10px;color:#444;">115网盘设置</h4>

                        <div style="display:flex;align-items:center;margin-bottom:10px;">
                            <input type="checkbox" id="tm-enable-transfer" ${enableTransfer ? 'checked' : ''} style="margin-right:8px;">
                            <label for="tm-enable-transfer" style="color:#555;font-weight:bold;font-size:13px;">启用115转存功能</label>
                        </div>

                        <div style="margin-bottom:15px;">
                            <label style="display:block;margin-bottom:8px;color:#555;font-weight:bold;font-size:13px;">转存方式:</label>
                            <input type="hidden" id="tm-transfer-method" value="${transferMethod}">
                            <div class="tm-custom-select" id="tm-custom-select">
                                <div class="tm-custom-select-trigger" id="tm-select-trigger">
                                    <span class="tm-select-value">${transferMethod === 'cookie' ? '🍪 115 Cookie转存' : '🔗 Symedia API转存'}</span>
                                    <span class="tm-select-arrow">
                                        <svg width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
                                    </span>
                                </div>
                                <div class="tm-custom-select-dropdown" id="tm-select-dropdown">
                                    <div class="tm-select-option ${transferMethod === 'cookie' ? 'selected' : ''}" data-value="cookie">
                                        <span>🍪 115 Cookie转存</span>
                                        <span class="tm-select-check">${transferMethod === 'cookie' ? '✓' : ''}</span>
                                    </div>
                                    <div class="tm-select-option ${transferMethod === 'symedia' ? 'selected' : ''}" data-value="symedia">
                                        <span>🔗 Symedia API转存</span>
                                        <span class="tm-select-check">${transferMethod === 'symedia' ? '✓' : ''}</span>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <div id="tm-cookie-settings" class="tm-transfer-settings" style="display:${transferMethod === 'cookie' ? 'block' : 'none'};">
                            <div style="margin-bottom:10px;">
                                <label style="display:block;margin-bottom:5px;color:#555;font-weight:bold;font-size:13px;">Cookie:</label>
                                <div style="display:flex;align-items:center;gap:8px;">
                                    <input id="tm-cookie-input" type="password" value="${cookie115}" placeholder="请输入115 Cookie" style="flex:1;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:12px;">
                                    <button id="tm-toggle-cookie" style="padding:6px 10px;border:none;border-radius:4px;background:#666;color:#fff;cursor:pointer;white-space:nowrap;font-size:12px;">显示</button>
                                </div>
                                <div style="font-size:11px;color:#666;margin-top:4px;">
                                    格式:UID=xxx;CID=xxx;SEID=xxx;... 或直接从浏览器复制
                                </div>
                            </div>
                        </div>

                        <div id="tm-symedia-settings" class="tm-transfer-settings" style="display:${transferMethod === 'symedia' ? 'block' : 'none'};">
                            <div style="margin-bottom:10px;">
                                <label style="display:block;margin-bottom:5px;color:#555;font-weight:bold;font-size:13px;">Symedia地址:</label>
                                <input id="tm-symedia-url" type="text" value="${symediaUrl}" placeholder="http://127.0.0.1:8095" style="width:100%;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:12px;">
                            </div>
                            <div style="margin-bottom:10px;">
                                <label style="display:block;margin-bottom:5px;color:#555;font-weight:bold;font-size:13px;">Token:</label>
                                <input id="tm-symedia-token" type="text" value="${symediaToken}" placeholder="默认: symedia" style="width:100%;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:12px;">
                            </div>
                            <div style="font-size:11px;color:#666;margin-top:4px;">
                                格式:http://IP:端口,token默认symedia
                            </div>
                        </div>

                        <div style="margin-bottom:10px;">
                            <label style="display:block;margin-bottom:5px;color:#555;font-weight:bold;font-size:13px;">目标文件夹CID:</label>
                            <div style="display:flex;gap:10px;">
                                <input id="tm-cid-input" type="text" value="${cid115}" placeholder="0为根目录" style="flex:1;padding:8px;border:1px solid #ccc;border-radius:4px;font-size:12px;">
                                <button id="tm-browse-folders" style="padding:6px 12px;border:none;border-radius:4px;background:#2196F3;color:#fff;cursor:pointer;font-size:12px;">浏览文件夹</button>
                            </div>
                            <div style="font-size:11px;color:#666;margin-top:4px;">
                                <div>说明:</div>
                                <div>1. 如果关闭"启用115转存功能",则不会执行转存,只输出链接和日志</div>
                                <div>2. Cookie转存:需要有效的115 Cookie,可点击"浏览文件夹"选择</div>
                                <div>3. Symedia转存:转存可触发实时监控归档整理 token默认symedia</div>
                                <div>4. 文件夹ID为0时转存到根目录</div>
                                <div>5. 当前设置: ${cid115}</div>
                            </div>
                        </div>
                    </div>
                </div>

                <div id="tm-tab-logs" class="tm-tab-content">
                    <div style="margin-bottom:20px;">
                        <h4 style="margin-top:0;margin-bottom:10px;color:#444;">操作日志</h4>
                        <div style="margin-bottom:10px;display:flex;gap:10px;">
                            <button id="tm-clear-logs" style="padding:6px 12px;border:none;border-radius:4px;background:#f44336;color:#fff;cursor:pointer;font-size:12px;">清空日志</button>
                            <button id="tm-show-log-panel" style="padding:6px 12px;border:none;border-radius:4px;background:#2196F3;color:#fff;cursor:pointer;font-size:12px;">显示独立日志面板</button>
                        </div>
                        <div style="border:1px solid rgba(0,0,0,0.05);border-radius:14px;padding:14px;height:300px;overflow-y:auto;background:rgba(255,255,255,0.35);font-size:11px;backdrop-filter:blur(4px);">
                            <div id="tm-settings-log-content"></div>
                        </div>
                    </div>
                </div>

                </div>

                <div style="display:flex;justify-content:flex-end;gap:10px;padding:18px 32px 28px 32px;border-top:1px solid rgba(0,0,0,0.06);flex-shrink:0;">
                    <button id="tm-settings-cancel" class="tm-btn-cancel" style="padding:10px 24px;border:1px solid rgba(0,0,0,0.08);border-radius:12px;background:rgba(255,255,255,0.5);color:#666;cursor:pointer;font-size:13px;font-weight:500;backdrop-filter:blur(4px);">取消</button>
                    <button id="tm-settings-save" class="tm-btn-save" style="padding:10px 24px;border:none;border-radius:12px;background:linear-gradient(135deg,#4CAF50,#2E7D32);color:#fff;cursor:pointer;font-size:13px;font-weight:600;box-shadow:0 4px 16px rgba(76,175,80,0.25);">保存设置</button>
                </div>
            `;

            overlay.appendChild(modal);
            document.body.appendChild(overlay);

            const tabBtns = modal.querySelectorAll('.tm-tab-btn');
            const tabContents = modal.querySelectorAll('.tm-tab-content');
            tabBtns.forEach(btn => {
                btn.addEventListener('click', function() {
                    const tab = this.getAttribute('data-tab');
                    tabBtns.forEach(b => b.classList.remove('active'));
                    tabContents.forEach(c => c.classList.remove('active'));
                    this.classList.add('active');
                    document.getElementById(`tm-tab-${tab}`).classList.add('active');
                    if (tab === 'logs') SettingsManager.refreshLogContent();
                });
            });

            const transferMethodHidden = modal.querySelector('#tm-transfer-method');
            const cookieSettings = modal.querySelector('#tm-cookie-settings');
            const symediaSettings = modal.querySelector('#tm-symedia-settings');
            const browseFoldersBtn = modal.querySelector('#tm-browse-folders');
            const customSelect = modal.querySelector('#tm-custom-select');
            const selectTrigger = modal.querySelector('#tm-select-trigger');
            const selectDropdown = modal.querySelector('#tm-select-dropdown');
            const selectOptions = modal.querySelectorAll('.tm-select-option');
            const selectValue = selectTrigger.querySelector('.tm-select-value');

            selectTrigger.addEventListener('click', function(e) {
                e.stopPropagation();
                customSelect.classList.toggle('open');
            });

            selectOptions.forEach(opt => {
                opt.addEventListener('click', function(e) {
                    e.stopPropagation();
                    const method = this.getAttribute('data-value');
                    transferMethodHidden.value = method;
                    selectOptions.forEach(o => {
                        o.classList.remove('selected');
                        o.querySelector('.tm-select-check').textContent = '';
                    });
                    this.classList.add('selected');
                    this.querySelector('.tm-select-check').textContent = '✓';
                    selectValue.textContent = this.querySelector('span').textContent;
                    customSelect.classList.remove('open');
                    cookieSettings.style.display = method === 'cookie' ? 'block' : 'none';
                    symediaSettings.style.display = method === 'symedia' ? 'block' : 'none';
                    browseFoldersBtn.style.display = method === 'cookie' ? '' : 'none';
                });
            });

            document.addEventListener('click', function closeSelect(e) {
                if (!customSelect.contains(e.target)) {
                    customSelect.classList.remove('open');
                }
            });

            modal.querySelector('#tm-settings-close').onclick = () => overlay.remove();
            
            const embyApiKeyInput = modal.querySelector('#tm-emby-apikey');
            const toggleEmbyApiKeyBtn = modal.querySelector('#tm-toggle-emby-apikey');
            if (toggleEmbyApiKeyBtn) {
                toggleEmbyApiKeyBtn.addEventListener('click', function() {
                    if (embyApiKeyInput.type === 'password') {
                        embyApiKeyInput.type = 'text';
                        toggleEmbyApiKeyBtn.textContent = '隐藏';
                    } else {
                        embyApiKeyInput.type = 'password';
                        toggleEmbyApiKeyBtn.textContent = '显示';
                    }
                });
            }

            modal.querySelector('#tm-emby-refresh').onclick = async () => {
                const btn = modal.querySelector('#tm-emby-refresh');
                const originalText = btn.innerHTML;
                btn.innerHTML = '🔄 正在刷新...';
                btn.disabled = true;

                state.embyCache.clear();
                state.processedItems.clear();
                state.processingItems.clear();

                const selectorList = [
                    '.emby-poster-btn',
                    '.emby-name-btn',
                    '.emby-detail-poster-btn',
                    '.emby-detail-title-btn',
                    '.emby-search-year-btn',
                    '.emby-user-page-btn',
                    '.emby-collection-btn'
                ];
                document.querySelectorAll(selectorList.join(',')).forEach(el => el.remove());

                await processAllPosters();

                setTimeout(() => {
                    btn.innerHTML = '✅ 刷新完成';
                    setTimeout(() => {
                        btn.innerHTML = originalText;
                        btn.disabled = false;
                    }, 1000);
                }, 500);
            };


            const cookieInput = modal.querySelector('#tm-cookie-input');
            const toggleCookieBtn = modal.querySelector('#tm-toggle-cookie');
            toggleCookieBtn.addEventListener('click', function() {
                if (cookieInput.type === 'password') {
                    cookieInput.type = 'text';
                    toggleCookieBtn.textContent = '隐藏';
                } else {
                    cookieInput.type = 'password';
                    toggleCookieBtn.textContent = '显示';
                }
            });

            modal.querySelector('#tm-browse-folders').onclick = () => {
                const cookieValue = cookieInput.value.trim();
                if (!cookieValue) {
                    alert('请先输入Cookie');
                    return;
                }
                GM_setValue('115_cookie', cookieValue);
                SettingsManager.showFolderBrowser();
            };

            modal.querySelector('#tm-clear-logs').onclick = () => {
                if (Logger.logContent) {
                    Logger.logContent.innerHTML = '';
                    Logger.stats = { free: 0, paid: 0, unlocked: 0 };
                    document.querySelectorAll('#log-stats span').forEach(span => {
                        span.style.display = 'none';
                        span.textContent = span.id.replace('stat-', '') + ': 0';
                    });
                }
                SettingsManager.refreshLogContent();
            };

            modal.querySelector('#tm-show-log-panel').onclick = () => {
                Logger.showLogPanel();
                overlay.remove();
            };

            modal.querySelector('#tm-settings-cancel').onclick = () => overlay.remove();

            modal.querySelector('#tm-settings-save').onclick = () => {
                const newEmbyHost = modal.querySelector('#tm-emby-host').value.trim();
                const newEmbyApiKey = embyApiKeyInput.value.trim();
                const newCookie = cookieInput.value.trim();
                const newCid = modal.querySelector('#tm-cid-input').value.trim() || '0';
                const newTransferMethod = modal.querySelector('#tm-transfer-method').value;
                const newSymediaUrl = modal.querySelector('#tm-symedia-url').value.trim();
                const newSymediaToken = modal.querySelector('#tm-symedia-token').value.trim() || 'symedia';
                const newEnableTransfer = modal.querySelector('#tm-enable-transfer').checked;

                GM_setValue('embyHost', newEmbyHost);
                GM_setValue('embyApiKey', newEmbyApiKey);
                EMBY_CONFIG.HOST = newEmbyHost;
                EMBY_CONFIG.API_KEY = newEmbyApiKey;

                GM_setValue('115_cookie', newCookie);
                GM_setValue('115_cid', newCid);
                GM_setValue('115_transfer_method', newTransferMethod);
                GM_setValue('symedia_url', newSymediaUrl);
                GM_setValue('symedia_token', newSymediaToken);
                GM_setValue('115_enable_transfer', newEnableTransfer);

                state.embyCache.clear();
                state.processedItems.clear();
                state.processingItems.clear();
                state.transferButtonsInitialized = false;

                Logger.addLog('✅ 所有设置已保存', 'success');
                overlay.remove();

                processAllPosters();
                
                if (Utils.isUserPage()) {
                    processUserPageButtons();
                } else if (Utils.isParentPage()) {
                    addButtons();
                }
            };

            SettingsManager.refreshLogContent();

            const style = document.createElement('style');
            style.textContent = `
                @keyframes tmOverlayIn {
                    from { opacity: 0; }
                    to { opacity: 1; }
                }
                @keyframes tmModalIn {
                    from { opacity: 0; transform: scale(0.96) translateY(8px); }
                    to { opacity: 1; transform: scale(1) translateY(0); }
                }
                @keyframes tmTabFade {
                    from { opacity: 0; transform: translateY(6px); }
                    to { opacity: 1; transform: translateY(0); }
                }
                .tm-tab-btn {
                    padding: 8px 16px;
                    border: none;
                    background: rgba(0, 0, 0, 0.04);
                    color: #333;
                    cursor: pointer;
                    font-size: 13px;
                    border-radius: 10px;
                    transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
                    font-weight: 600;
                }
                .tm-tab-btn:hover {
                    background: rgba(255, 255, 255, 0.7);
                    color: #111;
                }
                .tm-tab-btn.active {
                    background: rgba(255, 255, 255, 0.9);
                    color: #1565C0;
                    font-weight: 700;
                    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.06);
                }
                .tm-tab-content { display: none; }
                .tm-tab-content.active { display: block; animation: tmTabFade 0.3s ease; }
                .tm-tab-content > div {
                    background: rgba(255, 255, 255, 0.3);
                    border-radius: 16px;
                    padding: 20px;
                    border: 1px solid rgba(255, 255, 255, 0.5);
                }
                #tm-settings-modal input[type="text"],
                #tm-settings-modal input[type="password"],
                #tm-settings-modal select {
                    background: rgba(255, 255, 255, 0.45) !important;
                    border: 1px solid rgba(0, 0, 0, 0.07) !important;
                    border-radius: 12px !important;
                    padding: 10px 14px !important;
                    transition: all 0.25s ease;
                    font-size: 13px !important;
                    color: #333;
                    box-sizing: border-box;
                }
                #tm-settings-modal input[type="text"]:focus,
                #tm-settings-modal input[type="password"]:focus,
                #tm-settings-modal select:focus {
                    background: rgba(255, 255, 255, 0.8) !important;
                    border-color: rgba(33, 150, 243, 0.35) !important;
                    box-shadow: 0 0 0 4px rgba(33, 150, 243, 0.08), 0 2px 8px rgba(33, 150, 243, 0.06);
                    outline: none;
                }
                #tm-settings-modal input[type="checkbox"] {
                    width: 16px;
                    height: 16px;
                    accent-color: #2196F3;
                    cursor: pointer;
                }
                #tm-settings-modal button {
                    border-radius: 10px !important;
                    transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
                    font-weight: 500;
                }
                #tm-settings-modal button:hover {
                    transform: translateY(-1px);
                    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
                }
                #tm-settings-modal button:active {
                    transform: translateY(0) scale(0.98);
                    transition: all 0.1s ease;
                }
                .tm-close-btn:hover {
                    background: rgba(0, 0, 0, 0.1) !important;
                    color: #333 !important;
                    transform: scale(1.08) !important;
                    box-shadow: none !important;
                }
                .tm-btn-cancel:hover {
                    background: rgba(255, 255, 255, 0.8) !important;
                    border-color: rgba(0, 0, 0, 0.12) !important;
                    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06) !important;
                }
                .tm-btn-save:hover {
                    box-shadow: 0 8px 24px rgba(76, 175, 80, 0.35) !important;
                    transform: translateY(-2px) !important;
                }
                #tm-settings-modal h4 {
                    color: #1a1a2e !important;
                    font-weight: 600;
                    font-size: 14px;
                    padding-left: 12px;
                    border-left: 3px solid #2196F3;
                    margin-top: 0;
                    margin-bottom: 14px;
                    line-height: 1.4;
                }
                #tm-settings-modal label {
                    color: #444 !important;
                    font-size: 13px;
                }
                #tm-settings-modal ::-webkit-scrollbar {
                    width: 5px;
                }
                #tm-settings-modal ::-webkit-scrollbar-track {
                    background: transparent;
                }
                #tm-settings-modal ::-webkit-scrollbar-thumb {
                    background: rgba(0, 0, 0, 0.1);
                    border-radius: 3px;
                }
                #tm-settings-modal ::-webkit-scrollbar-thumb:hover {
                    background: rgba(0, 0, 0, 0.2);
                }
                .tm-custom-select {
                    position: relative;
                    width: 100%;
                    user-select: none;
                }
                .tm-custom-select-trigger {
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    padding: 10px 14px;
                    background: rgba(255, 255, 255, 0.45);
                    border: 1px solid rgba(0, 0, 0, 0.07);
                    border-radius: 12px;
                    cursor: pointer;
                    transition: all 0.25s ease;
                    font-size: 13px;
                    color: #333;
                }
                .tm-custom-select-trigger:hover {
                    background: rgba(255, 255, 255, 0.65);
                    border-color: rgba(0, 0, 0, 0.12);
                }
                .tm-custom-select.open .tm-custom-select-trigger {
                    background: rgba(255, 255, 255, 0.8);
                    border-color: rgba(33, 150, 243, 0.35);
                    box-shadow: 0 0 0 4px rgba(33, 150, 243, 0.08), 0 2px 8px rgba(33, 150, 243, 0.06);
                }
                .tm-select-arrow {
                    display: flex;
                    align-items: center;
                    color: #999;
                    transition: transform 0.25s ease;
                }
                .tm-custom-select.open .tm-select-arrow {
                    transform: rotate(180deg);
                    color: #1565C0;
                }
                .tm-custom-select-dropdown {
                    position: absolute;
                    top: calc(100% + 6px);
                    left: 0;
                    right: 0;
                    background: rgba(255, 255, 255, 0.92);
                    backdrop-filter: blur(20px);
                    -webkit-backdrop-filter: blur(20px);
                    border: 1px solid rgba(0, 0, 0, 0.08);
                    border-radius: 12px;
                    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);
                    overflow: hidden;
                    z-index: 100;
                    opacity: 0;
                    visibility: hidden;
                    transform: translateY(-8px) scale(0.98);
                    transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
                    pointer-events: none;
                }
                .tm-custom-select.open .tm-custom-select-dropdown {
                    opacity: 1;
                    visibility: visible;
                    transform: translateY(0) scale(1);
                    pointer-events: auto;
                }
                .tm-select-option {
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    padding: 10px 14px;
                    font-size: 13px;
                    color: #444;
                    cursor: pointer;
                    transition: background 0.15s ease;
                }
                .tm-select-option:hover {
                    background: rgba(33, 150, 243, 0.06);
                }
                .tm-select-option.selected {
                    color: #1565C0;
                    font-weight: 600;
                }
                .tm-select-option + .tm-select-option {
                    border-top: 1px solid rgba(0, 0, 0, 0.04);
                }
                .tm-select-check {
                    color: #1565C0;
                    font-weight: 700;
                    font-size: 14px;
                }
            `;
            modal.appendChild(style);
        },

        refreshLogContent: () => {
            const logContainer = document.querySelector('#tm-settings-log-content');
            if (!logContainer || !Logger.logContent) return;
            logContainer.innerHTML = Logger.logContent.innerHTML || '<div style="text-align:center;color:#999;padding:20px;">暂无日志</div>';
        },

        showFolderBrowser: async () => {
            if (document.querySelector('#tm-folder-browser')) return;

            const overlay = document.createElement('div');
            overlay.id = 'tm-folder-browser';
            Object.assign(overlay.style, {
                position: 'fixed',
                top: '0',
                left: '0',
                width: '100%',
                height: '100%',
                background: 'rgba(0,0,0,0.5)',
                zIndex: 10002,
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center'
            });

            const modal = document.createElement('div');
            Object.assign(modal.style, {
                background: '#fff',
                padding: '20px',
                borderRadius: '10px',
                width: '500px',
                maxHeight: '80vh',
                boxShadow: '0 6px 20px rgba(0,0,0,0.3)',
                fontFamily: 'Arial, sans-serif',
                display: 'flex',
                flexDirection: 'column'
            });

            modal.innerHTML = `
                <h3 style="margin-top:0;margin-bottom:15px;color:#333">浏览文件夹</h3>
                <div id="tm-current-path" style="margin-bottom:10px;padding:8px;background:#f5f5f5;border-radius:4px;font-size:12px;">根目录</div>
                <div id="tm-folders-list" style="flex:1;overflow-y:auto;margin-bottom:15px;min-height:200px;border:1px solid #eee;border-radius:4px;">
                    <div style="text-align:center;padding:40px 0;color:#999;">加载中...</div>
                </div>
                <div style="display:flex;justify-content:space-between;gap:10px;">
                    <button id="tm-folder-back" style="flex:1;padding:8px 12px;border:none;border-radius:4px;background:#ccc;color:#fff;cursor:pointer;font-size:12px;">返回上级</button>
                    <button id="tm-folder-cancel" style="flex:1;padding:8px 12px;border:none;border-radius:4px;background:#ccc;color:#fff;cursor:pointer;font-size:12px;">取消</button>
                    <button id="tm-folder-select" style="flex:1;padding:8px 12px;border:none;border-radius:4px;background:#4CAF50;color:#fff;cursor:pointer;font-size:12px;">选择</button>
                </div>
            `;

            overlay.appendChild(modal);
            document.body.appendChild(overlay);

            let currentCid = 0;
            let currentPath = ["根目录"];
            let cidStack = [];
            let pathStack = [];

            const getFolders = async (cid = 0) => {
                const cookie = GM_getValue('115_cookie');
                if (!cookie) {
                    Logger.addLog('❌ 获取文件夹失败:Cookie 未设置', 'error');
                    return [];
                }

                return new Promise((resolve) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: `https://webapi.115.com/files?aid=1&cid=${cid}&show_dir=1&nsprefix=1`,
                        headers: {
                            "Cookie": cookie,
                            "User-Agent": "Mozilla/5.0"
                        },
                        onload: (response) => {
                            try {
                                const data = JSON.parse(response.responseText);
                                if (data.state && data.data) {
                                    const folders = data.data
                                        .filter(item => item.fl && item.fl.length === 0)
                                        .map(item => ({
                                            name: item.n,
                                            cid: item.cid
                                        }));
                                    resolve(folders);
                                } else {
                                    resolve([]);
                                }
                            } catch (e) {
                                resolve([]);
                            }
                        },
                        onerror: () => resolve([])
                    });
                });
            };

            const loadFolders = async (cid = 0) => {
                const foldersList = document.getElementById('tm-folders-list');
                foldersList.innerHTML = '<div style="text-align:center;padding:40px 0;color:#999;">加载中...</div>';

                const folders = await getFolders(cid);

                if (folders.length === 0) {
                    foldersList.innerHTML = '<div style="text-align:center;padding:40px 0;color:#999;">该目录下没有文件夹</div>';
                    return;
                }

                foldersList.innerHTML = '';
                folders.forEach(folder => {
                    const folderItem = document.createElement('div');
                    Object.assign(folderItem.style, {
                        padding: '10px',
                        borderBottom: '1px solid #eee',
                        cursor: 'pointer',
                        display: 'flex',
                        justifyContent: 'space-between',
                        fontSize: '12px'
                    });
                    folderItem.innerHTML = `
                        <span>${folder.name}</span>
                        <span style="color:#999;">CID: ${folder.cid}</span>
                    `;

                    folderItem.addEventListener('mouseenter', () => {
                        folderItem.style.backgroundColor = '#f5f5f5';
                    });

                    folderItem.addEventListener('mouseleave', () => {
                        folderItem.style.backgroundColor = 'transparent';
                    });

                    folderItem.onclick = () => {
                        cidStack.push(currentCid);
                        pathStack.push([...currentPath]);
                        currentCid = folder.cid;
                        currentPath.push(folder.name);
                        updatePathDisplay();
                        loadFolders(currentCid);
                    };

                    foldersList.appendChild(folderItem);
                });
            };

            const updatePathDisplay = () => {
                const pathElement = document.getElementById('tm-current-path');
                pathElement.textContent = currentPath.join(' / ');
            };

            modal.querySelector('#tm-folder-back').onclick = () => {
                if (cidStack.length > 0) {
                    currentCid = cidStack.pop();
                    currentPath = pathStack.pop();
                    updatePathDisplay();
                    loadFolders(currentCid);
                }
            };

            modal.querySelector('#tm-folder-cancel').onclick = () => {
                overlay.remove();
            };

            modal.querySelector('#tm-folder-select').onclick = () => {
                if (currentCid !== 0) {
                    const cidInput = document.querySelector('#tm-cid-input');
                    if (cidInput) {
                        cidInput.value = currentCid;
                    }
                    Logger.addLog(`已选择文件夹: ${currentPath.join(' / ')} (CID: ${currentCid})`, 'success');
                }
                overlay.remove();
            };

            await loadFolders(currentCid);
            updatePathDisplay();
        },

        addSettingButton: () => {
            const checkInterval = setInterval(() => {
                const titleEl = Array.from(document.querySelectorAll('span[class*="MuiBox-root"][class*="mui-"]'))
                    .find(el => el.textContent && el.textContent.includes('HDHIVE'));
                if (titleEl) {
                    clearInterval(checkInterval);

                    if (document.querySelector('.emby-setting-btn')) return;

                    const btn = EmbyHelper.createSettingButton();
                    btn.addEventListener('click', (e) => {
                        e.stopPropagation();
                        e.preventDefault();
                        SettingsManager.showSettingsModal();
                    });

                    titleEl.parentNode.insertBefore(btn, titleEl.nextSibling);
                }
            }, 500);
        }
    };

    async function processPoster(poster) {
        const itemKey = `poster-${poster.href}`;
        if (state.processedItems.has(itemKey) || state.processingItems.has(itemKey)) {
            return;
        }
        state.processingItems.add(itemKey);
        const info = EmbyHelper.extractInfoFromPoster(poster);
        if (!info) {
            state.processingItems.delete(itemKey);
            return;
        }
        try {
            const hasResource = await EmbyHelper.checkEmbyResource(info.name, info.year);
            if (!poster.querySelector('.emby-poster-btn')) {
                const posterImageContainer = poster.querySelector('div[class*="Box-root"]');
                if (posterImageContainer) {
                    const btn = EmbyHelper.createPosterButton(hasResource);
                    posterImageContainer.style.position = 'relative';
                    posterImageContainer.appendChild(btn);
                }
            }
            if (!poster.querySelector('.emby-name-btn') && !poster.querySelector('.emby-collection-btn') && !Utils.isCollectionPage()) {
                const yearElement = info.element.querySelector('p[class*="MuiTypography-body1"][class*="mui-"]');
                if (yearElement) {
                    const btn = EmbyHelper.createNameButton(hasResource);
                    const buttonContainer = document.createElement('div');
                    buttonContainer.style.display = 'flex';
                    buttonContainer.style.justifyContent = 'center';
                    buttonContainer.style.width = '100%';
                    buttonContainer.appendChild(btn);
                    yearElement.parentNode.insertBefore(buttonContainer, yearElement.nextSibling);
                }
            }
            state.processedItems.add(itemKey);
        } catch (error) {
        } finally {
            state.processingItems.delete(itemKey);
        }
    }

    async function processDetailPage() {
        if (!Utils.isDetailPage()) return;
        const detailKey = 'detail-page';
        if (state.processedItems.has(detailKey) || state.processingItems.has(detailKey)) {
            return;
        }
        state.processingItems.add(detailKey);
        const info = EmbyHelper.extractInfoFromDetail();
        if (!info) {
            state.processingItems.delete(detailKey);
            return;
        }
        try {
            const hasResource = await EmbyHelper.checkEmbyResource(info.name, info.year);
            if (!document.querySelector('.emby-detail-poster-btn')) {
                const posterImage = document.querySelector('img.poster-item, img[alt*="海报"], img[class*="poster"]');
                let posterContainer = null;
                
                if (posterImage) {
                    posterContainer = posterImage.closest('div[class*="Box-root"]');
                }
                
                if (!posterContainer) {
                    posterContainer = document.querySelector('div[class*="Box-root"]');
                }
                
                if (posterContainer) {
                    const btn = EmbyHelper.createDetailPosterButton(hasResource);
                    posterContainer.style.position = 'relative';
                    posterContainer.appendChild(btn);
                }
            }
            if (!document.querySelector('.emby-detail-title-btn')) {
                const titleElement = document.querySelector('h1');
                if (titleElement) {
                    const btn = EmbyHelper.createDetailTitleButton(hasResource);
                    titleElement.parentNode.insertBefore(btn, titleElement.nextSibling);
                }
            }
            
            state.processedItems.add(detailKey);
        } catch (error) {
        } finally {
            state.processingItems.delete(detailKey);
        }
    }

    async function processSearchYearButtons() {
        const resultItems = document.querySelectorAll('a[href*="/tmdb/"]');
        for (const item of resultItems) {
            const itemKey = `search-${item.href}`;
            if (state.processedItems.has(itemKey) || state.processingItems.has(itemKey)) {
                continue;
            }
            state.processingItems.add(itemKey);
            const yearText = item.querySelector('[class*="MuiTypography-body2"][class*="mui-"]');
            if (yearText && yearText.textContent.includes('(')) {
                const info = EmbyHelper.extractInfoFromSearchYear(yearText);
                if (info) {
                    try {
                        const hasResource = await EmbyHelper.checkEmbyResource(info.name, info.year);
                        if (!yearText.parentNode.querySelector('.emby-search-year-btn')) {
                            const btn = EmbyHelper.createSearchYearButton(hasResource);
                            yearText.parentNode.insertBefore(btn, yearText.nextSibling);
                        }
                    } catch (error) {
                    }
                }
            }
            state.processedItems.add(itemKey);
            state.processingItems.delete(itemKey);
        }
    }

    async function processCollectionButtons() {
        if (!Utils.isCollectionPage()) return;
        const collectionItems = document.querySelectorAll('a[href*="/tmdb/"]');
        for (const item of collectionItems) {
            const itemKey = `collection-${item.href}`;
            if (state.processedItems.has(itemKey) || state.processingItems.has(itemKey)) {
                continue;
            }
            state.processingItems.add(itemKey);
            const info = EmbyHelper.extractInfoFromCollection(item);
            if (info) {
                try {
                    const hasResource = await EmbyHelper.checkEmbyResource(info.name, info.year);
                    if (!item.querySelector('.emby-poster-btn')) {
                        const posterImageContainer = item.querySelector('div[class*="Box-root"]');
                        if (posterImageContainer) {
                            const btn = EmbyHelper.createPosterButton(hasResource);
                            posterImageContainer.style.position = 'relative';
                            posterImageContainer.appendChild(btn);
                        }
                    }
                    if (!item.querySelector('.emby-collection-btn') && !item.querySelector('.emby-name-btn')) {
                        const btn = EmbyHelper.createCollectionButton(hasResource);
                        const yearElement = info.element.querySelector('p[class*="MuiTypography-body1"][class*="mui-"]');
                        if (yearElement) {
                            const buttonContainer = document.createElement('div');
                            buttonContainer.style.display = 'flex';
                            buttonContainer.style.justifyContent = 'center';
                            buttonContainer.style.width = '100%';
                            buttonContainer.appendChild(btn);
                            yearElement.parentNode.insertBefore(buttonContainer, yearElement.nextSibling);
                        }
                    }
                } catch (error) {
                }
            }
            state.processedItems.add(itemKey);
            state.processingItems.delete(itemKey);
        }
        
        const resource115Links = document.querySelectorAll('a[href*="/resource/115/"]');
        
        resource115Links.forEach(link => {
            const container = link.closest('a[class*="MuiBox-root"]');
            if (!container || container.querySelector('.one-click-transfer-btn')) return;

            let resourceType = 'unknown';
            let cost = '';
            
            const chips = container.querySelectorAll('[class*="MuiChip-root"][class*="mui-"]');
            
            chips.forEach(chip => {
                const chipText = chip.textContent.trim();
                if (chipText.includes('免费')) {
                    resourceType = 'free';
                } else if (chipText.includes('已解锁')) {
                    resourceType = 'unlocked';
                } else if (chipText.includes('积分')) {
                    resourceType = 'paid';
                    const match = chipText.match(/(\d+)\s*积分/);
                    if (match) cost = match[1];
                }
            });

            Logger.updateStats(resourceType);

            const btn = EmbyHelper.createTransferButton();
            
            btn.onclick = (e) => {
                e.preventDefault();
                e.stopPropagation();

                let logType = '';
                if (resourceType === 'paid' && cost) logType = `${cost}积分`;
                else if (resourceType === 'free') logType = '免费';
                else if (resourceType === 'unlocked') logType = '已解锁';
                else logType = '未知类型';
                
                const rawTarget = `${location.origin}${link.getAttribute('href')}`;

                if (Logger.isLinkProcessed(rawTarget)) {
                    Logger.addLog(`该资源已在处理中,请勿重复点击`, 'process');
                    return;
                }
                Logger.markLinkAsProcessed(rawTarget);

                Logger.startNewTask(rawTarget);
                Logger.addLog(`开始处理链接 [${logType}] <a href="${rawTarget}" target="_blank">${rawTarget}</a>`,'process');

                const finalType = (resourceType === 'free' || resourceType === 'unlocked') ? 'free' : (resourceType === 'paid' ? 'paid' : 'user_auto');
                const processedTarget = `${rawTarget}?autotransfer=1&type=${finalType}`;
                window.open(processedTarget, '_blank', `width=300,height=200,left=0,top=100,resizable=yes,scrollbars=yes`);
            };
            
            const descriptionElement = container.querySelector('p[class*="MuiTypography-root"][class*="MuiTypography-body2"][aria-label]');
            
            if (descriptionElement) {
                const descriptionContainer = descriptionElement.parentElement;
                
                const buttonWrapper = document.createElement('div');
                buttonWrapper.style.marginTop = '8px';
                buttonWrapper.style.width = '100%';
                buttonWrapper.style.display = 'flex';
                buttonWrapper.style.justifyContent = 'flex-end';
                buttonWrapper.appendChild(btn);
                
                descriptionContainer.appendChild(buttonWrapper);
            } else {
                const topSection = container.querySelector('[class*="MuiStack-root"]');
                if (topSection) {
                    const buttonWrapper = document.createElement('div');
                    buttonWrapper.style.marginTop = '8px';
                    buttonWrapper.style.width = '100%';
                buttonWrapper.style.display = 'flex';
                buttonWrapper.style.justifyContent = 'flex-end';
                    buttonWrapper.appendChild(btn);
                    topSection.parentNode.insertBefore(buttonWrapper, topSection.nextSibling);
                }
            }
        });
    }

    async function processUserPageButtons() {
        const elements = Array.from(document.querySelectorAll('h6[class*="MuiTypography-subtitle2"][class*="mui-"]'))
                              .filter(el => /\(\d{4}\)/.test(el.textContent));

        const uniqueMovies = new Map();
        
        for (const el of elements) {
            const info = EmbyHelper.extractInfoFromUserPage(el);
            if (info) {
                const cacheKey = `${info.name}-${info.year}`;
                if (!uniqueMovies.has(cacheKey)) {
                    uniqueMovies.set(cacheKey, {
                        name: info.name,
                        year: info.year,
                        elements: [],
                        containers: []
                    });
                }
                uniqueMovies.get(cacheKey).elements.push(el);
                const container = el.closest('[class*="MuiGrid"][class*="mui-"]');
                if (container) {
                    uniqueMovies.get(cacheKey).containers.push(container);
                }
            }
        }

        for (const [cacheKey, movie] of uniqueMovies) {
            const itemKey = `user-${cacheKey}`;
            if (state.processedItems.has(itemKey) || state.processingItems.has(itemKey)) {
                continue;
            }
            state.processingItems.add(itemKey);
            
            try {
                const hasResource = await EmbyHelper.checkEmbyResource(movie.name, movie.year);
                
                const containers115 = movie.containers.filter(container => {
                    return Utils.getDiskType(container) === '115';
                });
                
                const elements115 = containers115.map(container => {
                    return container.querySelector('h6[class*="MuiTypography-subtitle2"][class*="mui-"]');
                }).filter(el => el);
                
                let targetEl, targetContainer;
                
                if (elements115.length > 0) {
                    const randomIndex = Math.floor(Math.random() * elements115.length);
                    targetEl = elements115[randomIndex];
                    targetContainer = containers115[randomIndex];
                } else if (movie.elements.length > 0) {
                    const randomIndex = Math.floor(Math.random() * movie.elements.length);
                    targetEl = movie.elements[randomIndex];
                    targetContainer = movie.containers[randomIndex];
                }
                
                if (targetEl && !targetEl.querySelector('.emby-user-page-btn')) {
                    const btn = EmbyHelper.createUserPageButton(hasResource);
                    targetEl.appendChild(btn);
                }
                
                if (targetContainer) {
                    const imageContainers = targetContainer.querySelectorAll('div[class*="MuiBox-root"]');
                    let imageContainer = null;
                    
                    for (const container of imageContainers) {
                        if (container.querySelector('img') || container.style.backgroundImage) {
                            imageContainer = container;
                            break;
                        }
                    }
                    
                    if (imageContainer && !imageContainer.querySelector('.emby-poster-btn')) {
                        const posterBtn = EmbyHelper.createPosterButton(hasResource);
                        posterBtn.style.position = 'absolute';
                        posterBtn.style.top = '10px';
                        posterBtn.style.left = '10px';
                        posterBtn.style.right = 'auto';
                        posterBtn.style.zIndex = '10';
                        imageContainer.style.position = 'relative';
                        imageContainer.appendChild(posterBtn);
                    }
                }
            } catch (error) {
            } finally {
                state.processedItems.add(itemKey);
                state.processingItems.delete(itemKey);
            }
        }

        document.querySelectorAll('[class*="MuiGrid"][class*="mui-"]').forEach(container => {
            if (container.querySelector('.one-click-transfer-btn')) return;

            const link = container.querySelector('a[href*="/resource/"]');
            if (!link) return;

            const diskType = Utils.getDiskType(container);
            if (diskType !== '115') return;

            let resourceType = 'unknown';
            let cost = '';
            
            const chips = container.querySelectorAll('[class*="MuiChip-root"][class*="mui-"]');
            
            chips.forEach(chip => {
                const chipText = chip.textContent.trim();
                if (chipText.includes('免费')) {
                    resourceType = 'free';
                } else if (chipText.includes('已解锁')) {
                    resourceType = 'unlocked';
                } else if (chipText.includes('积分')) {
                    resourceType = 'paid';
                    const match = chipText.match(/(\d+)\s*积分/);
                    if (match) cost = match[1];
                }
            });

            const btn = EmbyHelper.createTransferButton();
            
            btn.onclick = (e) => {
                e.preventDefault();
                e.stopPropagation();

                let logType = '';
                if (resourceType === 'paid' && cost) logType = `${cost}积分`;
                else if (resourceType === 'free') logType = '免费';
                else if (resourceType === 'unlocked') logType = '已解锁';
                else logType = '未知类型';
                
                const rawTarget = `${location.origin}${link.getAttribute('href')}`;

                if (Logger.isLinkProcessed(rawTarget)) {
                    Logger.addLog(`⚠️ 该资源已在处理中,请勿重复点击`, 'process');
                    return;
                }
                Logger.markLinkAsProcessed(rawTarget);

                Logger.startNewTask(rawTarget);
                Logger.addLog(`开始处理链接 [${logType}] <a href="${rawTarget}" target="_blank">${rawTarget}</a>`,'process');

                const finalType = (resourceType === 'free' || resourceType === 'unlocked') ? 'free' : (resourceType === 'paid' ? 'paid' : 'user_auto');
                const processedTarget = `${rawTarget}?autotransfer=1&type=${finalType}`;
                window.open(processedTarget, '_blank', `width=300,height=200,left=0,top=100,resizable=yes,scrollbars=yes`);
            };
            
            const descriptionElement = container.querySelector('p[class*="MuiTypography-root"][class*="MuiTypography-body2"]');
            
            const buttonWrapper = document.createElement('div');
            buttonWrapper.style.marginTop = '8px';
            buttonWrapper.style.width = '100%';
                buttonWrapper.style.display = 'flex';
                buttonWrapper.style.justifyContent = 'flex-end';
            buttonWrapper.appendChild(btn);
            
            if (descriptionElement) {
                descriptionElement.parentElement.appendChild(buttonWrapper);
            } else {
                const titleElement = container.querySelector('h6[class*="MuiTypography-root"]');
                if (titleElement && titleElement.parentElement) {
                    titleElement.parentElement.appendChild(buttonWrapper);
                }
            }
        });
    }

    async function processAllPosters() {
        const posters = document.querySelectorAll('a[href*="/movie/"], a[href*="/tv/"]');
        for (const poster of posters) {
            await processPoster(poster);
        }
        
        const popoverPosters = document.querySelectorAll('a[href*="/movie/"], a[href*="/tv/"]');
        for (const poster of popoverPosters) {
            await processPoster(poster);
        }
        
        await processDetailPage();
        await processSearchYearButtons();
        await processCollectionButtons();
        if (Utils.isUserPage()) {
            FilterManager.injectBar();
            await processUserPageButtons();
        }
    }

    function removeButtons(){document.querySelectorAll('.one-click-transfer-btn, .detail-page-transfer-btn').forEach(b=>b.remove());}
    
    function addButtons(){
        const resourceContainers = document.querySelectorAll('[class*="MuiGrid"][class*="mui-"]');
        
        resourceContainers.forEach((container)=>{
            
            if(container.querySelector('.one-click-transfer-btn')) {
                return;
            }
            
            const link=container.querySelector('a[href^="/resource/"]');
            if(!link) {
                return;
            }
            
            const is115 = link.href.includes('/resource/115/');
            if (!is115) {
                return;
            }

            let type='unknown'; let cost=''; 
            const chips = container.querySelectorAll('[class*="MuiChip-root"][class*="mui-"]');
            
            chips.forEach(chip=>{
                const t=chip.textContent.trim();
                if(t.includes('免费')) {
                    type='free';
                } else if(t.includes('已解锁')) {
                    type='unlocked';
                } else if(t.includes('积分')){
                    type='paid';
                    const match = t.match(/(\d+)\s*积分/);
                    if(match) cost = match[1];
                }
            });
            
            Logger.updateStats(type);

            const btn=EmbyHelper.createTransferButton();

            btn.onclick=(e)=>{
                e.preventDefault(); e.stopPropagation();
                let logType = '';
                if(type === 'paid' && cost) logType = `${cost}积分`;
                else if(type === 'free') logType = '免费';
                else if(type === 'unlocked') logType = '已解锁';
                else logType = '未知类型';
                
                const rawTarget=`${location.origin}${link.getAttribute('href')}`;

                if (Logger.isLinkProcessed(rawTarget)) {
                    Logger.addLog(`⚠️ 该资源已在处理中,请勿重复点击`, 'process');
                    return;
                }
                Logger.markLinkAsProcessed(rawTarget);

                Logger.startNewTask(rawTarget);
                Logger.addLog(`开始处理链接 [${logType}] <a href="${rawTarget}" target="_blank">${rawTarget}</a>`,'process');

                const finalType = (type === 'free' || type === 'unlocked') ? 'free' : type;
                const processedTarget=`${rawTarget}?autotransfer=1&type=${finalType}`;
                window.open(processedTarget,'_blank',`width=300,height=200,left=0,top=100,resizable=yes,scrollbars=yes`);
            };
            
            const descriptionElement = container.querySelector('p[class*="MuiTypography-root"][class*="MuiTypography-body2"][aria-label]');
            
            if (descriptionElement) {
                const descriptionContainer = descriptionElement.parentElement;
                
                const buttonWrapper = document.createElement('div');
                buttonWrapper.style.marginTop = '8px';
                buttonWrapper.style.width = '100%';
                buttonWrapper.style.display = 'flex';
                buttonWrapper.style.justifyContent = 'flex-end';
                buttonWrapper.appendChild(btn);
                
                descriptionContainer.appendChild(buttonWrapper);
            } else {
                const topSection = container.querySelector('[class*="MuiStack-root"]');
                if (topSection) {
                    const buttonWrapper = document.createElement('div');
                    buttonWrapper.style.marginTop = '8px';
                    buttonWrapper.style.width = '100%';
                buttonWrapper.style.display = 'flex';
                buttonWrapper.style.justifyContent = 'flex-end';
                    buttonWrapper.appendChild(btn);
                    topSection.parentNode.insertBefore(buttonWrapper, topSection.nextSibling);
                }
            }
        });
    }

    function initParentPage() {
        window.addEventListener('message',(event)=>{
            if(event.data && event.data.type==='HDHIVE_RESULT'){
                const {status,url,error,step}=event.data;
                if(status==='success') {
                    if (Logger.isLinkProcessed(url)) {
                        return;
                    }
                    Logger.markLinkAsProcessed(url);
                    Logger.addLog(`✅ <b>获取成功</b>: <a href="${url}" target="_blank">${url}</a>`,'success');
                    handleTransfer115(url);
                }
                else if(status==='process') {
                    if (!Logger.isLinkProcessed(`process_${step}`)) {
                        Logger.markLinkAsProcessed(`process_${step}`);
                        Logger.addLog(`👉 ${step}`,'process');
                    }
                }
                else if(status==='error') Logger.addLog(`❌ <b>失败</b>: ${error}`,'error');
            }
        });

        async function handleTransfer115(url) {
            const enableTransfer = GM_getValue('115_enable_transfer', true);
            
            if (!enableTransfer) {
                Logger.addLog(`<span style="color:#ff9800;">⚠️ 未开启转存,取消转存</span>`, 'error');
                Logger.endCurrentTask('completed');
                return;
            }

            const transferMethod = GM_getValue('115_transfer_method', 'cookie');
            const cid = GM_getValue('115_cid') || '0';
            
            const transferKey = `transfer_${url}`;
            if (Logger.isLinkProcessed(transferKey)) {
                return;
            }
            Logger.markLinkAsProcessed(transferKey);

            let result;

            if (transferMethod === 'cookie') {
                const cookie = GM_getValue('115_cookie');
                if (!cookie) {
                    Logger.addLog('未填写115 Cookie,取消转存', 'process');
                    Logger.endCurrentTask('failed');
                    return;
                }
                result = await Transfer115.transfer(url, cookie, cid);
            } else if (transferMethod === 'symedia') {
                const symediaUrl = GM_getValue('symedia_url', '');
                const symediaToken = GM_getValue('symedia_token', 'symedia');

                if (!symediaUrl) {
                    Logger.addLog('未填写Symedia 地址,取消转存', 'process');
                    Logger.endCurrentTask('failed');
                    return;
                }

                result = await Transfer115.transferBySymedia(url, symediaUrl, symediaToken, cid);
            } else {
                Logger.addLog('未知的转存方式', 'error');
                Logger.endCurrentTask('failed');
                return;
            }

            if (result.success) {
                Logger.addLog(result.message, 'success');
                Logger.endCurrentTask('completed');
            } else {
                if (!result.message.includes('❌') && !result.message.includes('⚠️')) {
                    Logger.addLog(`❌ ${result.message}`, 'error');
                } else {
                    Logger.addLog(result.message, 'error');
                }
                Logger.endCurrentTask('failed');
            }
        }

        function is115Tab(){return document.querySelector('[class*="MuiTab-root"][class*="mui-"][class*="selected"], [class*="MuiTab-root"][class*="Mui-selected"]')?.textContent?.includes('115网盘');}
        function startObserver(){
            new MutationObserver(()=>{
                if(is115Tab()) {
                    addButtons();
                } else {
                    removeButtons();
                }
            }).observe(document.body,{childList:true,subtree:true});
            if(is115Tab()) addButtons();
        }
        
        if (Utils.isUserPage()) {
            new MutationObserver(async () => {
                await processUserPageButtons();
            }).observe(document.body, { childList: true, subtree: true });
            
            processUserPageButtons();
        } else {
            addButtons();
            startObserver();
        }
    }

    function initChildPage(){
        const params=new URLSearchParams(location.search);
        if(!params.has('autotransfer')) return;

        const type=params.get('type');
        let isFinished=false;
        
        const send=(data)=>window.opener && window.opener.postMessage({type:'HDHIVE_RESULT',...data},'*');
        const log=(step)=>send({status:'process',step});
        const fail=(msg)=>{if(isFinished) return; isFinished=true; clearAllFinders(); send({status:'error',error:msg});};
        
        const success=(rawUrl)=>{
            if(isFinished) return; 
            const check=Utils.verifyAndFormatUrl(rawUrl); 
            if(check.success){
                isFinished=true; 
                clearAllFinders(); 
                send({status:'success',url:check.url}); 
                setTimeout(()=>window.close(),CONFIG.autoCloseDelay);
            } else {
                if(type==='paid' || type==='user_auto') console.log("捕获到无效链接,非最终链接,忽略:",rawUrl); 
                else fail(`链接校验不通过: ${check.msg} (URL: ${rawUrl})`);
            }
        };
        
        const finders=[]; 
        function clearAllFinders(){finders.forEach(id=>{try{clearInterval(id);}catch(e){}; try{clearTimeout(id);}catch(e){};}); finders.length=0;}

        function checkUnlockAndCost() {
             const buttons=Array.from(document.querySelectorAll('button'));
             const unlockBtn=buttons.find(btn=>{
                 const text=Utils.normalizeText(btn.textContent);
                 return text.includes('确定解锁')||(text.includes('解锁')&&!text.includes('取消')&&!text.includes('close'));
             });

             if(unlockBtn && !unlockBtn.dataset.clicked){
                 unlockBtn.dataset.clicked="true";

                 const boxRoots=Array.from(document.querySelectorAll('[class*="MuiBox-root"][class*="mui-"]'));
                 let pointsDiv = boxRoots.find(el=>el.textContent && (el.textContent.includes('积分解锁')||el.textContent.includes('需要使用')||el.textContent.includes('已解锁人数')));
                 
                 if (!pointsDiv) {
                     const allElements = Array.from(document.querySelectorAll('*'));
                     pointsDiv = allElements.find(el => {
                        const text = el.textContent || '';
                        return (text.includes('已解锁人数') && text.includes('积分')) || 
                               (text.includes('需要使用') && text.includes('积分解锁'));
                    });
                 }

                 if (pointsDiv) {
                     const text=pointsDiv.textContent||'';
                     const unlockedMatch=text.match(/已解锁人数\s*[::]?\s*(\d+)/)||text.match(/已解锁\s*(\d+)/)||text.match(/(\d+)/);
                     const unlockedCount=unlockedMatch?unlockedMatch[1]:'未知';
                     const pointsMatch=text.match(/需要使用\s*(\d+)\s*积分/)||text.match(/消耗[::]?\s*(\d+)\s*积分/)||text.match(/(\d+)\s*积分/);
                     const pointsCount=pointsMatch?pointsMatch[1]:'未知';
                     log(`已解锁 ${unlockedCount} 人`);
                    log(`需要 ${pointsCount} 积分`);
                 }

                 log('找到解锁按钮');

                 if (Utils.isSafari) {
                    unlockBtn.dispatchEvent(new MouseEvent('click',{bubbles:true,cancelable:true,view:window}));
                 } else {
                    try{unlockBtn.click();}
                    catch(e){unlockBtn.dispatchEvent(new MouseEvent('click',{bubbles:true,cancelable:true,view:window})); log(' click() 失败,改用dispatchEvent');}
                 }
                 return true;
             }
             return false;
        }

        if(type === 'paid' || type === 'user_auto'){
            const unlockFinder=setInterval(()=>{
                if(isFinished) return;
                checkUnlockAndCost();
            }, 300); 
            finders.push(unlockFinder);
        }

        document.addEventListener('DOMContentLoaded',()=>{
            const to=setTimeout(()=>{if(!isFinished) fail('操作超时 (未获取到有效带密码链接)');}, CONFIG.maxWaitTime); 
            finders.push(to);
            
            const observer=new MutationObserver((mutations,obs)=>{
                if(isFinished){obs.disconnect();return;}

                const links=document.querySelectorAll('a');
                for(let a of links){
                    if(a.href && a.href.includes('115')){
                        const check=Utils.verifyAndFormatUrl(a.href);
                        if(check.success){success(a.href);obs.disconnect();return;}
                    }
                }
            });
            observer.observe(document.body,{childList:true,subtree:true});
        });

        const oldXhr=XMLHttpRequest.prototype.open;
        XMLHttpRequest.prototype.open=function(){
            this.addEventListener('load',function(){
                const txt=this.responseText;
                if(txt && (txt.includes('115cdn.com') || txt.includes('115.com/s/'))){
                    const match=txt.match(/https?:\/\/[^\s"']+/);
                    if(match){
                        const check=Utils.verifyAndFormatUrl(match[0]);
                        if(check.success){
                            log('已拦截XHR中的解锁链接');
                            success(match[0]);
                        }
                    }
                }
            });
            return oldXhr.apply(this,arguments);
        };

        const oldOpen=window.open;
        window.open=function(url){
            if(url && (url.includes('115cdn.com') || url.includes('115.com/s/'))){
                const check=Utils.verifyAndFormatUrl(url);
                if(check.success){log('已拦截window.open跳转');success(url);return null;}
            }
            return oldOpen.apply(this,arguments);
        };
    }

    function initFinal115Page(){
        if(!window.opener) return;
        const check=Utils.verifyAndFormatUrl(location.href);
        if(check.success){
            window.opener.postMessage({type:'HDHIVE_RESULT',status:'success',url:check.url},'*');
            window.close();
        }
        else{
            window.opener.postMessage({type:'HDHIVE_RESULT',status:'error',error:`跳转链接无效: ${check.msg}`},'*');
        }
    }

    function init() {
        Logger.init();

        if (Utils.isResourcePage()) {
            initChildPage();
        } else if (Utils.isFinal115Page()) {
            initFinal115Page();
        } else if (Utils.isHDHiveSite()) {
            SettingsManager.addSettingButton();
            
            processAllPosters();
            setupSearchListener();
            setupUrlChangeListener();
            setupSearchDialogListener();

            let mutationTimeout;
            const observer = new MutationObserver(mutations => {
                clearTimeout(mutationTimeout);
                mutationTimeout = setTimeout(() => {
                    let shouldProcess = false;
                    for (const mutation of mutations) {
                        if (mutation.addedNodes.length > 0) {
                            shouldProcess = true;
                            break;
                        }
                    }
                    if (shouldProcess) {
                        processAllPosters();
                        if (Utils.isUserPage()) {
                            setTimeout(() => FilterManager.apply(), 100);
                        }
                    }
                }, 300);
            });

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

            if (Utils.isParentPage() || Utils.isUserPage()) {
                initParentPage();
            }
        }
    }

    function setupSearchListener() {
        const searchInput = document.querySelector('input[type="text"][name="search"]');
        if (searchInput) {
            searchInput.addEventListener('input', () => {
                state.processedItems.clear();
                state.processingItems.clear();
                setTimeout(processAllPosters, 1000);
            });
        }
    }

    function setupUrlChangeListener() {
        let currentUrl = window.location.href;
        const observer = new MutationObserver(() => {
            if (window.location.href !== currentUrl) {
                currentUrl = window.location.href;
                state.processedItems.clear();
                state.processingItems.clear();
                state.embyCache.clear();
                setTimeout(processAllPosters, 1000);
            }
        });
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    function setupSearchDialogListener() {
        const observer = new MutationObserver(() => {
            const searchDialog = document.querySelector('.MuiDialog-paper');
            if (searchDialog) {
                state.processedItems.clear();
                state.processingItems.clear();
                setTimeout(processAllPosters, 500);
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    const style = document.createElement('style');
    style.textContent = `
        .emby-poster-btn {
            position: absolute;
            width: ${BUTTON_STYLES.posterBtn.size};
            height: ${BUTTON_STYLES.posterBtn.size};
            top: 10px;
            left: 10px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            font-weight: bold;
            cursor: pointer;
            z-index: 100;
            box-shadow: 0 4px 15px rgba(0,0,0,0.2);
            transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
            text-shadow: 0 1px 2px rgba(0,0,0,0.2);
        }
        .emby-poster-btn.has {
            background: ${BUTTON_STYLES.posterBtn.has.bg};
            color: white;
            border: ${BUTTON_STYLES.posterBtn.has.border};
        }
        .emby-poster-btn.not-has {
            background: ${BUTTON_STYLES.posterBtn.notHas.bg};
            color: white;
            border: ${BUTTON_STYLES.posterBtn.notHas.border};
        }
        .emby-poster-btn:hover {
            transform: ${BUTTON_STYLES.posterBtn.hoverEffect};
            box-shadow: 0 6px 20px rgba(0,0,0,0.3);
        }
        .emby-name-btn {
            display: inline-flex;
            align-items: center;
            margin-top: ${BUTTON_STYLES.nameBtn.marginTop};
            padding: ${BUTTON_STYLES.nameBtn.padding};
            border-radius: 12px;
            font-size: ${BUTTON_STYLES.nameBtn.fontSize};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            background: transparent;
        }
        .emby-name-btn.has {
            background: ${BUTTON_STYLES.nameBtn.has.bg};
            color: ${BUTTON_STYLES.nameBtn.has.textColor};
            border: ${BUTTON_STYLES.nameBtn.has.border};
        }
        .emby-name-btn.not-has {
            background: ${BUTTON_STYLES.nameBtn.notHas.bg};
            color: ${BUTTON_STYLES.nameBtn.notHas.textColor};
            border: ${BUTTON_STYLES.nameBtn.notHas.border};
        }
        .emby-name-btn:hover {
            transform: ${BUTTON_STYLES.nameBtn.hoverEffect};
            box-shadow: 0 2px 6px rgba(0,0,0,0.15);
        }
        .emby-detail-poster-btn {
            position: absolute;
            width: ${BUTTON_STYLES.detailBtn.posterBtn.size};
            height: ${BUTTON_STYLES.detailBtn.posterBtn.size};
            top: 15px;
            left: 15px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            font-weight: bold;
            cursor: pointer;
            z-index: 100;
            box-shadow: 0 6px 20px rgba(0,0,0,0.3);
            transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
            text-shadow: 0 2px 4px rgba(0,0,0,0.3);
        }
        .emby-detail-poster-btn.has {
            background: ${BUTTON_STYLES.detailBtn.posterBtn.has.bg};
            color: white;
            border: ${BUTTON_STYLES.detailBtn.posterBtn.has.border};
        }
        .emby-detail-poster-btn.not-has {
            background: ${BUTTON_STYLES.detailBtn.posterBtn.notHas.bg};
            color: white;
            border: ${BUTTON_STYLES.detailBtn.posterBtn.notHas.border};
        }
        .emby-detail-poster-btn:hover {
            transform: ${BUTTON_STYLES.detailBtn.posterBtn.hoverEffect};
            box-shadow: 0 8px 25px rgba(0,0,0,0.4);
        }
        .emby-detail-title-btn {
            display: inline-flex;
            align-items: center;
            margin-left: ${BUTTON_STYLES.detailBtn.titleBtn.marginLeft};
            padding: ${BUTTON_STYLES.detailBtn.titleBtn.padding};
            border-radius: 15px;
            font-size: ${BUTTON_STYLES.detailBtn.titleBtn.fontSize};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
            box-shadow: 0 2px 8px rgba(0,0,0,0.15);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            background: transparent;
        }
        .emby-detail-title-btn.has {
            background: ${BUTTON_STYLES.detailBtn.titleBtn.has.bg};
            color: ${BUTTON_STYLES.detailBtn.titleBtn.has.textColor};
            border: ${BUTTON_STYLES.detailBtn.titleBtn.has.border};
        }
        .emby-detail-title-btn.not-has {
            background: ${BUTTON_STYLES.detailBtn.titleBtn.notHas.bg};
            color: ${BUTTON_STYLES.detailBtn.titleBtn.notHas.textColor};
            border: ${BUTTON_STYLES.detailBtn.titleBtn.notHas.border};
        }
        .emby-detail-title-btn:hover {
            transform: ${BUTTON_STYLES.detailBtn.titleBtn.hoverEffect};
            box-shadow: 0 4px 12px rgba(0,0,0,0.2);
        }
        .emby-search-year-btn {
            display: inline-flex;
            align-items: center;
            margin-left: ${BUTTON_STYLES.searchYearBtn.marginLeft};
            padding: ${BUTTON_STYLES.searchYearBtn.padding};
            border-radius: 12px;
            font-size: ${BUTTON_STYLES.searchYearBtn.fontSize};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            background: transparent;
        }
        .emby-search-year-btn.has {
            background: ${BUTTON_STYLES.searchYearBtn.has.bg};
            color: ${BUTTON_STYLES.searchYearBtn.has.textColor};
            border: ${BUTTON_STYLES.searchYearBtn.has.border};
        }
        .emby-search-year-btn.not-has {
            background: ${BUTTON_STYLES.searchYearBtn.notHas.bg};
            color: ${BUTTON_STYLES.searchYearBtn.notHas.textColor};
            border: ${BUTTON_STYLES.searchYearBtn.notHas.border};
        }
        .emby-search-year-btn:hover {
            transform: ${BUTTON_STYLES.searchYearBtn.hoverEffect};
            box-shadow: 0 2px 6px rgba(0,0,0,0.15);
        }
        .emby-user-page-btn {
            display: inline-flex;
            align-items: center;
            margin-left: ${BUTTON_STYLES.userPageBtn.marginLeft};
            padding: ${BUTTON_STYLES.userPageBtn.padding};
            border-radius: 12px;
            font-size: ${BUTTON_STYLES.userPageBtn.fontSize};
            font-weight: 600;
            cursor: default;
            transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            opacity: 0.7;
        }
        .emby-user-page-btn.has {
            background: ${BUTTON_STYLES.userPageBtn.has.bg};
            color: ${BUTTON_STYLES.userPageBtn.has.textColor};
            border: ${BUTTON_STYLES.userPageBtn.has.border};
        }
        .emby-user-page-btn.not-has {
            background: ${BUTTON_STYLES.userPageBtn.notHas.bg};
            color: ${BUTTON_STYLES.userPageBtn.notHas.textColor};
            border: ${BUTTON_STYLES.userPageBtn.notHas.border};
        }
        .emby-user-page-btn:hover {
            transform: ${BUTTON_STYLES.userPageBtn.hoverEffect};
            box-shadow: 0 2px 6px rgba(0,0,0,0.15);
        }
        .emby-collection-btn {
            display: inline-flex;
            align-items: center;
            margin-left: ${BUTTON_STYLES.collectionBtn.marginLeft};
            padding: ${BUTTON_STYLES.collectionBtn.padding};
            border-radius: 12px;
            font-size: ${BUTTON_STYLES.collectionBtn.fontSize};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            background: transparent;
        }
        .emby-collection-btn.has {
            background: ${BUTTON_STYLES.collectionBtn.has.bg};
            color: ${BUTTON_STYLES.collectionBtn.has.textColor};
            border: ${BUTTON_STYLES.collectionBtn.has.border};
        }
        .emby-collection-btn.not-has {
            background: ${BUTTON_STYLES.collectionBtn.notHas.bg};
            color: ${BUTTON_STYLES.collectionBtn.notHas.textColor};
            border: ${BUTTON_STYLES.collectionBtn.notHas.border};
        }
        .emby-collection-btn:hover {
            transform: ${BUTTON_STYLES.collectionBtn.hoverEffect};
            box-shadow: 0 2px 6px rgba(0,0,0,0.15);
        }
        
        .emby-setting-btn {
            display: inline-flex;
            align-items: center;
            padding: ${BUTTON_STYLES.settingBtn.padding};
            margin-left: 10px;
            border-radius: 14px;
            font-size: ${BUTTON_STYLES.settingBtn.fontSize};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            background: ${BUTTON_STYLES.settingBtn.has.bg};
            color: ${BUTTON_STYLES.settingBtn.has.textColor};
            border: ${BUTTON_STYLES.settingBtn.has.border};
            vertical-align: middle;
        }
        .emby-setting-btn:hover {
            transform: ${BUTTON_STYLES.settingBtn.hoverEffect};
            box-shadow: 0 2px 6px rgba(0,0,0,0.15);
        }

        .emby-name-btn::before,
        .emby-detail-title-btn::before,
        .emby-search-year-btn::before,
        .emby-user-page-btn::before,
        .emby-collection-btn::before {
            content: "";
            display: inline-block;
            width: 16px;
            height: 16px;
            margin-right: 6px;
            background-image: url('https://raw.githubusercontent.com/lige47/QuanX-icon-rule/main/icon/04ProxySoft/emby.png');
            background-size: contain;
            background-repeat: no-repeat;
            background-position: center;
            filter: brightness(0.9);
        }
        .emby-detail-title-btn::before {
            width: 18px;
            height: 18px;
            margin-right: 8px;
        }

        .MuiPopover-root .emby-poster-btn,
        .MuiPopover-root .emby-name-btn,
        .MuiPopover-root .emby-detail-poster-btn,
        .MuiPopover-root .emby-detail-title-btn,
        .MuiPopover-root .emby-search-year-btn,
        .MuiPopover-root .emby-user-page-btn,
        .MuiPopover-root .emby-collection-btn,
        .MuiPopover-root .emby-setting-btn {
            z-index: 1500;
        }
        #hdhive-notice {
            position: fixed;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
            padding: 8px 12px;
            background-color: #ff9800;
            color: #fff;
            font-size: 14px;
            font-weight: bold;
            border-radius: 4px;
            z-index: 9999;
            box-shadow: 0 2px 6px rgba(0,0,0,0.3);
        }
    `;
    document.head.appendChild(style);

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();