// ==UserScript== // @name Bilibili & YouTube Tools // @namespace http://tampermonkey.net/ // @version 1.3.0 // @author geraldpeng & claude 4.5 sonnet // @description 跨平台视频工具集:字幕提取、AI总结、Notion集成、笔记保存、播放速度控制、广告跳过 - 支持B站和YouTube // @license MIT // @match *://*/* // @require https://cdn.jsdelivr.net/npm/marked@11.1.0/marked.min.js // @connect api.bilibili.com // @connect aisubtitle.hdslb.com // @connect api.notion.com // @connect openrouter.ai // @connect bsbsb.top // @connect * // @grant GM_addStyle // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant unsafeWindow // @run-at document-start // @downloadURL none // ==/UserScript== (function () { 'use strict'; const e=500,t=20,n=1500,o=500,i=500,s=2e3,r=2e3,a=500,l=12e4,c=2e3,d=2e3,u=32,p="bilibili_notes",h=4718592,g=10,m=100,b=3e3,f="idle",y="loading",v="active",x="no-subtitle",w="error",S="ai-summarizing",k="subtitle:loaded",I="subtitle:failed",T="subtitle:requested",C="ai:summary:start",E="ai:summary:complete",A="ai:summary:failed",$="ai:summary:chunk",_="notion:send:start",P="notion:send:complete",N="notion:send:failed",M="ui:panel:toggle",L="ui:ball:status:change",B="video:changed",D="请用中文总结以下视频字幕内容,使用Markdown格式输出。\n\n要求:\n1. 在开头提供TL;DR(不超过50字的核心摘要)\n2. 使用标题、列表等Markdown格式组织内容\n3. 突出关键信息和要点\n4. 总分结构,分段表示哪部分讲什么内容\n\n字幕内容如下:\n",q='分析以下带时间戳的字幕,提取关键段落。\n\n重要:你的回复必须只包含JSON,不要有任何其他文字、解释或markdown标记。\n\n直接以{开始,以}结束。\n\nJSON格式要求:\n{"segments":[\n {"timestamp":"分钟:秒","title":"标题(10字内)","summary":"内容总结(30-50字)"}\n]}\n\n示例(你的回复应该像这样):\n{"segments":[{"timestamp":"00:15","title":"开场介绍","summary":"主持人介绍今天的主题和嘉宾背景"},{"timestamp":"02:30","title":"核心观点","summary":"讨论技术发展趋势和未来展望"}]}\n\n特别注意:如果视频中存在商业广告推广内容(明确提及产品名称、品牌、购买链接等),请在对应位置添加一个段落,title固定为"广告",timestamp为广告开始时间,summary简述广告内容。\n\n包含广告的示例:\n{"segments":[{"timestamp":"00:15","title":"开场介绍","summary":"主持人介绍今天的主题"},{"timestamp":"02:30","title":"广告","summary":"推广某品牌手机,介绍功能和优惠"},{"timestamp":"04:00","title":"核心观点","summary":"讨论技术发展趋势"}]}\n\n字幕内容:\n',z={openrouter:"https://openrouter.ai/keys",openai:"https://platform.openai.com/api-keys",siliconflow:"https://cloud.siliconflow.cn/account/ak",deepseek:"https://platform.deepseek.com/api_keys",moonshot:"https://platform.moonshot.cn/console/api-keys",zhipu:"https://open.bigmodel.cn/usercenter/apikeys",yi:"https://platform.lingyiwanwu.com/apikeys",dashscope:"https://bailian.console.aliyun.com/",gemini:"https://aistudio.google.com/app/apikey"},R=[{id:"openrouter",name:"OpenRouter",url:"https://openrouter.ai/api/v1/chat/completions",apiKey:"",model:"alibaba/tongyi-deepresearch-30b-a3b:free",prompt1:D,prompt2:q,isOpenRouter:true},{id:"openai",name:"OpenAI",url:"https://api.openai.com/v1/chat/completions",apiKey:"",model:"gpt-3.5-turbo",prompt1:D,prompt2:q,isOpenRouter:false},{id:"siliconflow",name:"硅基流动",url:"https://api.siliconflow.cn/v1/chat/completions",apiKey:"",model:"Qwen/Qwen2.5-7B-Instruct",prompt1:D,prompt2:q,isOpenRouter:false},{id:"deepseek",name:"DeepSeek",url:"https://api.deepseek.com/v1/chat/completions",apiKey:"",model:"deepseek-chat",prompt1:D,prompt2:q,isOpenRouter:false},{id:"moonshot",name:"月之暗面 Kimi",url:"https://api.moonshot.cn/v1/chat/completions",apiKey:"",model:"moonshot-v1-8k",prompt1:D,prompt2:q,isOpenRouter:false},{id:"zhipu",name:"智谱清言",url:"https://open.bigmodel.cn/api/paas/v4/chat/completions",apiKey:"",model:"glm-4-flash",prompt1:D,prompt2:q,isOpenRouter:false},{id:"yi",name:"零一万物",url:"https://api.lingyiwanwu.com/v1/chat/completions",apiKey:"",model:"yi-large",prompt1:D,prompt2:q,isOpenRouter:false},{id:"dashscope",name:"通义千问",url:"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",apiKey:"",model:"qwen-plus",prompt1:D,prompt2:q,isOpenRouter:false},{id:"gemini",name:"Google Gemini",url:"https://generativelanguage.googleapis.com/v1beta/openai/chat/completions",apiKey:"",model:"gemini-1.5-flash",prompt1:D,prompt2:q,isOpenRouter:false}],O="ai_configs",V="selected_ai_config_id",j="ai_auto_summary_enabled",U="notion_api_key",F="notion_parent_page_id",K="notion_database_id",H="notion_auto_send_enabled",Y="notion_content_video_info",G="notion_content_summary",J="notion_content_segments",W="notion_content_subtitles",X="notion_notes_auto_sync_enabled",Q="notion_notes_database_id",Z="bilibili_tools_processed_videos",ee={BALL:2147483647,CONTAINER:2147483646,TOAST:2147483645,AI_MODAL:2147483643},te="2022-06-28",ne="https://api.notion.com/v1",oe=/\/video\/(BV[1-9A-Za-z]{10})/,ie=/BV[1-9A-Za-z]{10}/,se=/([a-f0-9]{32}|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i,re="video",ae=".bpx-player-container, #bilibili-player",le=".bpx-player-ctrl-subtitle-result",ce='.bpx-player-ctrl-subtitle-close-switch[data-action="close"]',de="h1.video-title",ue={API_URL:"https://bsbsb.top/api/skipSegments",CACHE_EXPIRY:18e5,CATEGORIES:{sponsor:{name:"广告",color:"#00d400"},selfpromo:{name:"无偿/自我推广",color:"#ffff00"},interaction:{name:"三连/订阅提醒",color:"#cc00ff"},poi_highlight:{name:"精彩时刻/重点",color:"#ff1684"},intro:{name:"过场/开场动画",color:"#00ffff"},outro:{name:"鸣谢/结束画面",color:"#0202ed"},preview:{name:"回顾/概要",color:"#008fd6"},filler:{name:"离题闲聊/玩笑",color:"#7300FF"},music_offtopic:{name:"音乐:非音乐部分",color:"#ff9900"},exclusive_access:{name:"柔性推广/品牌合作",color:"#008a5c"},mute:{name:"静音片段",color:"#B54D4B"}},DEFAULT_SETTINGS:{skipCategories:["sponsor"],showAdBadge:true,showQualityBadge:true,showProgressMarkers:true}},pe=`\n /* ==================== 小球样式 ==================== */\n #subtitle-ball {\n position: absolute;\n right: -30px;\n top: 50%;\n transform: translateY(-50%);\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background-color: #999;\n cursor: pointer;\n z-index: ${ee.BALL};\n box-shadow: 0 2px 6px rgba(0,0,0,0.25);\n transition: all 0.3s ease;\n animation: breath-ball-normal 2s ease-in-out infinite;\n }\n\n #subtitle-ball:hover {\n transform: translateY(-50%) scale(1.2);\n box-shadow: 0 3px 10px rgba(0,0,0,0.35);\n }\n\n #subtitle-ball.active {\n background-color: #feebea;\n cursor: pointer;\n }\n\n #subtitle-ball.loading {\n background-color: #3b82f6;\n animation: breath-ball 1.2s ease-in-out infinite;\n }\n\n #subtitle-ball.ai-summarizing {\n background-color: #feebea;\n animation: breath-ball-ai 1s ease-in-out infinite;\n }\n\n #subtitle-ball.no-subtitle {\n background-color: #999;\n cursor: default;\n opacity: 0.6;\n }\n\n #subtitle-ball.error {\n background-color: #ff0000;\n cursor: default;\n }\n\n @keyframes breath-ball-normal {\n 0%, 100% { transform: translateY(-50%) scale(1); }\n 50% { transform: translateY(-50%) scale(1.05); }\n }\n\n @keyframes breath-ball {\n 0%, 100% { transform: translateY(-50%) scale(1.1); opacity: 1; }\n 50% { transform: translateY(-50%) scale(1.4); opacity: 0.6; }\n }\n\n @keyframes breath-ball-ai {\n 0%, 100% { \n transform: translateY(-50%) scale(1.3); \n opacity: 1;\n box-shadow: 0 0 20px rgba(254, 235, 234, 0.8);\n }\n 50% { \n transform: translateY(-50%) scale(1.8); \n opacity: 0.7;\n box-shadow: 0 0 40px rgba(254, 235, 234, 1);\n }\n }\n\n /* ==================== 字幕容器样式 ==================== */\n #subtitle-container {\n position: absolute;\n top: 10%;\n left: 100%;\n width: 500px;\n min-width: 400px;\n max-width: 800px;\n height: 600px;\n min-height: 400px;\n max-height: 90vh;\n background: rgba(0, 0, 0, 0.85);\n backdrop-filter: blur(12px);\n color: #fff;\n border-radius: 12px;\n font-size: 14px;\n line-height: 1.8;\n display: none;\n flex-direction: column;\n overflow: hidden;\n box-shadow: -4px 0 24px rgba(0,0,0,0.5);\n border: 1px solid rgba(254, 235, 234, 0.2);\n transition: none;\n z-index: ${ee.CONTAINER};\n margin-left: 10px;\n }\n\n #subtitle-container.show {\n display: flex;\n }\n \n /* 调整大小的边缘检测区域 */\n #subtitle-container::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n }\n \n /* 鼠标悬停在边缘时的光标样式 */\n #subtitle-container.resize-n { cursor: n-resize; }\n #subtitle-container.resize-s { cursor: s-resize; }\n #subtitle-container.resize-e { cursor: e-resize; }\n #subtitle-container.resize-w { cursor: w-resize; }\n #subtitle-container.resize-ne { cursor: ne-resize; }\n #subtitle-container.resize-nw { cursor: nw-resize; }\n #subtitle-container.resize-se { cursor: se-resize; }\n #subtitle-container.resize-sw { cursor: sw-resize; }\n\n /* ==================== 头部样式 ==================== */\n .subtitle-header {\n font-size: 14px;\n font-weight: 500;\n padding: 16px 20px;\n border-bottom: 1px solid rgba(254, 235, 234, 0.15);\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: move;\n user-select: none;\n flex-shrink: 0;\n background: linear-gradient(135deg, rgba(254, 235, 234, 0.12), rgba(254, 235, 234, 0.06));\n color: #fff;\n border-radius: 12px 12px 0 0;\n user-select: none;\n }\n\n .subtitle-header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .subtitle-header-right {\n display: flex;\n align-items: center;\n gap: 12px;\n position: relative;\n z-index: 10;\n }\n\n .subtitle-status-text {\n font-size: 13px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.9);\n }\n\n .subtitle-search-box {\n position: relative;\n flex: 1;\n max-width: 300px;\n margin: 0 8px; \n color: rgba(255, 255, 255, 0.6);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .subtitle-search-container {\n position: relative;\n display: flex;\n align-items: center;\n background: rgba(0, 0, 0, 0.2);\n border-radius: 20px;\n padding: 5px 12px;\n border: 1px solid rgba(254, 235, 234, 0.15);\n transition: all 0.2s;\n width: 200px;\n }\n\n .subtitle-search-container:focus-within {\n border-color: #feebea;\n background: rgba(0, 0, 0, 0.4);\n box-shadow: 0 0 0 2px rgba(254, 235, 234, 0.1);\n }\n\n .search-input {\n flex: 1;\n background: transparent;\n border: none;\n outline: none;\n color: #fff;\n font-size: 14px;\n padding: 4px;\n padding-right: 70px;\n }\n\n .search-input::placeholder {\n color: rgba(255, 255, 255, 0.5);\n }\n\n .search-controls {\n position: absolute;\n right: 8px;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .search-counter {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.6);\n min-width: 28px;\n text-align: center;\n }\n\n .search-nav-btn {\n background: transparent;\n border: none;\n color: rgba(255, 255, 255, 0.6);\n cursor: pointer;\n padding: 2px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n }\n\n .search-nav-btn:hover {\n color: #fff;\n background: rgba(255, 255, 255, 0.1);\n }\n\n .search-nav-btn:active {\n transform: scale(0.9);\n }\n\n .search-nav-btn:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n \n .search-nav-btn svg {\n display: block;\n }\n\n /* 搜索高亮样式 */\n .search-highlight {\n background-color: rgba(255, 255, 0, 0.4);\n color: #000;\n padding: 2px 0;\n border-radius: 2px;\n }\n\n .search-highlight-current {\n background-color: rgba(255, 165, 0, 0.6);\n color: #000;\n padding: 2px 0;\n border-radius: 2px;\n box-shadow: 0 0 4px rgba(255, 165, 0, 0.8);\n }\n\n .subtitle-header-actions {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n\n .subtitle-close {\n cursor: pointer;\n font-size: 20px;\n line-height: 1;\n color: rgba(255, 255, 255, 0.5);\n transition: all 0.2s;\n padding: 4px;\n border-radius: 4px;\n }\n\n .subtitle-close:hover {\n color: rgba(255, 255, 255, 0.9);\n background: rgba(255, 255, 255, 0.1);\n }\n\n /* ==================== 标签页样式 ==================== */\n .subtitle-tabs {\n display: flex;\n padding: 0 20px;\n gap: 20px;\n border-bottom: 1px solid rgba(254, 235, 234, 0.1);\n background: rgba(0, 0, 0, 0.2);\n }\n\n .subtitle-tab {\n position: relative;\n padding: 12px 4px;\n color: rgba(255, 255, 255, 0.6);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n user-select: none;\n }\n\n .subtitle-tab:hover {\n color: rgba(255, 255, 255, 0.9);\n }\n\n .subtitle-tab.active {\n color: #fff;\n }\n\n .subtitle-tab.active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 2px;\n background: linear-gradient(90deg, #feebea, rgba(254, 235, 234, 0.6));\n border-radius: 2px 2px 0 0;\n }\n\n /* ==================== 内容区域样式 ==================== */\n .subtitle-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n height: calc(100% - 120px);\n }\n\n .subtitle-panel {\n padding: 20px;\n height: 100%;\n overflow-y: visible;\n }\n\n .subtitle-content::-webkit-scrollbar {\n width: 6px;\n }\n\n .subtitle-content::-webkit-scrollbar-thumb {\n background-color: rgba(254, 235, 234, 0.4);\n border-radius: 3px;\n }\n \n .subtitle-content::-webkit-scrollbar-thumb:hover {\n background-color: rgba(254, 235, 234, 0.6);\n }\n \n .subtitle-content::-webkit-scrollbar-track {\n background-color: rgba(255, 255, 255, 0.05);\n }\n\n /* ==================== 字幕列表样式 ==================== */\n .subtitle-toggle-btn {\n padding: 8px 12px;\n margin-bottom: 15px;\n background: rgba(255, 255, 255, 0.1);\n border: 1px solid rgba(254, 235, 234, 0.3);\n border-radius: 8px;\n color: #fff;\n cursor: pointer;\n font-size: 16px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n width: 100%;\n height: auto;\n }\n\n .subtitle-toggle-btn:hover {\n background: rgba(254, 235, 234, 0.2);\n border-color: #feebea;\n transform: scale(1.05);\n }\n\n .subtitle-toggle-icon {\n transition: transform 0.3s ease;\n display: inline-block;\n font-size: 12px;\n }\n\n .subtitle-toggle-btn.expanded .subtitle-toggle-icon {\n transform: rotate(90deg);\n }\n\n .subtitle-list-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n height: auto;\n overflow-y: visible;\n padding: 16px;\n position: relative;\n }\n\n .subtitle-item {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n padding: 6px 10px;\n border-radius: 6px;\n transition: all 0.2s;\n cursor: pointer;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(254, 235, 234, 0.2);\n position: relative;\n }\n\n .subtitle-item:hover {\n background: rgba(254, 235, 234, 0.15);\n border-color: #feebea;\n transform: translateX(4px);\n box-shadow: 0 2px 8px rgba(254, 235, 234, 0.2);\n }\n\n .subtitle-item.current {\n background: rgba(254, 235, 234, 0.2) !important;\n border-left: 3px solid #ff69b4;\n padding-left: 9px;\n box-shadow: 0 2px 8px rgba(255, 105, 180, 0.2);\n animation: subtitleHighlight 1.5s ease infinite;\n }\n \n @keyframes subtitleHighlight {\n 0%, 100% {\n box-shadow: 0 2px 8px rgba(255, 105, 180, 0.2);\n }\n 50% {\n box-shadow: 0 2px 12px rgba(255, 105, 180, 0.4);\n }\n }\n\n .subtitle-time {\n color: rgba(255, 255, 255, 0.6);\n font-size: 11px;\n font-weight: 600;\n flex-shrink: 0;\n min-width: 42px;\n }\n\n .subtitle-text {\n color: #e5e7eb;\n font-size: 14px;\n line-height: 1.5;\n flex: 1;\n }\n\n /* ==================== AI图标样式 ==================== */\n .ai-icon {\n cursor: pointer;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n transition: opacity 0.2s, transform 0.2s;\n }\n\n .ai-icon:hover {\n opacity: 1;\n transform: scale(1.1);\n }\n\n .ai-icon.loading {\n animation: breath-ai 1.2s ease-in-out infinite;\n pointer-events: none;\n }\n\n .ai-icon.disabled {\n opacity: 0.3;\n pointer-events: none;\n cursor: not-allowed;\n }\n\n @keyframes breath-ai {\n 0%, 100% { transform: scale(1.05); opacity: 1; }\n 50% { transform: scale(1.35); opacity: 0.5; }\n }\n\n /* ==================== 下载图标样式 ==================== */\n .download-icon {\n cursor: pointer;\n width: 20px;\n height: 20px;\n opacity: 0.7;\n transition: opacity 0.2s, transform 0.2s;\n }\n\n .download-icon:hover {\n opacity: 1;\n transform: scale(1.1);\n }\n\n /* ==================== Notion图标样式 ==================== */\n .notion-icon {\n cursor: pointer;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n transition: opacity 0.2s, transform 0.2s;\n }\n\n .notion-icon:hover {\n opacity: 1;\n transform: scale(1.1);\n }\n\n .notion-icon.loading {\n animation: breath-notion 1.2s ease-in-out infinite;\n }\n\n @keyframes breath-notion {\n 0%, 100% { transform: scale(1.05); opacity: 1; }\n 50% { transform: scale(1.35); opacity: 0.5; }\n }\n\n /* ==================== Toast提示样式 ==================== */\n .notion-toast {\n position: fixed;\n top: 80px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.85);\n color: white;\n padding: 12px 24px;\n border-radius: 8px;\n font-size: 14px;\n z-index: ${ee.TOAST};\n opacity: 0;\n transition: opacity 0.3s;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n }\n\n .notion-toast.show {\n opacity: 1;\n }\n\n /* ==================== AI总结样式 ==================== */\n .ai-summary-tips {\n padding: 10px 16px;\n background: rgba(254, 235, 234, 0.08);\n border-radius: 8px;\n color: rgba(255, 255, 255, 0.5);\n font-size: 12px;\n margin-bottom: 16px;\n }\n\n .ai-summary-main {\n padding: 16px;\n background: rgba(0, 0, 0, 0.2);\n border-radius: 12px;\n margin-bottom: 20px;\n border: 1px solid rgba(255, 255, 255, 0.08);\n }\n \n .summary-title {\n font-size: 14px;\n font-weight: bold;\n color: rgba(255, 255, 255, 0.9);\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n }\n \n .summary-content {\n font-size: 14px;\n line-height: 1.8;\n color: rgba(255, 255, 255, 0.85);\n overflow-y: visible;\n overflow-x: hidden;\n word-wrap: break-word;\n overflow-wrap: break-word;\n word-break: break-word;\n }\n \n /* 滚动条样式已统一由 .subtitle-content 管理 */\n \n /* Markdown样式 - 总结区域 */\n .summary-content h1,\n .summary-content h2,\n .summary-content h3,\n .summary-content h4,\n .summary-content h5,\n .summary-content h6 {\n color: rgba(255, 255, 255, 0.9) !important;\n margin-top: 12px;\n margin-bottom: 8px;\n font-weight: 600;\n }\n \n .summary-content h1 { font-size: 18px; }\n .summary-content h2 { font-size: 16px; }\n .summary-content h3 { font-size: 15px; }\n .summary-content h4 { font-size: 14px; }\n \n .summary-content p {\n margin: 8px 0;\n color: rgba(255, 255, 255, 0.85);\n }\n \n .summary-content ul,\n .summary-content ol {\n margin: 8px 0;\n padding-left: 20px;\n color: rgba(255, 255, 255, 0.85);\n }\n \n .summary-content li {\n margin: 4px 0;\n }\n \n .summary-content strong {\n color: rgba(255, 255, 255, 0.95);\n font-weight: 600;\n }\n \n .summary-content code {\n background: rgba(255, 255, 255, 0.1);\n color: #feebea;\n padding: 2px 4px;\n border-radius: 3px;\n font-size: 13px;\n }\n \n .summary-content blockquote {\n border-left: 3px solid #feebea;\n background: rgba(254, 235, 234, 0.05);\n padding: 8px 12px;\n margin: 8px 0;\n color: rgba(255, 255, 255, 0.8);\n }\n\n .ai-summary-outline {\n margin-bottom: 20px;\n }\n\n .progress-switch {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: rgba(0, 0, 0, 0.15);\n border-radius: 8px;\n margin-bottom: 16px;\n border: 1px solid rgba(254, 235, 234, 0.1);\n }\n \n .progress-switch span {\n font-size: 14px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.8);\n }\n\n .switch-btn {\n width: 40px;\n height: 22px;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 11px;\n position: relative;\n cursor: pointer;\n transition: all 0.3s;\n border: 1px solid rgba(254, 235, 234, 0.2);\n }\n\n .switch-btn.on {\n background: rgba(254, 235, 234, 0.3);\n border-color: #feebea;\n }\n\n .switch-block {\n width: 16px;\n height: 16px;\n background: #fff;\n border-radius: 50%;\n position: absolute;\n top: 2px;\n left: 2px;\n transition: all 0.3s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n }\n\n .switch-btn.on .switch-block {\n transform: translateX(18px);\n }\n\n .ai-summary-sections {\n padding: 0;\n }\n\n .summary-section {\n margin-bottom: 20px;\n }\n\n .section-title {\n font-size: 14px;\n font-weight: 600;\n color: #fff;\n margin-bottom: 12px;\n padding: 8px 12px;\n background: rgba(254, 235, 234, 0.08);\n border-radius: 8px;\n border-left: 3px solid #feebea;\n }\n\n .section-items {\n padding: 0;\n }\n\n .section-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px;\n background: rgba(255, 255, 255, 0.03);\n border-radius: 6px;\n border: 1px solid rgba(254, 235, 234, 0.1);\n margin-bottom: 8px;\n transition: all 0.2s ease;\n position: relative;\n cursor: pointer; /* 添加鼠标指针样式,表示可点击 */\n user-select: none; /* 禁止文字选择,防止与笔记功能冲突 */\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n }\n \n .section-item:hover {\n background: rgba(254, 235, 234, 0.15);\n border-color: #feebea;\n transform: translateX(4px);\n box-shadow: 0 2px 8px rgba(254, 235, 234, 0.2); /* 添加阴影效果 */\n }\n \n .section-item:active {\n transform: translateX(2px) scale(0.98); /* 点击时的反馈 */\n }\n \n .section-item.clicked {\n animation: segmentClick 0.3s ease;\n }\n \n @keyframes segmentClick {\n 0% {\n transform: scale(1);\n background: rgba(254, 235, 234, 0.05);\n }\n 50% {\n transform: scale(0.98);\n background: rgba(254, 235, 234, 0.3);\n box-shadow: 0 0 10px rgba(254, 235, 234, 0.5);\n }\n 100% {\n transform: scale(1);\n background: rgba(254, 235, 234, 0.05);\n }\n }\n \n .ai-segments-section .section-item {\n cursor: pointer;\n }\n \n .ai-segments-section .section-item:hover {\n background: rgba(254, 235, 234, 0.2);\n }\n \n .segment-item {\n cursor: pointer;\n transition: all 0.2s ease;\n }\n \n .segment-item:hover {\n background: rgba(254, 235, 234, 0.1);\n transform: translateX(2px);\n }\n\n .time-btn {\n padding: 2px 6px;\n background: transparent;\n border: none;\n color: rgba(255, 255, 255, 0.6);\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s;\n flex-shrink: 0;\n min-width: 42px;\n text-align: left;\n }\n\n .time-btn:hover {\n color: #feebea;\n }\n\n .item-content {\n flex: 1;\n color: #e5e7eb;\n font-size: 14px;\n line-height: 1.5;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .item-title {\n font-size: 14px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.9);\n }\n\n .item-desc {\n font-size: 12px;\n line-height: 1.5;\n color: rgba(255, 255, 255, 0.65);\n }\n \n .item-single {\n font-size: 14px;\n color: #e5e7eb;\n }\n\n .ai-segments-section,\n .original-subtitles-section,\n .ai-segments-in-summary {\n margin-bottom: 12px;\n }\n \n .summary-panel-container {\n height: auto;\n overflow-y: visible;\n overflow-x: hidden;\n padding: 12px;\n }\n \n /* 滚动条样式已移到 .subtitle-content */\n \n .ai-segments-in-summary {\n background: #2a2a2a;\n border-radius: 8px;\n padding: 8px;\n }\n\n .segments-header {\n font-size: 13px;\n font-weight: 600;\n color: rgba(255, 255, 255, 0.7);\n padding: 8px 12px;\n margin-bottom: 8px;\n background: rgba(0, 0, 0, 0.2);\n border-radius: 8px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .segments-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.1);\n margin: 16px 0;\n }\n\n .ai-summary-main {\n padding-top: 8px;\n }\n\n .ai-summary-empty {\n padding: 60px 20px;\n text-align: center;\n color: rgba(255, 255, 255, 0.4);\n font-size: 14px;\n }\n\n .ai-summary-content {\n color: #e5e7eb;\n font-size: 14px;\n line-height: 1.7;\n word-wrap: break-word;\n overflow-wrap: break-word;\n word-break: break-word;\n white-space: normal;\n max-width: 100%;\n }\n\n .ai-summary-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: rgba(255, 255, 255, 0.6);\n }\n\n .loading-spinner {\n width: 40px;\n height: 40px;\n border: 3px solid rgba(254, 235, 234, 0.1);\n border-top-color: #feebea;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n margin-bottom: 16px;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* ==================== Markdown样式 ==================== */\n .ai-summary-content h1,\n .ai-summary-content h2,\n .ai-summary-content h3 {\n color: #fff;\n margin-top: 12px;\n margin-bottom: 8px;\n font-weight: 700;\n word-wrap: break-word;\n overflow-wrap: break-word;\n }\n\n .ai-summary-content h1 { font-size: 17px; }\n .ai-summary-content h2 { font-size: 16px; }\n .ai-summary-content h3 { font-size: 15px; }\n\n .ai-summary-content ul,\n .ai-summary-content ol {\n margin: 8px 0;\n padding-left: 20px;\n max-width: 100%;\n }\n\n .ai-summary-content li {\n margin: 4px 0;\n word-wrap: break-word;\n overflow-wrap: break-word;\n word-break: break-word;\n }\n\n .ai-summary-content p {\n margin: 8px 0;\n word-wrap: break-word;\n overflow-wrap: break-word;\n word-break: break-word;\n white-space: normal;\n }\n\n .ai-summary-content code {\n background: rgba(255, 255, 255, 0.1);\n color: #feebea;\n padding: 3px 6px;\n border-radius: 4px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n border: 1px solid rgba(254, 235, 234, 0.2);\n }\n\n .ai-summary-content pre {\n background: rgba(0, 0, 0, 0.5);\n padding: 12px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 10px 0;\n border: 1px solid rgba(254, 235, 234, 0.2);\n white-space: pre-wrap;\n word-wrap: break-word;\n max-width: 100%;\n }\n\n .ai-summary-content pre code {\n background-color: transparent;\n padding: 0;\n border: none;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n\n .ai-summary-content blockquote {\n border-left: 4px solid #feebea;\n background: rgba(254, 235, 234, 0.1);\n padding: 12px;\n padding-left: 16px;\n margin: 10px 0;\n border-radius: 4px;\n word-wrap: break-word;\n overflow-wrap: break-word;\n }\n\n .ai-summary-content strong {\n color: #fff;\n font-weight: 700;\n }\n\n .ai-summary-content a {\n color: #feebea;\n text-decoration: underline;\n font-weight: 600;\n }\n \n .ai-summary-content a:hover {\n color: #fff;\n }\n\n /* ==================== 配置模态框样式 ==================== */\n .config-modal {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.7);\n z-index: ${ee.AI_MODAL};\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n .config-modal.show {\n display: flex;\n }\n \n /* 配置模态框overlay样式(用于快捷键配置等) */\n .config-modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.7);\n z-index: ${ee.AI_MODAL};\n display: none;\n align-items: center;\n justify-content: center;\n }\n \n .config-modal-overlay.show {\n display: flex;\n }\n \n /* 快捷键配置模态框 */\n #shortcut-config-modal {\n background: rgba(0, 0, 0, 0.85);\n backdrop-filter: blur(12px);\n border-radius: 16px;\n padding: 0;\n width: 600px;\n max-width: 90%;\n max-height: 85vh;\n overflow: hidden;\n box-shadow: 0 20px 60px rgba(0,0,0,0.5);\n color: #fff;\n display: flex;\n flex-direction: column;\n border: 1px solid rgba(254, 235, 234, 0.2);\n }\n\n .config-modal-content {\n background: rgba(0, 0, 0, 0.85);\n backdrop-filter: blur(12px);\n border-radius: 16px;\n padding: 0;\n width: 700px;\n max-width: 90%;\n max-height: 85vh;\n overflow: hidden;\n box-shadow: 0 20px 60px rgba(0,0,0,0.5);\n color: #fff;\n display: flex;\n flex-direction: column;\n border: 1px solid rgba(254, 235, 234, 0.2);\n }\n\n .config-modal-header {\n padding: 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: rgba(254, 235, 234, 0.15);\n border-bottom: 1px solid rgba(254, 235, 234, 0.2);\n border-radius: 16px 16px 0 0;\n }\n \n .config-modal-title {\n font-size: 20px;\n font-weight: 700;\n color: white;\n }\n \n .config-modal-close {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: transparent;\n border: none;\n color: rgba(255, 255, 255, 0.7);\n font-size: 24px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n \n .config-modal-close:hover {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.9);\n }\n \n .config-modal-body {\n flex: 1;\n overflow-y: auto;\n padding: 30px;\n background-color: transparent;\n }\n\n .config-field {\n margin-bottom: 20px;\n }\n\n .config-field label {\n display: block;\n margin-bottom: 10px;\n font-weight: 600;\n color: #e5e7eb;\n font-size: 14px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n \n .config-field label::before {\n content: '•';\n color: #feebea;\n font-size: 18px;\n font-weight: bold;\n }\n\n .config-field input,\n .config-field textarea {\n width: 100%;\n padding: 12px 14px;\n border: 1px solid rgba(254, 235, 234, 0.3);\n border-radius: 10px;\n font-size: 14px;\n box-sizing: border-box;\n transition: all 0.2s;\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n }\n\n .config-field input:hover,\n .config-field textarea:hover {\n background: rgba(255, 255, 255, 0.12);\n border-color: rgba(254, 235, 234, 0.5);\n }\n\n .config-field input:focus,\n .config-field textarea:focus {\n outline: none;\n border-color: #feebea;\n box-shadow: 0 0 0 3px rgba(254, 235, 234, 0.15);\n background: rgba(255, 255, 255, 0.15);\n }\n\n .config-field input::placeholder,\n .config-field textarea::placeholder {\n color: rgba(255, 255, 255, 0.5);\n }\n\n .config-field textarea {\n font-family: inherit;\n resize: vertical;\n min-height: 120px;\n line-height: 1.6;\n }\n \n .config-field input[type="checkbox"] {\n width: auto;\n margin-right: 8px;\n cursor: pointer;\n }\n\n .config-help {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.6);\n margin-top: 5px;\n }\n\n .config-help a {\n color: #feebea;\n text-decoration: underline;\n }\n\n .config-help code {\n background-color: rgba(255, 255, 255, 0.1);\n padding: 2px 6px;\n border-radius: 3px;\n font-family: 'Courier New', monospace;\n font-size: 11px;\n color: #fff;\n }\n\n .config-help strong {\n color: #feebea;\n }\n\n .config-footer {\n display: flex;\n gap: 12px;\n justify-content: flex-end;\n padding: 20px 30px;\n background-color: rgba(0, 0, 0, 0.3);\n border-top: 1px solid rgba(254, 235, 234, 0.2);\n border-radius: 0 0 16px 16px;\n }\n\n .config-btn {\n padding: 12px 24px;\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s;\n position: relative;\n overflow: hidden;\n }\n\n .config-btn::before {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n width: 0;\n height: 0;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.3);\n transform: translate(-50%, -50%);\n transition: width 0.6s, height 0.6s;\n }\n\n .config-btn:hover::before {\n width: 300px;\n height: 300px;\n }\n\n .config-btn-primary {\n background: linear-gradient(135deg, #feebea 0%, #2d2d2d 100%);\n color: #fff;\n box-shadow: 0 4px 12px rgba(254, 235, 234, 0.3);\n }\n\n .config-btn-primary:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 20px rgba(254, 235, 234, 0.4);\n }\n\n .config-btn-primary:active {\n transform: translateY(0);\n }\n\n .config-btn-secondary {\n background-color: #f3f4f6;\n color: #6b7280;\n border: 2px solid #e5e7eb;\n }\n\n .config-btn-secondary:hover {\n background-color: #e5e7eb;\n color: #374151;\n border-color: #d1d5db;\n }\n\n .config-btn-danger {\n background-color: #fee2e2;\n color: #dc2626;\n border: 2px solid #fecaca;\n }\n\n .config-btn-danger:hover {\n background-color: #dc2626;\n color: white;\n border-color: #dc2626;\n }\n\n .config-status {\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 12px;\n margin-top: 10px;\n }\n\n .config-status.success {\n background-color: #d4edda;\n color: #155724;\n }\n\n .config-status.error {\n background-color: #f8d7da;\n color: #721c24;\n }\n\n /* ==================== AI配置列表样式 ==================== */\n .ai-config-list {\n margin-bottom: 25px;\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 10px;\n }\n\n .ai-config-item {\n padding: 10px 14px;\n border: 1px solid rgba(254, 235, 234, 0.3);\n border-radius: 10px;\n margin-bottom: 0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n background: rgba(255, 255, 255, 0.05);\n position: relative;\n overflow: hidden;\n }\n\n .ai-config-item::before {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n width: 4px;\n background: linear-gradient(135deg, #feebea 0%, #ffdbdb 100%);\n transform: scaleY(0);\n transition: transform 0.3s ease;\n }\n\n .ai-config-item:hover {\n background: rgba(254, 235, 234, 0.15);\n border-color: #feebea;\n transform: translateX(4px);\n box-shadow: 0 4px 12px rgba(254, 235, 234, 0.2);\n }\n\n .ai-config-item:hover::before {\n transform: scaleY(1);\n }\n\n .ai-config-item.selected {\n border-color: #feebea;\n background: rgba(254, 235, 234, 0.2);\n box-shadow: 0 4px 16px rgba(254, 235, 234, 0.3);\n }\n\n .ai-config-item.selected::before {\n transform: scaleY(1);\n width: 4px;\n }\n\n .ai-config-item-name {\n font-weight: 600;\n font-size: 14px;\n color: #e5e7eb;\n }\n\n .ai-config-item.selected .ai-config-item-name {\n color: #fff;\n font-weight: 700;\n }\n\n .ai-config-item-actions {\n display: flex;\n gap: 8px;\n z-index: 1;\n }\n\n .ai-config-btn-small {\n padding: 4px 12px;\n font-size: 12px;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n font-weight: 500;\n }\n\n .ai-config-btn-small:hover {\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n }\n\n .ai-config-btn-small.config-btn-primary {\n background: linear-gradient(135deg, #feebea 0%, #2d2d2d 100%);\n color: white;\n }\n\n .ai-config-btn-small.config-btn-secondary {\n background-color: #f3f4f6;\n color: #6b7280;\n }\n\n .ai-config-btn-small.config-btn-secondary:hover {\n background-color: #fee2e2;\n color: #dc2626;\n }\n\n .ai-config-form {\n border-top: 1px solid rgba(254, 235, 234, 0.2);\n padding-top: 25px;\n margin-top: 10px;\n background: rgba(0, 0, 0, 0.3);\n padding: 25px;\n border-radius: 12px;\n border: 1px solid rgba(254, 235, 234, 0.2);\n }\n\n .ai-config-form.hidden {\n display: none;\n }\n\n .ai-config-form .config-field {\n margin-bottom: 20px;\n }\n\n /* ==================== 模型选择器样式 ==================== */\n .model-select-wrapper {\n margin-top: 8px;\n position: relative;\n }\n\n .model-search-input {\n width: 100%;\n padding: 10px;\n border: 1px solid rgba(254, 235, 234, 0.3);\n border-radius: 6px;\n font-size: 14px;\n box-sizing: border-box;\n margin-bottom: 8px;\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n }\n\n .model-search-input:focus {\n outline: none;\n border-color: #feebea;\n box-shadow: 0 0 0 3px rgba(254, 235, 234, 0.15);\n background: rgba(255, 255, 255, 0.15);\n }\n\n .model-search-input::placeholder {\n color: rgba(255, 255, 255, 0.5);\n }\n\n .model-select-wrapper select {\n width: 100%;\n padding: 10px;\n border: 1px solid rgba(254, 235, 234, 0.3);\n border-radius: 6px;\n font-size: 14px;\n box-sizing: border-box;\n max-height: 200px;\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n }\n\n .model-select-wrapper select option {\n padding: 8px;\n background: rgba(0, 0, 0, 0.9);\n color: #fff;\n }\n\n .model-count-badge {\n display: inline-block;\n background: #feebea;\n color: #1a1a1a;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n margin-left: 8px;\n font-weight: 600;\n }\n\n .model-field-with-button {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .model-field-with-button input {\n flex: 1;\n }\n\n .fetch-models-btn {\n padding: 12px 20px;\n font-size: 14px;\n font-weight: 600;\n border: none;\n border-radius: 10px;\n background: linear-gradient(135deg, #feebea 0%, #2d2d2d 100%);\n color: white;\n cursor: pointer;\n white-space: nowrap;\n transition: all 0.2s;\n box-shadow: 0 2px 8px rgba(254, 235, 234, 0.3);\n }\n\n .fetch-models-btn:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(254, 235, 234, 0.4);\n }\n\n .fetch-models-btn:active {\n transform: translateY(0);\n }\n\n .fetch-models-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n transform: none !important;\n box-shadow: none;\n }\n\n /* ==================== 速度控制样式 ==================== */\n .speed-control-section {\n padding: 12px;\n margin-bottom: 15px;\n background: linear-gradient(135deg, #fff5f5 0%, #ffe5e5 100%);\n border-radius: 12px;\n border: 2px solid rgba(254, 235, 234, 0.5);\n }\n\n .speed-control-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 10px;\n padding-bottom: 8px;\n border-bottom: 2px solid rgba(254, 235, 234, 0.5);\n }\n\n .speed-control-title {\n font-size: 14px;\n font-weight: 700;\n color: #2d2d2d;\n }\n\n .speed-control-display {\n font-size: 16px;\n font-weight: 700;\n color: #1a1a1a;\n font-family: monospace;\n }\n\n .speed-control-buttons {\n display: flex;\n gap: 8px;\n margin-bottom: 10px;\n }\n\n .speed-btn {\n flex: 1;\n padding: 8px;\n border: 2px solid #e5e7eb;\n border-radius: 8px;\n background: white;\n color: #1a1a1a;\n cursor: pointer;\n font-size: 14px;\n font-weight: 600;\n transition: all 0.2s;\n }\n\n .speed-btn:hover {\n background: #feebea;\n border-color: #feebea;\n transform: translateY(-1px);\n }\n\n .speed-btn-small {\n flex: 0 0 40px;\n font-size: 18px;\n }\n\n .speed-control-advanced {\n margin-top: 8px;\n }\n\n .speed-toggle-volume-btn {\n width: 100%;\n padding: 8px;\n border: 2px solid #e5e7eb;\n border-radius: 8px;\n background: white;\n color: #6b7280;\n cursor: pointer;\n font-size: 12px;\n transition: all 0.2s;\n }\n\n .speed-toggle-volume-btn:hover {\n background: #fff5f5;\n border-color: #ffe5e5;\n }\n\n /* ==================== 快捷键配置面板样式 ==================== */\n\n .shortcut-item {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: rgba(255, 255, 255, 0.05);\n border-radius: 8px;\n transition: all 0.2s;\n }\n\n .shortcut-item:hover {\n background: rgba(255, 255, 255, 0.08);\n }\n\n .shortcut-description {\n flex: 1;\n font-size: 14px;\n color: rgba(255, 255, 255, 0.9);\n }\n\n .shortcut-controls {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .shortcut-input {\n padding: 6px 12px;\n border: 1px solid rgba(254, 235, 234, 0.3);\n border-radius: 6px;\n font-size: 13px;\n min-width: 180px;\n text-align: center;\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .shortcut-input:hover {\n background: rgba(255, 255, 255, 0.15);\n border-color: rgba(254, 235, 234, 0.5);\n }\n\n .shortcut-input.recording,\n .shortcut-input.capturing {\n background: rgba(254, 235, 234, 0.2);\n border-color: #feebea;\n animation: pulse 1.5s infinite;\n }\n\n @keyframes pulse {\n 0% { box-shadow: 0 0 0 0 rgba(254, 235, 234, 0.4); }\n 50% { box-shadow: 0 0 0 8px rgba(254, 235, 234, 0); }\n 100% { box-shadow: 0 0 0 0 rgba(254, 235, 234, 0); }\n }\n\n .shortcut-reset-btn {\n padding: 6px 12px;\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.7);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 6px;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .shortcut-reset-btn:hover {\n background: rgba(255, 255, 255, 0.15);\n color: rgba(255, 255, 255, 0.9);\n }\n\n /* 长按和双击模式按钮 */\n .shortcut-mode-btn {\n padding: 4px 8px;\n background: rgba(255, 255, 255, 0.08);\n color: rgba(255, 255, 255, 0.6);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 4px;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n }\n\n .shortcut-mode-btn:hover {\n background: rgba(255, 255, 255, 0.12);\n color: rgba(255, 255, 255, 0.8);\n }\n\n .shortcut-mode-btn.active {\n background: rgba(254, 235, 234, 0.3);\n color: #feebea;\n border-color: #feebea;\n box-shadow: 0 0 8px rgba(254, 235, 234, 0.3);\n }\n\n .shortcut-config-footer {\n margin-top: 16px;\n padding-top: 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n \n .shortcut-tips {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.6);\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .shortcuts-icon {\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 4px;\n transition: all 0.2s;\n }\n\n .shortcuts-icon:hover {\n transform: rotate(45deg);\n filter: drop-shadow(0 0 8px rgba(254, 235, 234, 0.5));\n }\n\n /* ==================== 笔记面板样式 ==================== */\n .notes-panel {\n position: fixed;\n right: 20px;\n top: 50%;\n transform: translateY(-50%);\n width: 400px;\n min-width: 350px;\n max-width: 600px;\n height: 600px;\n min-height: 400px;\n max-height: 80vh;\n background: rgba(32, 32, 38, 0.95);\n backdrop-filter: blur(20px) saturate(200%);\n border-radius: 16px;\n box-shadow: \n 0 20px 60px -8px rgba(255, 105, 180, 0.2),\n 0 8px 24px -4px rgba(0, 0, 0, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.08),\n inset 0 -1px 0 rgba(0, 0, 0, 0.2);\n resize: both;\n overflow: hidden; /* 改为 hidden,只允许内部 body 滚动 */\n z-index: ${ee.MODAL};\n display: none;\n flex-direction: column;\n }\n\n .notes-panel.show {\n display: flex;\n }\n\n .notes-panel-content {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .notes-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px;\n border-bottom: 1px solid rgba(254, 235, 234, 0.2);\n background: rgba(254, 235, 234, 0.15);\n }\n\n .notes-panel-header h2 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #fff;\n }\n\n .notes-panel-close {\n background: none;\n border: none;\n font-size: 24px;\n color: rgba(255, 255, 255, 0.6);\n cursor: pointer;\n padding: 0;\n width: 30px;\n height: 30px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n transition: all 0.2s;\n }\n\n .notes-panel-close:hover {\n background: rgba(255,255,255,0.1);\n color: #fff;\n }\n\n /* 笔记筛选器样式 */\n .notes-filters {\n display: flex;\n gap: 20px;\n padding: 12px 20px;\n background: rgba(0, 0, 0, 0.2);\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n }\n\n .filter-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n user-select: none;\n }\n\n .filter-checkbox input[type="checkbox"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: #feebea;\n }\n\n .filter-checkbox span {\n color: rgba(255, 255, 255, 0.8);\n font-size: 14px;\n }\n\n .filter-checkbox:hover span {\n color: rgba(255, 255, 255, 0.95);\n }\n\n .notes-panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n }\n\n .notes-panel-body::-webkit-scrollbar {\n width: 6px;\n }\n\n .notes-panel-body::-webkit-scrollbar-thumb {\n background-color: rgba(254, 235, 234, 0.4);\n border-radius: 3px;\n }\n \n .notes-panel-body::-webkit-scrollbar-thumb:hover {\n background-color: rgba(254, 235, 234, 0.6);\n }\n \n .notes-panel-body::-webkit-scrollbar-track {\n background-color: rgba(255, 255, 255, 0.05);\n }\n\n .notes-empty-state {\n text-align: center;\n padding: 60px 20px;\n color: rgba(255, 255, 255, 0.6);\n }\n\n .notes-empty-icon {\n font-size: 48px;\n margin-bottom: 16px;\n }\n\n .notes-empty-hint {\n font-size: 14px;\n margin-top: 8px;\n }\n\n .note-group {\n margin-bottom: 24px;\n }\n\n .note-group-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 1px solid rgba(254, 235, 234, 0.2);\n }\n\n .note-group-title {\n font-size: 14px;\n font-weight: 600;\n color: #e5e7eb;\n }\n\n .note-group-actions {\n display: flex;\n gap: 8px;\n }\n\n .note-group-copy-btn,\n .note-group-delete-btn {\n padding: 4px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 12px;\n transition: all 0.2s;\n border: 1px solid;\n }\n\n .note-group-copy-btn {\n background: none;\n border-color: #4A90E2;\n color: #4A90E2;\n }\n\n .note-group-copy-btn:hover {\n background: #4A90E2;\n color: white;\n }\n\n .note-group-delete-btn {\n background: none;\n border-color: #e74c3c;\n color: #e74c3c;\n }\n\n .note-group-delete-btn:hover {\n background: #e74c3c;\n color: white;\n }\n\n .note-item {\n background: rgba(255, 255, 255, 0.05);\n padding: 12px;\n border-radius: 8px;\n margin-bottom: 8px;\n transition: background-color 0.2s;\n border: 1px solid rgba(254, 235, 234, 0.1);\n }\n\n .note-item:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(254, 235, 234, 0.3);\n }\n\n .note-content {\n color: #e5e7eb;\n font-size: 14px;\n line-height: 1.6;\n margin-bottom: 8px;\n word-break: break-word;\n white-space: pre-wrap;\n }\n\n .note-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .note-time {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.5);\n }\n\n .note-actions {\n display: flex;\n gap: 8px;\n }\n\n .note-copy-btn,\n .note-delete-btn {\n background: none;\n border: none;\n cursor: pointer;\n font-size: 12px;\n padding: 4px 8px;\n transition: color 0.2s;\n }\n\n .note-copy-btn {\n color: #4A90E2;\n }\n\n .note-copy-btn:hover {\n color: #357ABD;\n }\n\n .note-delete-btn {\n color: #e74c3c;\n }\n\n .note-delete-btn:hover {\n color: #c0392b;\n }\n\n /* ==================== AI 总结笔记样式 ==================== */\n .note-item-ai-summary {\n background: rgba(254, 235, 234, 0.08);\n border: 1px solid rgba(254, 235, 234, 0.2);\n padding: 16px;\n }\n\n .note-item-ai-summary:hover {\n background: rgba(254, 235, 234, 0.12);\n border-color: rgba(254, 235, 234, 0.4);\n }\n\n .ai-summary-content-wrapper {\n display: flex;\n flex-direction: column;\n gap: 16px;\n margin-bottom: 12px;\n }\n\n .ai-summary-section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .ai-summary-title {\n font-size: 13px;\n font-weight: 600;\n color: #feebea;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .ai-summary-content {\n font-size: 13px;\n color: rgba(255, 255, 255, 0.8);\n line-height: 1.6;\n padding: 8px 12px;\n background: rgba(255, 255, 255, 0.05);\n border-radius: 4px;\n border-left: 3px solid rgba(254, 235, 234, 0.3);\n }\n\n .ai-summary-segments {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .segment-item {\n padding: 12px;\n background: rgba(255, 255, 255, 0.03);\n border-radius: 4px;\n border: 1px solid rgba(254, 235, 234, 0.1);\n transition: all 0.2s;\n }\n\n .segment-item:hover {\n background: rgba(255, 255, 255, 0.06);\n border-color: rgba(254, 235, 234, 0.2);\n }\n\n .segment-header {\n display: flex;\n gap: 8px;\n margin-bottom: 8px;\n align-items: center;\n }\n\n .segment-time {\n font-size: 12px;\n font-weight: 600;\n color: #feebea;\n flex-shrink: 0;\n }\n\n .segment-title {\n font-size: 13px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.9);\n flex: 1;\n }\n\n .segment-summary {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.7);\n line-height: 1.5;\n margin-bottom: 8px;\n }\n\n .segment-screenshot {\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid rgba(254, 235, 234, 0.1);\n }\n\n .segment-screenshot img {\n max-width: 100%;\n border-radius: 4px;\n display: block;\n }\n\n .screenshot-time {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.5);\n margin-top: 4px;\n }\n\n /* ==================== 笔记选择保存点样式 ==================== */\n #note-saver-blue-dot {\n position: absolute;\n cursor: pointer;\n z-index: 2147483647; /* Maximum z-index */\n display: none;\n transition: transform 0.2s, filter 0.2s;\n pointer-events: auto !important;\n width: 24px;\n height: 24px;\n }\n\n #note-saver-blue-dot:hover {\n transform: scale(1.15);\n filter: drop-shadow(0 2px 4px rgba(254, 235, 234, 0.5));\n }\n\n /* ==================== 字幕项保存按钮样式 ==================== */\n .save-subtitle-note-btn {\n background: linear-gradient(135deg, #feebea 0%, #2d2d2d 100%);\n color: white;\n border: none;\n padding: 2px 8px;\n border-radius: 4px;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s;\n opacity: 0;\n flex-shrink: 0;\n margin-left: auto;\n }\n\n .subtitle-item:hover .save-subtitle-note-btn {\n opacity: 1;\n }\n\n .save-subtitle-note-btn:hover {\n transform: scale(1.05);\n }\n \n .subtitle-follow-btn {\n position: absolute;\n bottom: 10px;\n left: 50%;\n transform: translateX(-50%);\n padding: 6px 12px;\n background: rgba(255, 105, 180, 0.8);\n color: white;\n border: none;\n border-radius: 16px;\n font-size: 12px;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transition: all 0.3s;\n z-index: 10;\n }\n\n .subtitle-follow-btn:hover {\n background: rgba(255, 105, 180, 1);\n transform: translateX(-50%) translateY(-2px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);\n }\n\n /* ==================== 快捷键配置样式 ==================== */\n .shortcut-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .shortcut-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px;\n background: rgba(255, 255, 255, 0.05);\n border-radius: 8px;\n border: 1px solid rgba(254, 235, 234, 0.2);\n }\n\n .shortcut-label {\n font-size: 14px;\n color: #e5e7eb;\n font-weight: 500;\n }\n\n .shortcut-input-wrapper {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .shortcut-input {\n padding: 6px 12px;\n border: 1px solid rgba(254, 235, 234, 0.3);\n border-radius: 6px;\n font-size: 13px;\n min-width: 180px;\n text-align: center;\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .shortcut-input:focus {\n outline: none;\n border-color: #feebea;\n box-shadow: 0 0 0 3px rgba(254, 235, 234, 0.15);\n background: rgba(255, 255, 255, 0.15);\n }\n\n .shortcut-input.capturing {\n border-color: #feebea;\n background: rgba(254, 235, 234, 0.2);\n animation: pulse-border 1s infinite;\n }\n\n @keyframes pulse-border {\n 0%, 100% {\n border-color: #feebea;\n box-shadow: 0 0 0 3px rgba(254, 235, 234, 0.15);\n }\n 50% {\n border-color: #ffc9c9;\n box-shadow: 0 0 0 3px rgba(254, 235, 234, 0.3);\n }\n }\n\n .shortcut-clear-btn {\n background: none;\n border: none;\n color: #999;\n font-size: 18px;\n cursor: pointer;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n transition: all 0.2s;\n }\n\n .shortcut-clear-btn:hover {\n background: #fee2e2;\n color: #dc2626;\n }\n\n /* ==================== 调整大小手柄样式 ==================== */\n .subtitle-resize-handle {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 20px;\n height: 20px;\n cursor: nwse-resize;\n z-index: 10;\n }\n\n .subtitle-resize-handle::after {\n content: '';\n position: absolute;\n bottom: 4px;\n right: 4px;\n width: 12px;\n height: 12px;\n border-right: 3px solid rgba(254, 235, 234, 0.6);\n border-bottom: 3px solid rgba(254, 235, 234, 0.6);\n border-radius: 0 0 4px 0;\n }\n\n .subtitle-resize-handle:hover::after {\n border-color: #feebea;\n }\n\n .sponsor-switch {\n position: relative;\n width: 48px;\n height: 24px;\n }\n\n .sponsor-switch input {\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .sponsor-switch-slider {\n position: absolute;\n cursor: pointer;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: #cbd5e1;\n transition: 0.3s;\n border-radius: 24px;\n }\n\n .sponsor-switch-slider:before {\n position: absolute;\n content: "";\n height: 18px;\n width: 18px;\n left: 3px;\n bottom: 3px;\n background-color: white;\n transition: 0.3s;\n border-radius: 50%;\n }\n\n .sponsor-switch input:checked + .sponsor-switch-slider {\n background-color: #feebea;\n }\n\n .sponsor-switch input:checked + .sponsor-switch-slider:before {\n transform: translateX(24px);\n }\n\n /* ==================== SponsorBlock 标签样式 ==================== */\n .bili-quality-tag, .bili-ad-tag {\n display: inline-flex !important;\n align-items: center;\n color: white !important;\n padding: 3px 10px !important;\n border-radius: 15px !important;\n margin-right: 6px !important;\n font-size: 12px !important;\n animation: badgeSlideIn 0.3s ease-out !important;\n position: relative;\n z-index: 2;\n font-weight: 500;\n box-shadow: 0 2px 4px rgba(0,0,0,0.2);\n white-space: nowrap;\n flex-shrink: 0;\n }\n \n /* 只显示emoji的标签样式 */\n .bili-quality-tag.emoji-only,\n .bili-ad-tag.emoji-only {\n padding: 3px 8px !important;\n min-width: auto;\n }\n\n /* 视频卡片标签位置 */\n .video-page-card-small .bili-quality-tag,\n .video-page-card-small .bili-ad-tag,\n .bili-video-card__wrap .bili-quality-tag,\n .bili-video-card__wrap .bili-ad-tag {\n position: absolute;\n left: 8px;\n top: 8px;\n transform: scale(0.9);\n }\n\n /* UP主主页视频卡片 */\n .up-main-video-card .bili-quality-tag,\n .up-main-video-card .bili-ad-tag,\n .small-item .bili-quality-tag,\n .small-item .bili-ad-tag {\n position: absolute !important;\n left: 8px !important;\n top: 8px !important;\n z-index: 10 !important;\n transform: scale(0.9);\n }\n\n .up-main-video-card .cover-container,\n .up-main-video-card .cover,\n .small-item .cover {\n position: relative !important;\n }\n\n /* 多标签容器 */\n .bili-tags-container {\n display: flex;\n flex-wrap: nowrap;\n gap: 4px;\n overflow: visible;\n align-items: center;\n }\n\n @keyframes badgeSlideIn {\n 0% { opacity: 0; transform: translateX(-15px) scale(0.9); }\n 100% { opacity: 1; transform: translateX(0) scale(0.9); }\n }\n\n /* 跳过提示Toast - 视频右下角,绿色 */\n .skip-toast {\n position: absolute;\n bottom: 60px;\n right: 20px;\n background: rgba(0, 212, 0, 0.15);\n color: #00d400;\n padding: 8px 16px;\n border-radius: 4px;\n font-size: 14px;\n z-index: 10000;\n animation: fadeIn 0.3s ease-out;\n font-weight: 500;\n backdrop-filter: blur(4px);\n pointer-events: auto !important;\n user-select: none;\n }\n\n .skip-toast.hiding {\n animation: fadeOut 0.3s ease-out forwards;\n }\n\n /* 手动跳过提示 - 视频右下角 */\n .skip-prompt {\n position: absolute;\n bottom: 80px;\n right: 20px;\n background: rgba(0, 0, 0, 0.9);\n color: white;\n border-radius: 8px;\n padding: 12px 16px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.4);\n z-index: 10000;\n min-width: 280px;\n animation: fadeIn 0.3s ease-out;\n pointer-events: auto !important;\n user-select: none;\n }\n\n .skip-prompt-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 10px;\n font-size: 14px;\n font-weight: 500;\n }\n\n .skip-prompt-icon {\n width: 20px;\n height: 20px;\n flex-shrink: 0;\n }\n\n .skip-prompt-icon svg {\n width: 100%;\n height: 100%;\n }\n\n .skip-prompt-message {\n flex: 1;\n }\n\n .skip-prompt-buttons {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n }\n\n .skip-prompt-btn {\n padding: 6px 14px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n transition: all 0.2s;\n }\n\n .skip-prompt-btn-primary {\n background: #00a1d6;\n color: white;\n }\n\n .skip-prompt-btn-primary:hover {\n background: #0087b3;\n }\n\n .skip-prompt-btn-secondary {\n background: rgba(255, 255, 255, 0.1);\n color: white;\n }\n\n .skip-prompt-btn-secondary:hover {\n background: rgba(255, 255, 255, 0.2);\n }\n\n .skip-prompt-close {\n background: none;\n border: none;\n color: #999;\n cursor: pointer;\n font-size: 18px;\n padding: 0;\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-left: 8px;\n }\n\n .skip-prompt-close:hover {\n color: white;\n }\n\n .skip-prompt.hiding {\n animation: fadeOut 0.3s ease-out forwards;\n }\n\n /* 进度条片段标记 */\n #sponsorblock-preview-bar {\n overflow: hidden;\n padding: 0;\n margin: 0;\n position: absolute;\n width: 100%;\n height: 100%;\n z-index: 1;\n pointer-events: none;\n }\n\n .sponsorblock-segment {\n display: inline-block;\n height: 100%;\n position: absolute;\n min-width: 1px;\n opacity: 0.7;\n transition: all 0.2s ease;\n pointer-events: auto;\n cursor: pointer;\n }\n\n .sponsorblock-segment:hover {\n opacity: 0.95;\n transform: scaleY(1.5);\n z-index: 100;\n }\n\n /* 片段详情弹窗 */\n .segment-details-popup {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: rgba(0, 0, 0, 0.95);\n color: white;\n border-radius: 12px;\n padding: 24px;\n min-width: 350px;\n max-width: 500px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.5);\n z-index: 10002;\n animation: popupFadeIn 0.2s ease-out;\n }\n\n @keyframes popupFadeIn {\n from {\n opacity: 0;\n transform: translate(-50%, -45%);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%);\n }\n }\n\n .segment-details-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n padding-bottom: 12px;\n border-bottom: 1px solid rgba(255,255,255,0.2);\n }\n\n .segment-details-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 18px;\n font-weight: 500;\n }\n\n .segment-details-close {\n background: none;\n border: none;\n color: #999;\n font-size: 24px;\n cursor: pointer;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: all 0.2s;\n }\n\n .segment-details-close:hover {\n background: rgba(255,255,255,0.1);\n color: white;\n }\n\n .segment-details-content {\n margin-bottom: 16px;\n }\n\n .segment-details-row {\n display: flex;\n justify-content: space-between;\n padding: 8px 0;\n font-size: 14px;\n }\n\n .segment-details-label {\n color: #999;\n }\n\n .segment-details-value {\n color: white;\n font-weight: 500;\n }\n\n .segment-details-actions {\n display: flex;\n gap: 12px;\n justify-content: flex-end;\n }\n\n .segment-details-btn {\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s;\n }\n\n .segment-details-btn-primary {\n background: #00a1d6;\n color: white;\n }\n\n .segment-details-btn-primary:hover {\n background: #0087b3;\n }\n\n .segment-details-btn-secondary {\n background: rgba(255,255,255,0.1);\n color: white;\n }\n\n .segment-details-btn-secondary:hover {\n background: rgba(255,255,255,0.2);\n }\n\n .segment-details-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0,0,0,0.3);\n z-index: 10001;\n }\n\n /* SponsorBlock 设置面板样式 */\n .sponsor-settings-section {\n margin-bottom: 24px;\n }\n\n .sponsor-settings-section h3 {\n font-size: 16px;\n color: #e5e7eb;\n margin: 0 0 12px 0;\n }\n\n .sponsor-checkbox-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .sponsor-checkbox-item {\n display: flex;\n align-items: center;\n padding: 8px;\n border-radius: 6px;\n transition: background 0.2s;\n }\n\n .sponsor-checkbox-item:hover {\n background: rgba(255, 255, 255, 0.05);\n }\n\n .sponsor-checkbox-item input[type="checkbox"] {\n margin-right: 10px;\n cursor: pointer;\n width: 18px;\n height: 18px;\n }\n\n .sponsor-checkbox-item label {\n cursor: pointer;\n flex: 1;\n display: flex;\n align-items: center;\n gap: 8px;\n color: #e5e7eb;\n }\n\n .category-color-dot {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n display: inline-block;\n }\n\n .sponsor-switch-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px;\n border-radius: 6px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(254, 235, 234, 0.2);\n margin-bottom: 8px;\n color: #e5e7eb;\n }\n`;const he='',ge='',me='';function be(e){if(!e||"string"!=typeof e)return {valid:false,error:"URL不能为空"};if(!e.startsWith("http://")&&!e.startsWith("https://"))return {valid:false,error:"URL必须以 http:// 或 https:// 开头"};try{return new URL(e),{valid:!0,error:null}}catch(t){return {valid:false,error:"URL格式无效"}}}function fe(e){return e&&"string"==typeof e?0===e.trim().length?{valid:false,error:"API Key不能为空"}:e.length<10?{valid:false,error:"API Key长度过短,请检查是否完整"}:{valid:true,error:null}:{valid:false,error:"API Key不能为空"}}function ye(e){return e?e.bvid&&e.bvid.match(/^BV[1-9A-Za-z]{10}$/)?e.cid?void 0!==e.p&&null!==e.p&&(!Number.isInteger(e.p)||e.p<1)?{valid:false,error:"分P参数错误,必须是大于等于1的整数"}:{valid:true,error:null}:{valid:false,error:"CID为空"}:{valid:false,error:"BV号格式错误"}:{valid:false,error:"视频信息为空"}}function ve(e){if(!ye(e).valid)return null;const t=e.p||1;return `${e.bvid}-${e.cid}-p${t}`}const xe=new class{constructor(){this.events=new Map,this.modules=new Map,this.subscriptionId=0;}on(e,t,n=null){return this.events.has(e)||this.events.set(e,[]),this.events.get(e).push(t),n&&(this.modules.has(n)||this.modules.set(n,new Set),this.modules.get(n).add({event:e,handler:t})),()=>this.off(e,t)}once(e,t){const n=(...o)=>{t(...o),this.off(e,n);};this.on(e,n);}off(e,t){if(!this.events.has(e))return;const n=this.events.get(e),o=n.indexOf(t);o>-1&&n.splice(o,1),0===n.length&&this.events.delete(e);}emit(e,...t){if(!this.events.has(e))return;const n=[...this.events.get(e)],o=n.length;o>10&&console.warn(`[EventBus] ⚠️ 事件 "${e}" 有 ${o} 个监听器,可能存在内存泄漏`);for(const s of n)try{s(...t);}catch(i){console.error(`[EventBus] 事件 "${e}" 处理出错:`,i);}}clear(){this.events.clear(),this.modules.clear();}clearModule(e){const t=this.modules.get(e);t&&(t.forEach(({event:e,handler:t})=>{this.off(e,t);}),this.modules.delete(e));}listenerCount(e){return this.events.has(e)?this.events.get(e).length:0}getModuleStats(){const e={};return this.modules.forEach((t,n)=>{e[n]=t.size;}),e}};const we=new class{constructor(){this.debugMode=GM_getValue("debug_mode",false),this.prefix="[BilibiliTools]",this.LOG_LEVELS={TRACE:0,DEBUG:1,INFO:2,SUCCESS:3,WARN:4,ERROR:5},this.currentLevel=this.debugMode?this.LOG_LEVELS.TRACE:this.LOG_LEVELS.WARN;}toggleDebugMode(){return this.debugMode=!this.debugMode,GM_setValue("debug_mode",this.debugMode),this.currentLevel=this.debugMode?this.LOG_LEVELS.TRACE:this.LOG_LEVELS.WARN,console.log(`${this.prefix} 调试模式: ${this.debugMode?"开启":"关闭"}`),this.debugMode}isDebugMode(){return this.debugMode}trace(e,...t){this.currentLevel<=this.LOG_LEVELS.TRACE&&console.log(`🔍 [${e}]`,...t);}debug(e,...t){this.currentLevel<=this.LOG_LEVELS.DEBUG&&console.log(`🐛 [${e}]`,...t);}info(e,...t){this.currentLevel<=this.LOG_LEVELS.INFO&&console.info(`ℹ️ [${e}]`,...t);}success(e,...t){this.currentLevel<=this.LOG_LEVELS.SUCCESS&&console.log(`✅ [${e}]`,...t);}warn(e,...t){this.currentLevel<=this.LOG_LEVELS.WARN&&console.warn(`⚠️ [${e}]`,...t);}error(e,...t){this.currentLevel<=this.LOG_LEVELS.ERROR&&console.error(`❌ [${e}]`,...t);}group(e,t){this.debugMode&&console.group(`[${e}] ${t}`);}groupEnd(){this.debugMode&&console.groupEnd();}table(e,t){this.debugMode&&(console.log(`[${e}] 数据表格:`),console.table(t));}time(e){this.debugMode&&console.time(e);}timeEnd(e){this.debugMode&&console.timeEnd(e);}};const Se=new class{constructor(){this.activeTasks=new Map,this.processedVideos=this._loadProcessedVideos(),this.taskQueue=[],window.addEventListener("beforeunload",()=>{this._saveProcessedVideos();});}_loadProcessedVideos(){try{const e=localStorage.getItem(Z);if(e){const t=JSON.parse(e),n=Date.now()-2592e6,o=Object.entries(t).filter(([,e])=>e>n).map(([e])=>e);return new Set(o)}}catch(e){we.error("TaskManager","加载已处理视频记录失败:",e);}return new Set}_saveProcessedVideos(){try{const e={};this.processedVideos.forEach(t=>{e[t]=Date.now();}),localStorage.setItem(Z,JSON.stringify(e));}catch(e){we.error("TaskManager","保存已处理视频记录失败:",e);}}isVideoProcessed(e){const t="string"==typeof e?e:ve(e);return !!t&&this.processedVideos.has(t)}markVideoProcessed(e){const t="string"==typeof e?e:ve(e);t&&(this.processedVideos.add(t),this._saveProcessedVideos());}clearVideoProcessed(e){const t="string"==typeof e?e:ve(e);t&&(this.processedVideos.delete(t),this._saveProcessedVideos());}createTask(e,t,n,o=false){const i=ve(t);if(!i)return we.error("TaskManager","无效的视频信息,无法创建任务"),null;for(const[a,l]of this.activeTasks){if(ve(l.videoInfo)===i&&l.type===e&&("pending"===l.status||"running"===l.status))return we.info("TaskManager",`视频 ${t.bvid} 已有 ${e} 任务在运行中,跳过创建`),null}const s=`${e}_${i}_${Date.now()}`;if(!o&&this.isVideoProcessed(t)){const e=t.p||1;return we.debug("TaskManager",`视频 ${t.bvid} P${e} 已自动处理过,跳过自动任务`),null}const r={id:s,type:e,videoInfo:{...t},status:"pending",createdAt:Date.now(),isManual:o,abortController:new AbortController,result:null,error:null};return this.activeTasks.set(s,r),this._executeTask(r,n),s}async _executeTask(e,t){try{e.status="running",we.info("TaskManager",`开始执行任务 ${e.id},视频: ${e.videoInfo.bvid}`);const n=await t({videoInfo:e.videoInfo,signal:e.abortController.signal,taskId:e.id});e.result=n,e.status="completed",e.isManual||"ai_summary"!==e.type||this.markVideoProcessed(e.videoInfo),we.success("TaskManager",`任务 ${e.id} 完成`),setTimeout(()=>{this.activeTasks.delete(e.id);},6e4);}catch(n){e.error=n,e.status="failed","AbortError"===n.name?we.info("TaskManager",`任务 ${e.id} 被取消`):we.error("TaskManager",`任务 ${e.id} 失败:`,n),setTimeout(()=>{this.activeTasks.delete(e.id);},6e4);}}cancelVideoTasks(e){const t="string"==typeof e?e:ve(e);if(!t)return 0;let n=0;return this.activeTasks.forEach((e,o)=>{ve(e.videoInfo)===t&&"running"===e.status&&(e.abortController.abort(),e.status="canceled",n++,we.info("TaskManager",`取消任务 ${o}`));}),n>0&&we.info("TaskManager",`已取消视频 ${t} 的 ${n} 个任务`),n}cancelTypeTasks(e){let t=0;return this.activeTasks.forEach((n,o)=>{n.type===e&&"running"===n.status&&(n.abortController.abort(),n.status="canceled",t++);}),t}getVideoTasks(e){const t="string"==typeof e?e:ve(e);if(!t)return [];const n=[];return this.activeTasks.forEach(e=>{ve(e.videoInfo)===t&&n.push(e);}),n}hasRunningTask(e,t=null){let n=null;null!==t&&(n="string"==typeof t?t:ve(t));for(const o of this.activeTasks.values())if(o.type===e&&"running"===o.status){if(null===n)return true;if(ve(o.videoInfo)===n)return true}return false}cleanup(){const e=[];this.activeTasks.forEach((t,n)=>{"completed"!==t.status&&"failed"!==t.status&&"canceled"!==t.status||e.push(n);}),e.forEach(e=>{this.activeTasks.delete(e);}),we.debug("TaskManager",`清理了 ${e.length} 个已完成任务`);}reset(){this.activeTasks.forEach(e=>{"running"===e.status&&e.abortController.abort();}),this.activeTasks.clear(),this.taskQueue=[],we.info("TaskManager","任务管理器已重置");}getStats(){const e={total:this.activeTasks.size,running:0,completed:0,failed:0,canceled:0,processedVideos:this.processedVideos.size};return this.activeTasks.forEach(t=>{"running"===t.status?e.running++:"completed"===t.status?e.completed++:"failed"===t.status?e.failed++:"canceled"===t.status&&e.canceled++;}),e}};class ke{constructor(e=10,t="LRUCache"){this.maxSize=e,this.cacheName=t,this.cache=new Map,we.debug("LRUCache",`初始化 ${t},最大容量: ${e}`);}get(e){if(!this.cache.has(e))return;const t=this.cache.get(e);return this.cache.delete(e),this.cache.set(e,t),we.debug("LRUCache",`${this.cacheName} 缓存命中: ${e}`),t}set(e,t){if(this.cache.has(e)&&this.cache.delete(e),this.cache.size>=this.maxSize){const e=this.cache.keys().next().value;this.cache.delete(e),we.debug("LRUCache",`${this.cacheName} LRU淘汰: ${e}`);}this.cache.set(e,t),we.debug("LRUCache",`${this.cacheName} 缓存保存: ${e},当前数量: ${this.cache.size}/${this.maxSize}`);}has(e){return this.cache.has(e)}delete(e){const t=this.cache.delete(e);return t&&we.debug("LRUCache",`${this.cacheName} 缓存删除: ${e}`),t}clear(){const e=this.cache.size;this.cache.clear(),we.info("LRUCache",`${this.cacheName} 缓存已清空,删除了 ${e} 个项`);}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}getStats(){return {name:this.cacheName,size:this.cache.size,maxSize:this.maxSize,usage:`${this.cache.size}/${this.maxSize}`,keys:this.keys()}}}const Ie=new ke(10,"字幕缓存"),Te=new ke(10,"AI-Markdown缓存"),Ce=new ke(10,"AI-段落缓存"),Ee=new ke(10,"Notion页面缓存");const Ae=new class{constructor(){this.reset();}reset(){this.subtitle={data:null,capturedUrl:null},this.request={isRequesting:false,currentRequestKey:null,requestPromise:null,abortController:null},this.ai={isSummarizing:false,currentSummary:null,summaryPromise:null,abortController:null},this.notion={isSending:false,sendPromise:null,pageIds:{}},this.ui={ballStatus:f,panelVisible:false,isDragging:false,dragStart:{x:0,y:0},panelStart:{x:0,y:0}},this.video={bvid:null,cid:null,aid:null,p:null};}setVideoInfo(e){if(!ye(e).valid)return false;const t=this.video.bvid,n=this.video.p||1,o=e.bvid,i=e.p||1;if(t&&(t!==o||n!==i)){we.info("StateManager",`检测到视频切换: ${t}-P${n} -> ${o}-P${i}`);const s=ve({bvid:t,cid:this.video.cid,p:n});Se.cancelVideoTasks(s),xe.emit(B,{oldBvid:t,newBvid:o,oldP:n,newP:i,oldVideoInfo:{...this.video},newVideoInfo:e});}return this.video.bvid=e.bvid,this.video.cid=e.cid,this.video.aid=e.aid,this.video.p=e.p||1,true}getVideoInfo(){return {...this.video}}getVideoKey(){return ve(this.video)}setSubtitleData(e){this.subtitle.data=e;}getSubtitleData(e=null){return e&&e!==this.getVideoKey()?Ie.get(e):this.subtitle.data}startRequest(){const e=this.getVideoKey();return e?this.request.isRequesting&&this.request.currentRequestKey===e?{success:false,reason:"已有相同视频的请求在进行中"}:Ie.has(e)?{success:false,reason:"已有缓存"}:(this.request.isRequesting&&this.cancelRequest(),this.request.isRequesting=true,this.request.currentRequestKey=e,{success:true,reason:null}):{success:false,reason:"视频信息无效"}}finishRequest(){this.request.isRequesting=false,this.request.currentRequestKey=null,this.request.requestPromise=null,this.request.abortController=null;}cancelRequest(){this.request.abortController&&this.request.abortController.abort(),this.finishRequest();}startAISummary(){return !this.ai.isSummarizing&&(this.ai.isSummarizing=true,this.ai.abortController=new AbortController,true)}finishAISummary(e){this.ai.isSummarizing=false,this.ai.currentSummary=e,this.ai.summaryPromise=null,this.ai.abortController=null;const t=this.getVideoKey();xe.emit(E,e,t);}cancelAISummary(){this.ai.abortController&&this.ai.abortController.abort(),this.ai.isSummarizing=false,this.ai.summaryPromise=null,this.ai.abortController=null;}getAISummary(e=null){const t=e||this.getVideoKey();if(!t)return this.ai.currentSummary;const n=Te.get(t),o=Ce.get(t);return n&&o?{markdown:n,segments:o.segments||[],ads:o.ads||[]}:null}setBallStatus(e){this.ui.ballStatus!==e&&(this.ui.ballStatus=e,xe.emit(L,e));}getBallStatus(){return this.ui.ballStatus}togglePanel(){this.ui.panelVisible=!this.ui.panelVisible,xe.emit(M,this.ui.panelVisible);}setNotionPageId(e,t){this.notion.pageIds[e]=t,t?(Ee.set(e,t),sessionStorage.setItem(`notion-page-${e}`,t)):(Ee.delete(e),sessionStorage.removeItem(`notion-page-${e}`));}getNotionPageId(e){const t=Ee.get(e);return t||(this.notion.pageIds[e]||null)}setPanelVisible(e){this.ui.panelVisible!==e&&(this.ui.panelVisible=e,xe.emit(M,e));}};const $e=new class{getAIConfigs(){const e=GM_getValue(O,[]);if(0===e.length)return [...R];const t=e.map(e=>!e.prompt||e.prompt1&&e.prompt2?e:{...e,prompt1:e.prompt,prompt2:this._getDefaultPrompt2(),prompt:void 0});return t.some(t=>void 0===t.prompt&&e.some(e=>e.prompt))&&this.saveAIConfigs(t),t}saveAIConfigs(e){GM_setValue(O,e);}getSelectedAIConfigId(){return GM_getValue(V,"openrouter")}setSelectedAIConfigId(e){GM_setValue(V,e);}getSelectedAIConfig(){const e=this.getAIConfigs(),t=this.getSelectedAIConfigId();return e.find(e=>e.id===t)||e[0]||null}addAIConfig(e){if(!(e.name&&e.url&&e.apiKey&&e.model))return {success:false,error:"所有字段都是必填的"};const t=be(e.url);if(!t.valid)return {success:false,error:t.error};const n=fe(e.apiKey);if(!n.valid)return {success:false,error:n.error};const o=this.getAIConfigs(),i={id:Date.now().toString(),name:e.name.trim(),url:e.url.trim(),apiKey:e.apiKey.trim(),model:e.model.trim(),prompt1:e.prompt1||"",prompt2:e.prompt2||"",isOpenRouter:e.isOpenRouter||false};return o.push(i),this.saveAIConfigs(o),this.setSelectedAIConfigId(i.id),{success:true,error:null,config:i}}updateAIConfig(e,t){const n=this.getAIConfigs(),o=n.findIndex(t=>t.id===e);if(-1===o)return {success:false,error:"配置不存在"};if(void 0!==t.apiKey){const e=fe(t.apiKey,n[o].isOpenRouter);if(!e.valid)return {success:false,error:e.error}}if(void 0!==t.url){const e=be(t.url);if(!e.valid)return {success:false,error:e.error}}return !t.prompt||t.prompt1&&t.prompt2||(t.prompt1=t.prompt,t.prompt2=this._getDefaultPrompt2(),delete t.prompt),n[o]={...n[o],...t},this.saveAIConfigs(n),{success:true,error:null}}deleteAIConfig(e){if("openrouter"===e||"openai"===e)return {success:false,error:"预设配置不能删除"};let t=this.getAIConfigs();return t=t.filter(t=>t.id!==e),this.saveAIConfigs(t),this.getSelectedAIConfigId()===e&&this.setSelectedAIConfigId("openrouter"),{success:true,error:null}}getAIAutoSummaryEnabled(){return GM_getValue(j,true)}setAIAutoSummaryEnabled(e){GM_setValue(j,e);}getNotionConfig(){return {apiKey:GM_getValue(U,""),parentPageId:GM_getValue(F,""),databaseId:GM_getValue(K,"")}}isNotionConfigured(){const e=this.getNotionConfig();return !(!e.apiKey||!e.parentPageId)}saveNotionConfig(e){if(e.apiKey){const t=fe(e.apiKey);if(!t.valid)return {success:false,error:t.error};GM_setValue(U,e.apiKey.trim());}if(e.parentPageId){const t=function(e){if(!e||"string"!=typeof e)return {valid:false,cleaned:null,error:"Page ID不能为空"};let t=e.split("?")[0].split("#")[0];const n=t.match(se);return n?(t=n[1].replace(/-/g,""),t.length!==u?{valid:false,cleaned:null,error:`Page ID长度错误,需要${u}位字符`}:{valid:true,cleaned:t,error:null}):{valid:false,cleaned:null,error:"Page ID格式错误,应为32位十六进制字符"}}(e.parentPageId);if(!t.valid)return {success:false,error:t.error};GM_setValue(F,t.cleaned);}return void 0!==e.databaseId&&GM_setValue(K,e.databaseId),{success:true,error:null}}getNotionAutoSendEnabled(){return GM_getValue(H,false)}setNotionAutoSendEnabled(e){GM_setValue(H,e);}getNotionContentOptions(){return {videoInfo:GM_getValue(Y,true),summary:GM_getValue(G,true),segments:GM_getValue(J,true),subtitles:GM_getValue(W,true)}}saveNotionContentOptions(e){ void 0!==e.videoInfo&&GM_setValue(Y,e.videoInfo),void 0!==e.summary&&GM_setValue(G,e.summary),void 0!==e.segments&&GM_setValue(J,e.segments),void 0!==e.subtitles&&GM_setValue(W,e.subtitles);}getNotionNotesAutoSync(){return GM_getValue(X,false)}setNotionNotesAutoSync(e){GM_setValue(X,e);}getNotionNotesDatabaseId(){return GM_getValue(Q,"")}setNotionNotesDatabaseId(e){GM_setValue(Q,e);}fixExistingConfigPrompts(){const e=this.getAIConfigs();let t=false;const n=e.map(e=>e.prompt1&&e.prompt2&&(e.prompt1===e.prompt2||e.prompt2.includes("TL;DR"))?(t=true,{...e,prompt2:this._getDefaultPrompt2()}):e);return t&&(this.saveAIConfigs(n),we.debug("ConfigManager","已修复配置中的prompt2为JSON格式")),t}_getDefaultPrompt2(){return '分析以下带时间戳的字幕,提取5-8个关键段落。\n\n重要:\n1. 你的回复必须是一个完整且有效的JSON\n2. 不要有任何其他文字、解释或markdown标记\n3. 直接以{开始,以}结束\n4. 数组元素之间必须用逗号分隔\n\nJSON格式要求(注意逗号):\n{\n "segments": [\n {"timestamp":"分钟:秒","title":"标题(10字内)","summary":"内容总结(30-50字)"},\n {"timestamp":"分钟:秒","title":"标题(10字内)","summary":"内容总结(30-50字)"}\n ]\n}\n\n正确示例(特别注意元素之间的逗号):\n{"segments":[{"timestamp":"00:15","title":"开场介绍","summary":"主持人介绍今天的主题和嘉宾背景"},{"timestamp":"02:30","title":"核心观点","summary":"讨论技术发展趋势和未来展望"}]}\n\n字幕内容:\n'}},_e="bilibili_shortcuts_config",Pe=/Mac|iPhone|iPad|iPod/.test(navigator.platform),Ne={toggleSubtitlePanel:{key:"KeyB",meta:true,ctrl:true,alt:false,shift:false,description:"切换字幕面板"},toggleNotesPanel:{key:"Slash",meta:false,ctrl:false,alt:false,shift:true,description:"切换笔记面板"},takeScreenshot:{key:"Slash",meta:true,ctrl:true,alt:false,shift:false,description:"截图并保存到笔记"},speedIncrease:{key:"Period",meta:false,ctrl:false,alt:false,shift:false,description:"增加播放速度"},speedDecrease:{key:"Comma",meta:false,ctrl:false,alt:false,shift:false,description:"减少播放速度"},speedReset:{key:"Comma",meta:false,ctrl:false,alt:false,shift:false,doubleClick:true,description:"重置播放速度(双击)"},speedDouble:{key:"Period",meta:false,ctrl:false,alt:false,shift:false,doubleClick:true,description:"2倍速(双击)"}};const Me=new class{constructor(){this.shortcuts=this.loadShortcuts(),this.handlers=new Map,this.isListening=false,this.pressedKeys=new Set,this.setupKeyTracking();}static get DEFAULT_SHORTCUTS(){return Ne}loadShortcuts(){try{const e=GM_getValue(_e,null);if(!e)return {...Ne};const t=JSON.parse(e),n={...Ne};for(const[o,i]of Object.entries(t))i.key&&"(双击)"!==i.key&&""!==i.key?n[o]=i:(we.warn("ShortcutManager",`修复损坏的快捷键配置: ${o}`),Ne[o]&&(n[o]={...Ne[o]}));return n}catch(e){return console.error("加载快捷键配置失败:",e),{...Ne}}}saveShortcuts(e){try{return this.shortcuts=e,GM_setValue(_e,JSON.stringify(e)),{success:!0,error:null}}catch(t){return console.error("保存快捷键配置失败:",t),{success:false,error:t.message}}}resetToDefaults(){return this.shortcuts={...Ne},this.saveShortcuts(this.shortcuts)}getAllShortcuts(){return {...this.shortcuts}}updateShortcut(e,t){if(!this.shortcuts[e])return {success:false,error:"快捷键不存在"};const n=this.checkConflict(e,t);return n?{success:false,error:`与"${n}"冲突`}:(this.shortcuts[e]={...this.shortcuts[e],...t},this.saveShortcuts(this.shortcuts))}checkConflict(e,t){for(const[n,o]of Object.entries(this.shortcuts)){if(n===e)continue;const i=o.key===t.key,s=o.alt===t.alt,r=o.shift===t.shift,a=o.doubleClick===t.doubleClick,l=(o.meta||false)===(t.meta||false),c=(o.ctrl||false)===(t.ctrl||false);if(i&&l&&c&&s&&r&&a)return o.description}return null}register(e,t){this.handlers.set(e,t);}setupKeyTracking(){document.addEventListener("keydown",e=>{this.pressedKeys.add(e.code);},true),document.addEventListener("keyup",e=>{this.pressedKeys.delete(e.code);},true),window.addEventListener("blur",()=>{this.pressedKeys.clear();});}matches(e,t){if(t.keys&&Array.isArray(t.keys)){const n=t.keys.every(e=>this.pressedKeys.has(e)),o=!(e.ctrlKey||e.metaKey||e.altKey||e.shiftKey);return n&&o}const n=Pe?e.metaKey:e.ctrlKey,o=Pe?t.meta||false:t.ctrl||false;return e.code===t.key&&n===o&&e.altKey===(t.alt||false)&&e.shiftKey===(t.shift||false)}startListening(){this.isListening||(document.addEventListener("keydown",e=>this.handleKeyDown(e),true),document.addEventListener("keyup",e=>this.handleKeyUp(e),true),this.isListening=true);}handleKeyDown(e){const t="INPUT"===e.target.tagName||"TEXTAREA"===e.target.tagName||e.target.isContentEditable;for(const[n,o]of Object.entries(this.shortcuts)){if(o.holdMode){if(e.code===o.key){const t=this.handlers.get(n);t&&(e.preventDefault(),t(e));}continue}if(o.doubleClickMode){e.code===o.key&&this.handleDoubleClick(e,n,o);continue}if(o.doubleClick){"takeScreenshot"===n&&this.handleDoubleClick(e,n,o);continue}const i=o.ctrl||o.alt||o.meta;if(this.matches(e,o)){if(t&&!i)continue;const o=this.handlers.get(n);o&&(e.preventDefault(),o(e));}}}handleKeyUp(e){for(const[t,n]of Object.entries(this.shortcuts))if(n.holdMode&&e.code===n.key){const n=this.handlers.get(t);n&&n.release&&(e.preventDefault(),n.release(e));}}handleDoubleClick(e,t,n){if(e.code!==n.key)return;const o=Date.now();this.lastKeyPressTime||(this.lastKeyPressTime={});if(o-(this.lastKeyPressTime[n.key]||0)<300){const o=this.handlers.get(t);o&&(e.preventDefault(),o(e),this.lastKeyPressTime[n.key]=0);}else this.lastKeyPressTime[n.key]=o;}formatShortcut(e){if(e.keys&&Array.isArray(e.keys)){return e.keys.map(e=>"Period"===e?".":"Comma"===e?",":1===e.length?e.toUpperCase():e).join(" + ")}if(e.holdMode){let t=e.key;return "Period"===t&&(t="."),"Comma"===t&&(t=","),"Slash"===t&&(t="/"),t.startsWith("Key")&&(t=t.substring(3)),1===t.length&&(t=t.toUpperCase()),`${t} (长按)`}if(e.doubleClickMode){let t=e.key;return "Period"===t&&(t="."),"Comma"===t&&(t=","),"Slash"===t&&(t="/"),t.startsWith("Key")&&(t=t.substring(3)),1===t.length&&(t=t.toUpperCase()),`${t} (双击)`}const t=[];Pe&&e.meta?t.push("Cmd"):!Pe&&e.ctrl&&t.push("Ctrl"),e.alt&&t.push(Pe?"Option":"Alt"),e.shift&&t.push("Shift");let n=e.key;return "Period"===n&&(n="."),"Comma"===n&&(n=","),"Slash"===n&&(n="/"),n.startsWith("Key")&&(n=n.substring(3)),1===n.length&&(n=n.toUpperCase()),t.push(n),e.doubleClick&&t.push("(双击)"),t.join(" + ")}validateConfig(e){return e.key&&"string"==typeof e.key?"boolean"!=typeof e.ctrl||"boolean"!=typeof e.alt||"boolean"!=typeof e.shift?{valid:false,error:"修饰键配置错误"}:{valid:true,error:null}:{valid:false,error:"按键不能为空"}}};class Le{constructor(){this.platform="unknown",this.video=null,this.progressBar=null;}isVideoPage(){throw new Error("子类必须实现isVideoPage方法")}getVideoId(){throw new Error("子类必须实现getVideoId方法")}getVideoElement(){throw new Error("子类必须实现getVideoElement方法")}getProgressBar(){throw new Error("子类必须实现getProgressBar方法")}getAdProgressBar(){throw new Error("子类必须实现getAdProgressBar方法")}getPlayerContainer(){throw new Error("子类必须实现getPlayerContainer方法")}async waitForVideo(){return new Promise(e=>{const t=()=>{const n=this.getVideoElement();n?(this.video=n,e(n)):setTimeout(t,500);};t();})}async waitForProgressBar(){return new Promise(e=>{const t=()=>{const n=this.getProgressBar();n?(this.progressBar=n,e(n)):setTimeout(t,500);};t();})}seekTo(e){this.video&&(this.video.currentTime=e);}getCurrentTime(){return this.video?this.video.currentTime:0}getDuration(){return this.video?this.video.duration:0}isPlaying(){return this.video&&!this.video.paused}showNotification(e,t={}){throw new Error("子类必须实现showNotification方法")}addProgressMarkers(e){throw new Error("子类必须实现addProgressMarkers方法")}destroy(){this.video=null,this.progressBar=null;}}class Be extends Le{constructor(){super(),this.platform="bilibili";}isVideoPage(){return location.hostname.includes("bilibili.com")&&location.pathname.includes("/video/")}getVideoId(){const e=location.pathname.match(/video\/(BV\w+)/)?.[1];if(!e)return null;return `${e}_p${new URLSearchParams(window.location.search).get("p")||"1"}`}getVideoElement(){return document.querySelector("video")||document.querySelector(".bpx-player-video-wrap video")}getProgressBar(){return document.querySelector(".bpx-player-progress-schedule")}getAdProgressBar(){return null}getPlayerContainer(){return document.querySelector(".bpx-player-video-wrap")||document.querySelector(".bpx-player-container")}showNotification(e,t={}){const{duration:n=3e3,type:o="info",position:i="top-right"}=t,s=document.createElement("div");s.className="bilibili-skip-notification",s.textContent=e;const r="warning"===o?"#ff9800":"success"===o?"#4caf50":"error"===o?"#f44336":"#2196f3";s.style.cssText=`\n position: absolute;\n ${i.includes("top")?"top: 70px":"bottom: 70px"};\n ${i.includes("right")?"right: 12px":"left: 12px"};\n background: ${r};\n color: white;\n padding: 12px 20px;\n border-radius: 4px;\n font-size: 14px;\n font-weight: 500;\n box-shadow: 0 2px 5px rgba(0,0,0,0.3);\n z-index: 1000;\n animation: fadeIn 0.3s ease;\n pointer-events: none;\n `;const a=this.getPlayerContainer();if(a){if(a.appendChild(s),!document.querySelector("#bilibili-notification-styles")){const e=document.createElement("style");e.id="bilibili-notification-styles",e.textContent="\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @keyframes fadeOut {\n from { opacity: 1; transform: translateY(0); }\n to { opacity: 0; transform: translateY(-10px); }\n }\n ",document.head.appendChild(e);}setTimeout(()=>{s.style.animation="fadeOut 0.3s ease",setTimeout(()=>s.remove(),300);},n);}}addProgressMarkers(e,t={}){const{containerId:n="sponsorblock-preview-bar",className:o="sponsorblock-segment",defaultColor:i="#ff0000",opacity:s=.7}=t,r=this.getProgressBar();if(!r||!this.video)return;document.querySelectorAll(`#${n}`).forEach(e=>e.remove());const a=document.createElement("ul");a.id=n,a.style.cssText="\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 10;\n ";const l=this.video.duration;[...e].sort((e,t)=>{const n=(e.end||e.segment?.[1]||0)-(e.start||e.segment?.[0]||0);return (t.end||t.segment?.[1]||0)-(t.start||t.segment?.[0]||0)-n}).forEach((e,t)=>{const n=e.start||e.segment?.[0]||0,r=e.end||e.segment?.[1]||0,c=n/l*100,d=100*(1-r/l),u=document.createElement("li");u.className=o,u.dataset.segmentIndex=t.toString();const p=e.color||this.getCategoryColor(e.category)||i;u.style.cssText=`\n position: absolute;\n left: ${c}%;\n right: ${d}%;\n height: 100%;\n background: ${p};\n opacity: ${s};\n pointer-events: auto;\n cursor: pointer;\n transition: opacity 0.2s ease;\n `,u.addEventListener("mouseenter",()=>{u.style.opacity="1";}),u.addEventListener("mouseleave",()=>{u.style.opacity=s.toString();});const h=r-n,g=this.getCategoryName(e.category);u.title=`${g}\n${this.formatTime(n)} - ${this.formatTime(r)} (${h.toFixed(1)}秒)`,u.addEventListener("click",t=>{t.stopPropagation(),"mute"!==e.actionType&&(this.seekTo(r),this.showNotification(`已跳过 ${g}`,{type:"success"}));}),a.appendChild(u);}),r.prepend(a);}getCategoryColor(e){return {sponsor:"#00d400",selfpromo:"#ffff00",interaction:"#cc00ff",intro:"#00ffff",outro:"#0202ed",preview:"#008fd6",filler:"#7300ff",music_offtopic:"#ff9900"}[e]||"#ff0000"}getCategoryName(e){return {sponsor:"赞助商",selfpromo:"自我推广",interaction:"互动提醒",intro:"开场动画",outro:"结尾推荐",preview:"预告",filler:"无关内容",music_offtopic:"非音乐部分"}[e]||e||"广告"}formatTime(e){return `${Math.floor(e/60)}:${Math.floor(e%60).toString().padStart(2,"0")}`}isVIPUser(){const e=document.querySelector(".bili-avatar-pendent-dom"),t=document.querySelector(".bpx-player-video-info-vip"),n=localStorage.getItem("bili_vip_status");return !(!e&&!t&&"true"!==n)}destroy(){super.destroy();}}class De extends Le{constructor(){super(),this.platform="youtube",this.adObserver=null;}isVideoPage(){return location.hostname.includes("youtube.com")&&location.pathname.includes("/watch")}getVideoId(){return new URLSearchParams(window.location.search).get("v")}getVideoElement(){return document.querySelector("video.html5-main-video")||document.querySelector("video")}getProgressBar(){return document.querySelector(".ytp-progress-bar")}getAdProgressBar(){return document.querySelector(".ytp-ad-progress-list")}getPlayerContainer(){return document.querySelector("#movie_player")||document.querySelector(".html5-video-player")}detectNativeAdMarkers(){const e=[],t=this.getProgressBar();if(!t)return e;t.querySelectorAll(".ytp-ad-progress, .ytp-play-progress").forEach(t=>{const n=window.getComputedStyle(t);if(n.backgroundColor.includes("255, 204")||n.backgroundColor.includes("254, 205")||t.classList.contains("ytp-ad-progress")){const n=parseFloat(t.style.left)||0,o=parseFloat(t.style.width)||100*(parseFloat(t.style.transform?.match(/scaleX\(([\d.]+)\)/)?.[1])||0);if(o>0&&this.video){const t=this.video.duration,i=n/100*t,s=(n+o)/100*t;e.push({start:Math.max(0,i),end:Math.min(t,s),type:"native_ad",color:"#ffcc00"});}}});return t.querySelectorAll(".ytp-ad-section-marker").forEach(t=>{const n=parseFloat(t.style.left)||0,o=parseFloat(t.style.width)||0;if(o>0&&this.video){const t=this.video.duration,i=n/100*t,s=(n+o)/100*t;e.push({start:Math.max(0,i),end:Math.min(t,s),type:"section_marker",color:"#ffcc00"});}}),e}observeAdChanges(e){const t=this.getProgressBar();t&&(this.adObserver&&this.adObserver.disconnect(),this.adObserver=new MutationObserver(t=>{let n=false;if(t.forEach(e=>{(e.target.classList.contains("ytp-ad-progress")||e.target.classList.contains("ytp-ad-progress-list")||"style"===e.attributeName)&&(n=true);}),n){const t=this.detectNativeAdMarkers();e(t);}}),this.adObserver.observe(t,{attributes:true,attributeFilter:["style","class"],childList:true,subtree:true}));}showNotification(e,t={}){const{duration:n=3e3,type:o="info",position:i="top-right"}=t,s=document.createElement("div");s.className="youtube-skip-notification",s.textContent=e,s.style.cssText=`\n position: absolute;\n ${i.includes("top")?"top: 70px":"bottom: 70px"};\n ${i.includes("right")?"right: 12px":"left: 12px"};\n background: ${"warning"===o?"#ff9800":"success"===o?"#4caf50":"#2196f3"};\n color: white;\n padding: 12px 20px;\n border-radius: 4px;\n font-size: 14px;\n font-weight: 500;\n box-shadow: 0 2px 5px rgba(0,0,0,0.3);\n z-index: 1000;\n animation: slideIn 0.3s ease;\n pointer-events: none;\n `;const r=this.getPlayerContainer();r&&(r.appendChild(s),setTimeout(()=>{s.style.animation="slideOut 0.3s ease",setTimeout(()=>s.remove(),300);},n));}addProgressMarkers(e,t={}){const{containerId:n="universal-ad-markers",className:o="universal-ad-marker",color:i="#ff0000",opacity:s=.7}=t,r=this.getProgressBar();if(!r||!this.video)return;const a=this.video.duration;if(!a||0===a)return we.debug("YouTubeAdapter","视频时长无效,延迟添加标记"),void setTimeout(()=>this.addProgressMarkers(e,t),1e3);const l=document.getElementById(n);l&&l.remove();const c=document.createElement("div");c.id=n,c.style.cssText="\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 40;\n display: flex;\n align-items: center;\n ";const d={sponsor:"#00d400",intro:"#00ffff",outro:"#0202ed",selfpromo:"#ffff00",interaction:"#cc00ff",preview:"#008fd6",filler:"#7300ff",music_offtopic:"#ff9900"};e.forEach((e,t)=>{const n=e.start||e.segment?.[0]||0,r=e.end||e.segment?.[1]||0;if(n>=r||n<0||r>a)return void we.warn("YouTubeAdapter",`跳过无效段落: ${n}-${r}`);const l=n/a*100,u=(r-n)/a*100,p=document.createElement("div");p.className=o,p.dataset.segmentIndex=t.toString(),p.dataset.category=e.category||"unknown";const h=d[e.category]||e.color||i;p.style.cssText=`\n position: absolute;\n left: ${l}%;\n width: ${u}%;\n height: 100%;\n background-color: ${h};\n opacity: ${s};\n pointer-events: auto;\n cursor: pointer;\n box-sizing: border-box;\n transition: opacity 0.2s;\n `,p.addEventListener("mouseenter",()=>{p.style.opacity="1";}),p.addEventListener("mouseleave",()=>{p.style.opacity=s.toString();});const g=this.getCategoryName(e.category);p.title=`${g}: ${this.formatTime(n)} - ${this.formatTime(r)}`,p.addEventListener("click",t=>{t.stopPropagation(),t.preventDefault(),"mute"!==e.actionType&&(this.seekTo(r),this.showNotification(`跳过了 ${g}`,{type:"success"}));}),c.appendChild(p);});const u=r.querySelector(".ytp-progress-bar-container"),p=r.querySelector(".ytp-play-progress"),h=r.querySelector(".ytp-load-progress");u?p&&p.parentElement?p.parentElement.insertBefore(c,p.nextSibling):h&&h.parentElement?h.parentElement.appendChild(c):u.appendChild(c):r.appendChild(c),we.info("YouTubeAdapter",`已添加 ${e.length} 个进度条标记`);}getCategoryName(e){return {sponsor:"赞助商",selfpromo:"自我推广",interaction:"互动提醒",intro:"片头",outro:"片尾",preview:"预告",filler:"填充内容",music_offtopic:"非音乐内容"}[e]||e||"广告"}formatTime(e){return `${Math.floor(e/60)}:${Math.floor(e%60).toString().padStart(2,"0")}`}isPremiumUser(){const e=document.querySelector(".ytp-premium-badge"),t="1"===new URLSearchParams(window.location.search).get("premium"),n="true"===localStorage.getItem("yt-player-premium");return !!(e||t||n)}destroy(){this.adObserver&&(this.adObserver.disconnect(),this.adObserver=null),super.destroy();}}class qe{static decorateClass(e,t,n={}){const{includeMethods:o=[],excludeMethods:i=[],logLevel:s="trace",logArgs:r=true,logReturn:a=true,logTime:l=true}=n,c=e.prototype;return Object.getOwnPropertyNames(c).forEach(e=>{if("constructor"===e||e.startsWith("_"))return;if(i.includes(e))return;if(o.length>0&&!o.includes(e))return;const n=c[e];"function"==typeof n&&(c[e]=function(...o){const i=l?performance.now():0;we.isDebugMode()&&(we.trace(t,`→ ${e}()${r&&o.length>0?" with args:":""}`),r&&o.length>0&&o.forEach((e,n)=>{we.trace(t,` [${n}]:`,this._formatArgument(e));}));try{const s=n.apply(this,o);if(s instanceof Promise)return s.then(n=>{if(we.isDebugMode()){const o=l?(performance.now()-i).toFixed(2):0;we.trace(t,`← ${e}() async completed${l?` in ${o}ms`:""}`),a&&void 0!==n&&we.trace(t," Return:",this._formatArgument(n));}return n}).catch(n=>{if(we.isDebugMode()){const o=l?(performance.now()-i).toFixed(2):0;we.error(t,`✗ ${e}() failed${l?` after ${o}ms`:""}:`,n);}throw n});if(we.isDebugMode()){const n=l?(performance.now()-i).toFixed(2):0;we.trace(t,`← ${e}()${l?` in ${n}ms`:""}`),a&&void 0!==s&&we.trace(t," Return:",this._formatArgument(s));}return s}catch(s){if(we.isDebugMode()){const n=l?(performance.now()-i).toFixed(2):0;we.error(t,`✗ ${e}() failed${l?` after ${n}ms`:""}:`,s);}throw s}},Object.defineProperty(c[e],"name",{value:e,configurable:true}));}),c._formatArgument=function(e){if(null===e)return "null";if(void 0===e)return "undefined";const t=typeof e;if("string"===t)return e.length>100?`"${e.substring(0,100)}..."`:`"${e}"`;if("number"===t||"boolean"===t)return e;if("function"===t)return `[Function: ${e.name||"anonymous"}]`;if(Array.isArray(e))return `[Array(${e.length})]`;if(e instanceof Error)return `[Error: ${e.message}]`;if("object"===t){const t=Object.keys(e);return t.length<=3?JSON.stringify(e):`{${t.slice(0,3).join(", ")}...}`}return String(e)},e}static decorateMethod(e,t,n,o={}){const{logLevel:i="trace",logArgs:s=true,logReturn:r=true,logTime:a=true}=o;return function(...o){const i=a?performance.now():0;we.isDebugMode()&&(we.trace(t,`→ ${n}()${s&&o.length>0?" with args:":""}`),s&&o.length>0&&o.forEach((e,n)=>{we.trace(t,` [${n}]:`,qe.formatArgument(e));}));try{const s=e.apply(this,o);if(s instanceof Promise)return s.then(e=>{if(we.isDebugMode()){const o=a?(performance.now()-i).toFixed(2):0;we.trace(t,`← ${n}() async completed${a?` in ${o}ms`:""}`),r&&void 0!==e&&we.trace(t," Return:",qe.formatArgument(e));}return e}).catch(e=>{if(we.isDebugMode()){const o=a?(performance.now()-i).toFixed(2):0;we.error(t,`✗ ${n}() failed${a?` after ${o}ms`:""}:`,e);}throw e});if(we.isDebugMode()){const e=a?(performance.now()-i).toFixed(2):0;we.trace(t,`← ${n}()${a?` in ${e}ms`:""}`),r&&void 0!==s&&we.trace(t," Return:",qe.formatArgument(s));}return s}catch(l){if(we.isDebugMode()){const e=a?(performance.now()-i).toFixed(2):0;we.error(t,`✗ ${n}() failed${a?` after ${e}ms`:""}:`,l);}throw l}}}static formatArgument(e){if(null===e)return "null";if(void 0===e)return "undefined";const t=typeof e;if("string"===t)return e.length>100?`"${e.substring(0,100)}..."`:`"${e}"`;if("number"===t||"boolean"===t)return e;if("function"===t)return `[Function: ${e.name||"anonymous"}]`;if(Array.isArray(e))return `[Array(${e.length})]`;if(e instanceof Error)return `[Error: ${e.message}]`;if("object"===t){const t=Object.keys(e);if(t.length<=3)try{return JSON.stringify(e)}catch{return `{${t.slice(0,3).join(", ")}...}`}return `{${t.slice(0,3).join(", ")}...}`}return String(e)}static createModuleLogger(e){return {trace:(...t)=>we.trace(e,...t),debug:(...t)=>we.debug(e,...t),info:(...t)=>we.info(e,...t),success:(...t)=>we.success(e,...t),warn:(...t)=>we.warn(e,...t),error:(...t)=>we.error(e,...t),group:t=>we.group(e,t),groupEnd:()=>we.groupEnd(),table:t=>we.table(e,t),time:t=>we.time(`${e}-${t}`),timeEnd:t=>we.timeEnd(`${e}-${t}`)}}}const ze=new class{constructor(){this.enabled=true;}measure(e,t){if(!this.enabled)return t();const n=performance.now();let o,i;try{o=t();}catch(r){i=r;}const s=performance.now()-n;if(we.debug("计时",`${e}: ${s.toFixed(2)}ms`),i)throw i;return o}async measureAsync(e,t){if(!this.enabled)return await t();const n=performance.now();let o,i;try{o=await t();}catch(r){i=r;}const s=performance.now()-n;if(we.debug("计时",`${e}: ${s.toFixed(2)}ms`),i)throw i;return o}destroy(){}};function Re(e){const t=Math.floor(e/60),n=Math.floor(e%60);return `${t.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`}function Oe(){const e=location.hostname;if(e.includes("youtube.com")){return {videoId:new URLSearchParams(window.location.search).get("v"),platform:"youtube",bvid:null,cid:null,aid:null,p:null}}if(e.includes("bilibili.com")){let e=null,t=null,n=null,i=null;e=function(e=window.location.href){const t=e.match(oe);if(t)return t[1];const n=e.match(ie);return n?n[0]:null}();const s=new URLSearchParams(window.location.search).get("p");i=s?parseInt(s,10):1;try{const o=unsafeWindow.__INITIAL_STATE__;if(o&&o.videoData){if(e=e||o.videoData.bvid,o.videoData.pages&&o.videoData.pages.length>0){const e=i-1;t=o.videoData.pages[e]?o.videoData.pages[e].cid:o.videoData.pages[0].cid;}else t=o.videoData.cid;n=o.videoData.aid;}}catch(o){}return {bvid:e,cid:t,aid:n,p:i,videoId:e,platform:"bilibili"}}let t=null;const n=document.querySelector('meta[property="og:url"]');if(n){const e=n.content.split("/").filter(e=>e);t=e[e.length-1];}return {bvid:null,cid:null,aid:null,p:null,videoId:t,platform:"unknown"}}function Ve(){const e=location.hostname;let t="";if(e.includes("youtube.com")){const e=document.querySelector("h1.ytd-video-primary-info-renderer yt-formatted-string")||document.querySelector("h1 yt-formatted-string.style-scope.ytd-watch-metadata")||document.querySelector("#title h1")||document.querySelector("h1.title");if(e&&(t=e.textContent.trim()),!t){const e=document.querySelector('meta[property="og:title"]')||document.querySelector('meta[name="title"]');e&&(t=e.content);}return t||(t=document.title.replace(" - YouTube","").trim()),t||"未知视频"}if(e.includes("bilibili.com")){try{const e=unsafeWindow.__INITIAL_STATE__;e&&e.videoData&&e.videoData.title&&(t=e.videoData.title);}catch(o){}if(!t){const e=document.querySelector(de);e&&(t=e.textContent.trim());}return t||(t=document.title.replace(/_哔哩哔哩.*$/,"").replace(/_bilibili.*$/i,"").trim()),t||"未知视频"}const n=document.querySelector('meta[property="og:title"]');if(n&&(t=n.content),!t){const e=document.querySelector("h1");e&&(t=e.textContent.trim());}return t||(t=document.title),t||"未知视频"}function je(){const e=location.hostname;if(e.includes("youtube.com")){const e=document.querySelector("#owner #channel-name a")||document.querySelector("#upload-info #channel-name a")||document.querySelector("ytd-channel-name a")||document.querySelector(".ytd-channel-name a")||document.querySelector("#owner-name a");if(e)return e.textContent.trim();const t=document.querySelector('link[itemprop="name"]');return t?t.content:"未知"}if(e.includes("bilibili.com")){try{const e=unsafeWindow.__INITIAL_STATE__;if(e&&e.videoData&&e.videoData.owner)return e.videoData.owner.name}catch(n){}const e=document.querySelector(".up-name")||document.querySelector(".up-info__name")||document.querySelector(".up-detail-name");return e?e.textContent.trim():"未知"}const t=document.querySelector('meta[name="author"]')||document.querySelector('meta[property="article:author"]');return t?t.content:"未知"}function Ue(){return window.location.href.split("?")[0]}function Fe(e){return new Promise(t=>setTimeout(t,e))}function Ke(e,t,n="操作超时"){return Promise.race([e,new Promise((e,o)=>setTimeout(()=>o(new Error(n)),t))])}function He(e,t="提示"){return function(e,t={}){return new Promise(n=>{const{title:o="确认操作",confirmText:i="确认",cancelText:s="取消",type:r="info"}=t;we.debug("ConfirmDialog",`显示确认对话框: ${e}`);const a=document.createElement("div");a.className="confirm-dialog-overlay",a.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.6);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999999;\n animation: fadeIn 0.2s ease-out;\n ";const l=document.createElement("div");l.className="confirm-dialog",l.style.cssText="\n background: white;\n border-radius: 12px;\n padding: 0;\n min-width: 320px;\n max-width: 480px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n animation: slideIn 0.3s ease-out;\n ";const c={info:"#1890ff",warning:"#faad14",danger:"#ff4d4f"},d=c[r]||c.info,u=document.createElement("div");u.style.cssText="\n padding: 20px 24px;\n border-bottom: 1px solid #f0f0f0;\n ",u.innerHTML=`\n
]*>\s*<\/code><\/pre>/g,""),e}catch(o){we.warn("UIRenderer","Marked解析失败:",o);}let n=t;return n=n.replace(/```([a-zA-Z0-9]*)?\n([\s\S]*?)```/g,(e,t,n)=>{if(!n.trim())return "";return `${this._escapeHtml(n)}
`}),n=n.replace(/^### (.*$)/gim,"$1
"),n=n.replace(/^## (.*$)/gim,"$1
"),n=n.replace(/^# (.*$)/gim,"$1
"),n=n.replace(/\*\*(.*?)\*\*/g,"$1"),n=n.replace(/(?$1"),n=n.replace(/`([^`]+)`/g,"$1"),n=n.replace(/^\* (.*$)/gim,"$1 "),n=n.replace(/^- (.*$)/gim,"$1 "),n=n.replace(/^\d+\. (.*$)/gim,"$1 "),n=n.replace(/(.*<\/li>(?:\s* .*<\/li>)*)/g,"$1
"),n=n.replace(/((?:- .*<\/li>\s*)+)<\/ul>/g,(e,n)=>t.split("\n").some(e=>/^\d+\.\s+/.test(e))?`
${n}
`:e),n=n.replace(/\n/g,"
"),n}normalizeMarkdown(e){if(!e)return "";let t=String(e).replace(/\r\n/g,"\n").replace(/\r/g,"\n").trim();const n=t.match(/^```[a-zA-Z0-9+_-]*\s*\n([\s\S]*?)\s*```$/);n&&(t=n[1]);const o=t.split("\n"),i=o.filter(e=>e.trim().length>0);if(i.length>0){const e=Math.min(...i.map(e=>e.match(/^ */)[0].length));e>0&&(t=o.map(t=>t.startsWith(" ".repeat(e))?t.slice(e):t).join("\n"));}return t.trim()}renderAISummaryPanel(e=null,t=false){let n="";if(e){let t="",o=[];if("object"==typeof e&&e.markdown)t=this.parseMarkdown(e.markdown),o=e.segments||[];else if("string"==typeof e){t=this.parseAISummary(e).mainSummary;}n='',o&&o.length>0&&(n+=`\n \n AI时间戳段落\n ${this.renderAISegments(o)}\n \n \n `),n+=t.trim()?`\n \n ${t}\n \n `:'暂无总结内容',n+="";}else n='\n \n 点击上方AI图标生成视频总结
\n \n ';return n}parseAISummary(e){let t="",n=[];const o=e.match(/\[总结\]([\s\S]*?)(?=\[段落\]|$)/i),i=e.match(/\[段落\]([\s\S]*)/i);if(o&&o[1]){const e=o[1].trim();t=this.parseMarkdown(e);}if(i&&i[1]){const e=i[1],t=/\[(\d{1,2}:\d{2}(?::\d{2})?)\]\s*([^\n]+?)(?:\n\s+([^\[]+?))?(?=\[|$)/g;let o;for(;null!==(o=t.exec(e));){const[e,t,i,s]=o;let r=t;const a=t.split(":");if(2===a.length)r=`[${a[0].padStart(2,"0")}:${a[1].padStart(2,"0")}]`;else if(3===a.length){r=`[${(60*parseInt(a[0])+parseInt(a[1])).toString().padStart(2,"0")}:${a[2].padStart(2,"0")}]`;}const l=i.trim(),c=s?s.trim():"";n.push({title:l,time:r,content:c});}}if(!t&&0===n.length){const o=e.split("\n");let i=[],s=false;for(const e of o){const t=e.trim();if(t.match(/^\[\d{1,2}:\d{2}(?::\d{2})?\]/)){s=true;const e=t.match(/^\[(\d{1,2}:\d{2}(?::\d{2})?)\]\s*(.*)/);if(e){const[t,o,i]=e;let s=o;const r=o.split(":");if(2===r.length)s=`[${r[0].padStart(2,"0")}:${r[1].padStart(2,"0")}]`;else if(3===r.length){s=`[${(60*parseInt(r[0])+parseInt(r[1])).toString().padStart(2,"0")}:${r[2].padStart(2,"0")}]`;}n.push({title:i.trim(),time:s,content:""});}}else s?n.length>0&&e.startsWith(" ")&&(n[n.length-1].content+=(n[n.length-1].content?" ":"")+t):i.push(e);}i.length>0&&(t=this.parseMarkdown(i.join("\n").trim()));}if(!t&&0===n.length){const o=e.split(/##\s*要点/i);if(o.length>=2){const e=o[0].replace(/##\s*总结/i,"").trim();t=this.parseMarkdown(e);const i=o[1].matchAll(/###\s*\[?([^\]\n]+)\]?[\s\S]*?-\s*时间[::]\s*\[(\d{1,2}):(\d{2})\][\s\S]*?-\s*内容[::]\s*([^\n]+)/gi);for(const t of i){const[e,o,i,s,r]=t;n.push({title:o.trim(),time:`[${i.padStart(2,"0")}:${s.padStart(2,"0")}]`,content:r.trim()});}}}return t||0!==n.length||(t=this.parseMarkdown(e)),{mainSummary:t,keyPoints:n}}renderAISummarySection(e=null,t=false){const n=document.createElement("div");return n.className="ai-summary-section",n.innerHTML=this.renderAISummaryPanel(e,t),n}updateAISummary(e,t){if(e||(e=document.getElementById("subtitle-container")),!e)return;const n=e.querySelector("#summary-panel");n&&(n.innerHTML=this.renderAISummaryPanel(t,false));}renderAISegments(e){return e.map((e,t)=>{const n=(e.timestamp||"[00:00]").replace(/[\[\]]/g,"");return `\n \n \n \n ${e.summary?`${e.title||""}\n ${e.summary}`:`${e.title||""}`}\n \n \n `}).join("")}createNotification(e){const t=document.createElement("div");return t.className="notion-toast show",t.textContent=e,document.body.appendChild(t),setTimeout(()=>{t.remove();},3e3),t}createNotionConfigModal(){const e=document.createElement("div");return e.id="notion-config-modal",e.className="config-modal",e.innerHTML='\n \n ',e}createAIConfigModal(){const e=document.createElement("div");return e.id="ai-config-modal",e.className="config-modal",e.innerHTML='\n \n ',e}renderAIConfigList(e){const t=$e.getAIConfigs(),n=$e.getSelectedAIConfigId();e.innerHTML=t.map(e=>{const t=e.apiKey&&""!==e.apiKey.trim(),o=t?"✅":"⚠️",i=t?"已配置":"未配置",s=t?"#4ade80":"#fbbf24";return `\n \n \n ${e.name}\n \n ${o} ${i}\n \n \n \n \n \n \n `}).join("");}showNotionStatus(e,t=false){const n=document.getElementById("notion-status-message");n&&(n.className="config-status "+(t?"error":"success"),n.textContent=e);}renderShortcutConfigModal(){if(we.debug("UIRenderer","renderShortcutConfigModal 开始"),!Me)return console.error("[UIRenderer] shortcutManager 未定义"),null;let e;try{e=Me.getAllShortcuts(),we.debug("UIRenderer","获取到快捷键:",e);}catch(t){return console.error("[UIRenderer] 获取快捷键失败:",t),null}return e&&"object"==typeof e?`\n \n \n \n `:(console.error("[UIRenderer] 快捷键配置无效:",e),null)}};const Tt=new class{constructor(){this.stack=[],this.escHandler=null,this.init();}init(){this.escHandler=e=>{if("Escape"===e.key&&this.stack.length>0){const e=this.stack[this.stack.length-1];e&&"function"==typeof e.hide&&e.hide();}},document.addEventListener("keydown",this.escHandler);}push(e){if(!e||"function"!=typeof e.hide)return void we.warn("ModalManager","模态框实例必须有hide方法");-1===this.stack.indexOf(e)&&this.stack.push(e);}pop(e){const t=this.stack.indexOf(e);t>-1&&this.stack.splice(t,1);}closeAll(){for(;this.stack.length>0;){const e=this.stack.pop();e&&"function"==typeof e.hide&&e.hide();}}getStackSize(){return this.stack.length}isInStack(e){return this.stack.includes(e)}destroy(){this.escHandler&&(document.removeEventListener("keydown",this.escHandler),this.escHandler=null),this.stack=[];}};const Ct=new class{constructor(){this.panel=null,this.isPanelVisible=false,this.filters={showText:true,showScreenshot:true};}createPanel(){return this.panel||(this.panel=document.createElement("div"),this.panel.id="notes-panel",this.panel.className="notes-panel",document.body.appendChild(this.panel)),this.panel}showPanel(){const e=this.createPanel();this.renderPanel(),e.classList.add("show"),this.isPanelVisible=true,Tt.push(this);}hidePanel(){this.panel&&this.panel.classList.remove("show"),this.isPanelVisible=false,Tt.pop(this);}hide(){this.hidePanel();}togglePanel(){this.isPanelVisible?this.hidePanel():this.showPanel();}renderPanel(){const e=this.createPanel(),t=this.getFilteredGroupedNotes(),n=ot.getAllNotes(),o=n.filter(e=>"screenshot"!==e.type&&"ai-summary"!==e.type).length,i=n.filter(e=>"ai-summary"===e.type).length,s=n.filter(e=>"screenshot"===e.type).length,r=o+i,a=`\n \n \n 我的笔记
\n \n \n \n \n \n \n \n ${0===t.length?this.renderEmptyState():t.map(e=>this.renderGroup(e)).join("")}\n \n \n `;e.innerHTML=a,this.bindPanelEvents();}getFilteredGroupedNotes(){const e=ot.getAllNotes().filter(e=>"screenshot"===e.type?this.filters.showScreenshot:(e.type,this.filters.showText)),t={};return e.forEach(e=>{const n=e.createdAt||e.timestamp,o=ot.formatDate(n);t[o]||(t[o]=[]),t[o].push(e);}),Object.keys(t).sort((e,n)=>{const o=t[e][0].createdAt||t[e][0].timestamp;return (t[n][0].createdAt||t[n][0].timestamp)-o}).map(e=>({date:e,notes:t[e].sort((e,t)=>{if("ai-summary"===e.type&&"ai-summary"!==t.type)return -1;if("ai-summary"!==e.type&&"ai-summary"===t.type)return 1;const n=e.createdAt||e.timestamp;return (t.createdAt||t.timestamp)-n})}))}renderEmptyState(){if(ot.getAllNotes().length>0)return '\n \n \n 没有符合筛选条件的笔记\n 请调整上方的筛选条件\n \n ';{let t="截图";try{const e=window.shortcutManager;if(e){const n=e.getAllShortcuts();n.takeScreenshot&&(t=e.formatShortcut(n.takeScreenshot));}}catch(e){}return `\n \n \n 还没有保存任何笔记\n 选中文字后点击粉色钢笔即可保存
或使用 ${t} 保存截图\n \n `}}renderGroup(e){return `\n \n \n \n ${e.date} (${e.notes.length}条)\n \n \n \n \n \n \n \n ${e.notes.map(e=>this.renderNote(e)).join("")}\n \n \n `}renderNote(e){if("ai-summary"===e.type)return this.renderAISummaryNote(e);const t=e.content.length>200?e.content.substring(0,200)+"...":e.content,n="screenshot"===e.type&&e.imageData?`\n \n
\n \n ${this.escapeHtml(t)}\n `:`${this.escapeHtml(t)}`;let o="",i="";return "screenshot"===e.type?(o=e.timeString||ot.formatTime(e.createdAt||e.timestamp),e.videoTitle&&"未知视频"!==e.videoTitle?i=` · ${this.escapeHtml(e.videoTitle)}`:e.videoBvid&&(i=` · ${this.escapeHtml(e.videoBvid)}`)):(o=ot.formatTime(e.timestamp),e.videoTitle&&(i=` · ${this.escapeHtml(e.videoTitle)}`)),`\n \n ${n}\n \n \n `}renderAISummaryNote(e){const t=e.videoInfo?.title||e.videoBvid||"未知视频",n=`\n \n 📹 视频信息\n \n ${this.escapeHtml(t)}\n \n \n `,o=e.summary?`\n \n 📊 视频总结\n \n ${this.escapeHtml(e.summary).replace(/\n/g,"
")}\n \n \n `:"",i=e.segments&&e.segments.length>0?`\n \n ⏱️ 时间戳段落\n \n ${e.segments.map((t,n)=>{const o=(e.screenshots||[]).filter(e=>e.segmentIndex===n);return `\n \n \n [${t.timestamp}]\n ${this.escapeHtml(t.title)}\n \n ${this.escapeHtml(t.summary)}\n ${o.map(e=>`\n \n
\n 📸 ${e.timeString}\n \n `).join("")}\n \n `}).join("")}\n \n \n `:"";return `\n \n \n ${n}\n ${o}\n ${i}\n \n \n \n `}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}async copyToClipboard(e){try{if(navigator.clipboard&&navigator.clipboard.writeText)await navigator.clipboard.writeText(e);else {const t=document.createElement("textarea");t.value=e,t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t);}}catch(t){console.error("复制失败:",t);}}bindPanelEvents(){const e=this.panel.querySelector(".notes-panel-close");e&&e.addEventListener("click",()=>this.hidePanel());const t=this.panel.querySelector("#filter-text-notes"),n=this.panel.querySelector("#filter-screenshot-notes");t&&t.addEventListener("change",e=>{this.filters.showText=e.target.checked,this.renderPanel();}),n&&n.addEventListener("change",e=>{this.filters.showScreenshot=e.target.checked,this.renderPanel();});const o=this.panel.querySelector(".notes-panel-body");o&&o.addEventListener("click",async e=>{const t=e.target.closest(".note-copy-btn");if(t){const e=t.getAttribute("data-note-id"),n=ot.getAllNotes().find(t=>t.id===e);if(n){await this.copyToClipboard(n.content);const e=t.textContent;t.textContent="✓",setTimeout(()=>{t.textContent=e;},1e3);}return}const n=e.target.closest(".note-delete-btn");if(n){const e=n.getAttribute("data-note-id");return ot.deleteNote(e),void this.renderPanel()}const o=e.target.closest(".note-group-copy-btn");if(o){const e=o.getAttribute("data-date"),t=ot.getGroupedNotes().find(t=>t.date===e);if(t){const e=t.notes.map(e=>e.content).join("\n\n");await this.copyToClipboard(e);const n=o.textContent;o.textContent="✓",setTimeout(()=>{o.textContent=n;},1e3);}return}const i=e.target.closest(".note-group-delete-btn");if(i){const e=i.getAttribute("data-date"),t=ot.getGroupedNotes().find(t=>t.date===e);if(t&&confirm(`确定要删除 ${e} 的 ${t.notes.length} 条笔记吗?`)){const e=t.notes.map(e=>e.id);ot.deleteNotes(e),this.renderPanel();}return}});}addSaveButton(e){if(e.querySelector(".save-subtitle-note-btn"))return;const t=e.querySelector(".subtitle-text")?.textContent;if(!t)return;const n=document.createElement("button");n.className="save-subtitle-note-btn",n.textContent="保存",n.title="保存此字幕为笔记",n.addEventListener("click",e=>{e.stopPropagation(),ot.saveSubtitleNote(t),n.textContent="✓",setTimeout(()=>{n.textContent="保存";},1e3);});const o=e.querySelector(".subtitle-time");o&&o.appendChild(n);}addSaveButtonsToSubtitles(e){e.querySelectorAll(".subtitle-item").forEach(e=>this.addSaveButton(e));}};const Et=new class{constructor(){this.container=null,this.video=null,this.isFollowing=true,this.scrollTimer=null,this.followInterval=null,this.userScrollTimeout=null,this.lastScrollTime=0,this.lastHighlightedItem=null,this.config={followIntervalMs:200,userScrollDetectMs:300,scrollBehavior:"smooth",scrollPosition:"start",highlightClass:"current"},this.callbacks={onFollowStatusChange:null,onSubtitleHighlight:null};}init(e,t={}){e?(this.container=e,this.video=document.querySelector("video"),this.video?(this.config={...this.config,...t},this.setupScrollListener(),this.startAutoFollow()):console.warn("SubtitleScrollManager: 未找到视频元素")):console.warn("SubtitleScrollManager: 容器不存在");}setupScrollListener(){this.container&&this.container.addEventListener("scroll",()=>{this.handleUserScroll();},{passive:true});}handleUserScroll(){Date.now()-this.lastScrollTime<50||(this.userScrollTimeout&&clearTimeout(this.userScrollTimeout),this.isFollowing,this.userScrollTimeout=setTimeout(()=>{this.isFollowing&&(this.isFollowing=false,this.triggerFollowStatusChange(false));},this.config.userScrollDetectMs));}startAutoFollow(){this.stopAutoFollow(),this.isFollowing=true,this.triggerFollowStatusChange(true),this.updateScroll(),this.followInterval=setInterval(()=>{this.isFollowing&&this.updateScroll();},this.config.followIntervalMs);}stopAutoFollow(){this.followInterval&&(clearInterval(this.followInterval),this.followInterval=null),this.isFollowing=false,this.triggerFollowStatusChange(false);}resumeAutoFollow(){this.startAutoFollow(),this.scrollToCurrentSubtitle(true);}updateScroll(){if(!this.video||!this.container)return;const e=this.video.currentTime,t=this.container.querySelectorAll(".subtitle-item");if(0===t.length)return;let n=null;for(let o=0;o=s&&e<=r){n=i;break}if(o=s&&e=n&&t<=i){this.updateHighlight(o),this.scrollToElement(o,e);break}}}triggerFollowStatusChange(e){this.callbacks.onFollowStatusChange&&this.callbacks.onFollowStatusChange(e);}on(e,t){this.callbacks.hasOwnProperty(e)&&(this.callbacks[e]=t);}updateConfig(e){this.config={...this.config,...e};}isAutoFollowing(){return this.isFollowing}destroy(){this.stopAutoFollow(),this.userScrollTimeout&&(clearTimeout(this.userScrollTimeout),this.userScrollTimeout=null),this.lastHighlightedItem&&(this.lastHighlightedItem.classList.remove(this.config.highlightClass),this.lastHighlightedItem=null),this.container=null,this.video=null,this.callbacks={onFollowStatusChange:null,onSubtitleHighlight:null};}};const At=new class{constructor(){this.isDragging=false,this.dragStartX=0,this.dragStartY=0,this.translateX=0,this.translateY=0,this.isResizing=false,this.resizeStartX=0,this.resizeStartY=0,this.resizeStartWidth=0,this.resizeStartHeight=0,this.subtitleDataCache=null,this.currentHighlightedIndex=-1,this.throttledHighlight=null,this.aiConfigModalProxy={hide:()=>this.hideAIConfigModal()},this.notionConfigModalProxy={hide:()=>this.hideNotionConfigModal()},this.shortcutConfigModalProxy={hide:()=>this.hideShortcutConfigModal()};}bindSubtitlePanelEvents(e){this.restoreContainerState(e),this.bindDragEvents(e),this.bindResizeEvents(e),this.observeContainerResize(e);const t=e.querySelector(".subtitle-close");t&&t.addEventListener("click",()=>{Ae.setPanelVisible(false),e.classList.remove("show"),Et.destroy();});const n=e.querySelector(".ai-icon");n&&n.addEventListener("click",async e=>{if(e.stopPropagation(),Ae.ai.isSummarizing)return void et.warning("AI总结正在生成中,请稍候...");const t=Ae.getSubtitleData();if(!t||0===t.length)return void et.error("没有可用的字幕数据");if(!$e.getSelectedAIConfig())return void et.warning("请先在油猴菜单中AI配置中选择或配置一个AI服务");const n=Ae.getVideoKey();if(Ae.getAISummary(n)){if(!confirm('已存在AI总结,是否重新生成?\n\n点击"确定"重新生成\n点击"取消"查看现有总结'))return;n&&sessionStorage.removeItem(`ai-summary-${n}`),Ae.ai.currentSummary=null;}try{await it.summarize(t,!0);}catch(o){et.handleError(o,"AI总结");}});const o=e.querySelector("#progress-switch");o&&o.addEventListener("click",()=>{o.classList.toggle("on");o.classList.contains("on")?this.addProgressBarMarkers(e):this.removeProgressBarMarkers();});const i=e.querySelector(".download-icon");i&&i.addEventListener("click",e=>{e.stopPropagation();try{Ye.downloadSubtitleFile(),et.success("字幕文件已下载");}catch(t){et.handleError(t,"下载字幕");}});const s=e.querySelector(".notion-icon");s&&s.addEventListener("click",async e=>{if(e.stopPropagation(),Ae.ai.isSummarizing)return void et.warning("AI总结正在生成中,请稍后再发送到Notion");const t=Ae.getSubtitleData();if(t&&0!==t.length)try{const e=Ae.getVideoInfo(),n=Ae.getVideoKey(),o=n?Ae.getAISummary(n):null;if(Ae.getNotionPageId(n)){confirm('该视频已经发送到Notion。\n\n点击"确定"更新现有页面\n点击"取消"创建新页面')||Ae.setNotionPageId(n,null);}const i=$e.getNotionContentOptions().subtitles?t:null;await tt.sendComplete(i,o,e);}catch(n){et.handleError(n,"Notion发送");}else et.error("没有字幕数据可发送");}),e.addEventListener("click",t=>{const n=t.target.closest(".section-item");if(n){t.stopPropagation();const e=window.getSelection();e&&e.removeAllRanges(),we.info("EventHandlers","段落元素被点击");const o=n.getAttribute("data-time");if(we.info("EventHandlers","时间戳字符串:",o),o){let e=0;const t=o.match(/\[?(\d{1,2}):(\d{2})(?::(\d{2}))?\]?/);if(t){const[i,s,r,a]=t;e=a?3600*parseInt(s)+60*parseInt(r)+parseInt(a):60*parseInt(s)+parseInt(r),we.info("EventHandlers","解析后的秒数:",e);const l=document.querySelector(re);if(l){l.currentTime=e;const t=o.replace(/[\[\]]/g,"");et.info(`跳转到 ${t}`),n.classList.add("clicked"),setTimeout(()=>{n.classList.remove("clicked");},300);}}}return}const o=t.target.closest(".save-subtitle-note-btn");if(o){t.stopPropagation();const e=o.getAttribute("data-content");return void(e&&(ot.saveSubtitleNote(e),o.textContent="✓",setTimeout(()=>{o.textContent="保存";},1e3)))}const i=t.target.closest(".subtitle-item");if(i){const t=document.querySelector(re);if(t){const n=parseFloat(i.dataset.from);e.querySelectorAll(".subtitle-item").forEach(e=>{e.classList.remove("current");}),i.classList.add("current"),t.currentTime=n;}}}),this.syncSubtitleHighlight(e);}setupDragging(e){const t=e.querySelector(".subtitle-header");t&&(t.addEventListener("mousedown",t=>{t.target.closest(".subtitle-close")||t.target.closest(".ai-icon")||t.target.closest(".download-icon")||t.target.closest(".notion-icon")||(this.isDragging=true,this.dragStartX=t.clientX,this.dragStartY=t.clientY,e.style.willChange="transform",t.preventDefault());}),document.addEventListener("mousemove",t=>{this.isDragging&&requestAnimationFrame(()=>{const n=t.clientX-this.dragStartX,o=t.clientY-this.dragStartY;this.translateX+=n,this.translateY+=o,this.dragStartX=t.clientX,this.dragStartY=t.clientY,e.style.transform=`translate(${this.translateX}px, ${this.translateY}px)`;});}),document.addEventListener("mouseup",()=>{this.isDragging&&(this.isDragging=false,e.style.willChange="auto",this.savePanelPosition(e));}));}setupResize(e){const t=e.querySelector(".subtitle-resize-handle");t&&(t.addEventListener("mousedown",t=>{this.isResizing=true,this.resizeStartX=t.clientX,this.resizeStartY=t.clientY,this.resizeStartWidth=e.offsetWidth,this.resizeStartHeight=e.offsetHeight,t.preventDefault(),t.stopPropagation();}),document.addEventListener("mousemove",t=>{this.isResizing&&requestAnimationFrame(()=>{const n=t.clientX-this.resizeStartX,o=t.clientY-this.resizeStartY,i=this.resizeStartWidth+n,s=this.resizeStartHeight+o,r=Math.max(300,Math.min(800,i)),a=.9*window.innerHeight,l=Math.max(400,Math.min(a,s));e.style.width=`${r}px`,e.style.maxHeight=`${l}px`;});}),document.addEventListener("mouseup",()=>{this.isResizing&&(this.isResizing=false,this.savePanelDimensions(e));}));}savePanelPosition(e){try{localStorage.setItem("subtitle_panel_position",JSON.stringify({translateX:this.translateX,translateY:this.translateY}));}catch(t){console.error("保存面板位置失败:",t);}}savePanelDimensions(e){try{localStorage.setItem("subtitle_panel_dimensions",JSON.stringify({width:e.offsetWidth,height:e.offsetHeight}));}catch(t){console.error("保存面板尺寸失败:",t);}}loadPanelDimensions(e){try{const t=localStorage.getItem("subtitle_panel_dimensions");if(t){const{width:n,height:o}=JSON.parse(t);e.style.width=`${n}px`,e.style.maxHeight=`${o}px`;}const n=localStorage.getItem("subtitle_panel_position");if(n){const{translateX:t,translateY:o}=JSON.parse(n);this.translateX=t,this.translateY=o,e.style.transform=`translate(${t}px, ${o}px)`;}}catch(t){console.error("加载面板设置失败:",t);}}syncSubtitleHighlight(e){const t=st.get(re);if(!t)return;const n=Array.from(e.querySelectorAll(".subtitle-item"));this.subtitleDataCache=n.map(e=>({element:e,from:parseFloat(e.dataset.from),to:parseFloat(e.dataset.to)})),this.throttledHighlight||(this.throttledHighlight=function(e){let t=null;return function(...n){null===t&&(t=requestAnimationFrame(()=>{e.apply(this,n),t=null;}));}}(e=>{this.updateSubtitleHighlight(e);})),t.addEventListener("timeupdate",()=>{this.throttledHighlight(t.currentTime);});}updateSubtitleHighlight(e){if(!this.subtitleDataCache||0===this.subtitleDataCache.length)return;const t=function(e,t){if(!e||0===e.length)return -1;if(e.length<50){for(let n=0;n=e[n].from&&t<=e[n].to)return n;return -1}let n=0,o=e.length-1;for(;n<=o;){const i=Math.floor((n+o)/2),s=e[i];if(t>=s.from&&t<=s.to)return i;t=0&&this.currentHighlightedIndex=0&&this.subtitleDataCache[t].element.classList.add("current"),this.currentHighlightedIndex=t);}showAIConfigModal(){const e=document.getElementById("ai-config-modal");if(!e)return;const t=document.getElementById("ai-config-list");t&&It.renderAIConfigList(t),this.clearAIConfigForm();const n=e.querySelector(".ai-config-form");n&&n.classList.add("hidden"),document.getElementById("ai-auto-summary-enabled").checked=$e.getAIAutoSummaryEnabled(),e.classList.add("show"),Tt.push(this.aiConfigModalProxy);}hideAIConfigModal(){const e=document.getElementById("ai-config-modal");if(!e)return;const t=document.getElementById("ai-auto-summary-enabled").checked;$e.setAIAutoSummaryEnabled(t),e.classList.remove("show"),this.clearAIConfigForm(),Tt.pop(this.aiConfigModalProxy);}clearAIConfigForm(){const e=document.getElementById("ai-config-name"),t=document.getElementById("ai-config-url"),n=document.getElementById("ai-config-apikey"),o=document.getElementById("ai-config-model"),i=document.getElementById("ai-config-prompt1"),s=document.getElementById("ai-config-prompt2"),r=document.getElementById("ai-config-is-openrouter"),a=document.getElementById("ai-save-new-btn"),l=document.getElementById("ai-update-btn"),c=document.getElementById("model-select-wrapper"),d=document.getElementById("api-key-help-link");e&&(e.value=""),t&&(t.value="https://openrouter.ai/api/v1/chat/completions"),n&&(n.value=""),o&&(o.value="alibaba/tongyi-deepresearch-30b-a3b:free"),i&&(i.value=""),s&&(s.value=""),r&&(r.checked=true),a&&(a.style.display=""),l&&(l.style.display="none"),c&&(c.style.display="none"),d&&(d.innerHTML="");}showNotionConfigModal(){const e=document.getElementById("notion-config-modal");if(!e)return;const t=$e.getNotionConfig(),n=$e.getNotionContentOptions();document.getElementById("notion-api-key").value=t.apiKey,document.getElementById("notion-parent-page-id").value=t.parentPageId,document.getElementById("notion-auto-send-enabled").checked=$e.getNotionAutoSendEnabled(),document.getElementById("notion-content-video-info").checked=n.videoInfo,document.getElementById("notion-content-summary").checked=n.summary,document.getElementById("notion-content-segments").checked=n.segments,document.getElementById("notion-content-subtitles").checked=n.subtitles,document.getElementById("notion-notes-auto-sync").checked=$e.getNotionNotesAutoSync();const o=document.getElementById("notion-status-message");o&&(o.innerHTML=""),e.classList.add("show"),Tt.push(this.notionConfigModalProxy);}hideNotionConfigModal(){const e=document.getElementById("notion-config-modal");e&&e.classList.remove("show"),Tt.pop(this.notionConfigModalProxy);}showShortcutConfigModal(){try{we.debug("EventHandlers","显示快捷键配置模态框");const e=document.getElementById("shortcut-config-modal");if(e)return e.classList.add("show"),void Tt.push(this.shortcutConfigModalProxy);const t=It.renderShortcutConfigModal();if(!t)return console.error("[EventHandlers] 无法生成快捷键配置模态框HTML"),void et.error("无法打开快捷键设置");const n=document.createElement("div");n.innerHTML=t;const o=n.firstElementChild;if(!o)return console.error("[EventHandlers] 无法创建模态框元素"),void et.error("无法创建快捷键设置界面");document.body.appendChild(o),requestAnimationFrame(()=>{o.classList.add("show"),Tt.push(this.shortcutConfigModalProxy);}),this.bindShortcutConfigModalEvents(o),we.debug("EventHandlers","快捷键配置模态框已显示");}catch(e){console.error("[EventHandlers] 显示快捷键配置模态框失败:",e),et.error("打开快捷键设置失败: "+e.message);}}hideShortcutConfigModal(){const e=document.getElementById("shortcut-config-modal");e&&(e.classList.remove("show"),Tt.pop(this.shortcutConfigModalProxy),setTimeout(()=>{e&&e.parentNode&&e.parentNode.removeChild(e);},300));}bindShortcutConfigModalEvents(e){const t=e.querySelector(".config-modal-close");t&&t.addEventListener("click",()=>{this.hideShortcutConfigModal();}),e.addEventListener("click",t=>{t.target===e&&this.hideShortcutConfigModal();});e.querySelectorAll(".shortcut-input").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault(),this.startShortcutCapture(e);});});e.querySelectorAll(".shortcut-reset-btn").forEach(t=>{t.addEventListener("click",()=>{const n=t.dataset.key,o=Me.constructor.DEFAULT_SHORTCUTS||{};if(o[n]){Me.updateShortcut(n,o[n]);const t=e.querySelector(`.shortcut-input[data-key="${n}"]`);t&&(t.value=Me.formatShortcut(o[n])),et.success("已重置到默认值");}});});const n=e.querySelector("#reset-all-shortcuts");n&&n.addEventListener("click",()=>{confirm("确定要重置所有快捷键到默认值吗?")&&(Me.resetToDefaults(),et.success("快捷键已重置到默认值"),this.hideShortcutConfigModal(),this.showShortcutConfigModal());});e.querySelectorAll(".shortcut-mode-btn").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=e.dataset.key,o=e.dataset.mode,i=Me.getAllShortcuts()[n];if(!i)return;const s=e.closest(".shortcut-item"),r=s.querySelector(".shortcut-hold-btn"),a=s.querySelector(".shortcut-double-btn");if("hold"===o){const t=e.classList.contains("active");r.classList.toggle("active"),a.classList.remove("active");const o={...i,holdMode:!t,doubleClickMode:false};Me.updateShortcut(n,o);}else if("double"===o){const t=e.classList.contains("active");a.classList.toggle("active"),r.classList.remove("active");const o={...i,holdMode:false,doubleClickMode:!t};Me.updateShortcut(n,o);}});});}startShortcutCapture(e){const t=e.dataset.key,n=Me.getAllShortcuts()[t];e.classList.add("recording");const o=e.closest(".shortcut-item"),i=o?.querySelector(".shortcut-hold-btn"),s=o?.querySelector(".shortcut-double-btn"),r=i?.classList.contains("active"),a=s?.classList.contains("active");e.value=r||a?"按下任意键...":"按下快捷键...";let l=null,c="";const d=o=>{if(o.preventDefault(),o.stopPropagation(),"Escape"===o.key)return e.classList.remove("recording"),e.value=Me.formatShortcut(n),void document.removeEventListener("keydown",d);if(r||a){const i={key:o.code||o.key,meta:false,ctrl:false,alt:false,shift:false,holdMode:r,doubleClickMode:a},s=Me.updateShortcut(t,i);return s.success?(e.value=Me.formatShortcut(i),et.success("快捷键已更新")):(et.error(s.error),e.value=Me.formatShortcut(n)),e.classList.remove("recording"),void document.removeEventListener("keydown",d)}if(["Meta","Control","Alt","Shift"].includes(o.key))return void(e.value="继续按下字符键...");if(!(o.ctrlKey||o.metaKey||o.altKey||o.shiftKey)&&"takeScreenshot"===t&&"Slash"===o.code){if("Slash"===c&&l){clearTimeout(l);const n={key:"Slash",meta:false,ctrl:false,alt:false,shift:false,doubleClick:true};Me.updateShortcut(t,n).success&&(e.value=Me.formatShortcut(n),et.success("快捷键已更新")),e.classList.remove("recording"),document.removeEventListener("keydown",d);}else c="Slash",l=setTimeout(()=>{l=null,c="";},300);return}const i={key:o.code||o.key,meta:o.metaKey,ctrl:o.ctrlKey,alt:o.altKey,shift:o.shiftKey,doubleClick:false},s=Me.checkConflict(t,i);if(s)et.warning(`与"${s}"冲突,请重新设置`),e.value=Me.formatShortcut(n);else {const o=Me.updateShortcut(t,i);o.success?(e.value=Me.formatShortcut(i),et.success("快捷键已更新")):(et.error(o.error),e.value=Me.formatShortcut(n));}e.classList.remove("recording"),document.removeEventListener("keydown",d);};document.addEventListener("keydown",d);}bindAIConfigModalEvents(e){e.addEventListener("click",t=>{t.target===e&&this.hideAIConfigModal();});const t=document.getElementById("ai-config-list");t&&t.addEventListener("click",n=>{const o=n.target.closest(".ai-config-item"),i=n.target.closest(".ai-edit-btn");if(i){const t=i.dataset.id,n=e.querySelector(".ai-config-form");n&&n.classList.remove("hidden"),this.loadConfigToForm(t);}else if(o&&!i){const n=o.dataset.id;$e.setSelectedAIConfigId(n),It.renderAIConfigList(t);const i=$e.getAIConfigs().find(e=>e.id===n);et.success(`已选择配置: ${i.name}`);const s=e.querySelector(".ai-config-form");s&&s.classList.remove("hidden"),this.loadConfigToForm(n);}});const n=document.getElementById("ai-start-summary-btn");n&&n.addEventListener("click",async()=>{const e=Ae.getSubtitleData();if(!e||0===e.length)return void et.error("没有可用的字幕数据");if($e.getSelectedAIConfig()){this.hideAIConfigModal();try{await it.summarize(e,!0);}catch(t){et.handleError(t,"AI总结");}}else et.warning("请先选择或配置一个AI服务");}),document.getElementById("ai-new-config-btn").addEventListener("click",()=>{this.clearAIConfigForm();const t=e.querySelector(".ai-config-form");t&&(t.classList.remove("hidden"),setTimeout(()=>{t.scrollIntoView({behavior:"smooth",block:"nearest"});},100)),et.info("请填写新配置信息");}),document.getElementById("ai-save-new-btn").addEventListener("click",()=>{this.saveNewAIConfig();}),document.getElementById("ai-update-btn").addEventListener("click",()=>{this.updateAIConfig();}),document.getElementById("ai-cancel-btn").addEventListener("click",()=>{this.hideAIConfigModal();}),document.getElementById("ai-delete-current-btn").addEventListener("click",()=>{const e=document.getElementById("ai-delete-current-btn"),t=e?.dataset.deleteId;if(t&&et.confirm("确定要删除这个配置吗?")){const n=$e.deleteAIConfig(t);if(n.success){et.success("配置已删除");const t=document.getElementById("ai-config-list");t&&It.renderAIConfigList(t);const n=document.querySelector(".ai-config-form");n&&n.classList.add("hidden"),e.style.display="none";}else et.error(n.error);}}),document.getElementById("fetch-models-btn").addEventListener("click",async()=>{await this.fetchModels();});}loadConfigToForm(e){const t=$e.getAIConfigs().find(t=>t.id===e);if(!t)return;const n=document.getElementById("ai-config-name"),o=document.getElementById("ai-config-url"),i=document.getElementById("ai-config-apikey"),s=document.getElementById("ai-config-model"),r=document.getElementById("ai-config-prompt1"),a=document.getElementById("ai-config-prompt2"),l=document.getElementById("ai-config-is-openrouter"),c=document.getElementById("ai-save-new-btn"),d=document.getElementById("ai-update-btn"),u=document.getElementById("model-select-wrapper");n&&(n.value=t.name),o&&(o.value=t.url),i&&(i.value=t.apiKey),s&&(s.value=t.model),r&&(r.value=t.prompt1||""),a&&(a.value=t.prompt2||""),l&&(l.checked=t.isOpenRouter||false);const p=document.getElementById("api-key-help-link");p&&z[t.id]?p.innerHTML=`📖 如何获取API Key?`:p&&(p.innerHTML=""),c&&(c.style.display="none"),d&&(d.style.display="",d.dataset.editId=e),u&&(u.style.display="none");const h=document.getElementById("ai-delete-current-btn");h&&("openrouter"===e||"openai"===e||"siliconflow"===e||"deepseek"===e||"moonshot"===e||"zhipu"===e||"yi"===e||"dashscope"===e||"gemini"===e?h.style.display="none":(h.style.display="",h.dataset.deleteId=e)),setTimeout(()=>{const e=document.querySelector(".ai-config-form");e&&e.scrollIntoView({behavior:"smooth",block:"nearest"});},100);}editAIConfig(e){this.loadConfigToForm(e);}saveNewAIConfig(){const e={name:document.getElementById("ai-config-name").value.trim(),url:document.getElementById("ai-config-url").value.trim(),apiKey:document.getElementById("ai-config-apikey").value.trim(),model:document.getElementById("ai-config-model").value.trim(),prompt1:document.getElementById("ai-config-prompt1").value,prompt2:document.getElementById("ai-config-prompt2").value,isOpenRouter:document.getElementById("ai-config-is-openrouter").checked},t=$e.addAIConfig(e);if(t.success){et.success(`配置"${e.name}"已添加`);const t=document.getElementById("ai-config-list");t&&It.renderAIConfigList(t),this.clearAIConfigForm();}else et.error(t.error);}updateAIConfig(){const e=document.getElementById("ai-update-btn").dataset.editId;if(!e)return;const t={name:document.getElementById("ai-config-name").value.trim(),url:document.getElementById("ai-config-url").value.trim(),apiKey:document.getElementById("ai-config-apikey").value.trim(),model:document.getElementById("ai-config-model").value.trim(),prompt1:document.getElementById("ai-config-prompt1").value,prompt2:document.getElementById("ai-config-prompt2").value,isOpenRouter:document.getElementById("ai-config-is-openrouter").checked},n=$e.updateAIConfig(e,t);if(n.success){et.success(`配置"${t.name}"已更新`);const e=document.getElementById("ai-config-list");e&&It.renderAIConfigList(e),this.clearAIConfigForm();}else et.error(n.error);}async fetchModels(){const e=document.getElementById("ai-config-apikey").value.trim(),t=document.getElementById("ai-config-url").value.trim(),n=document.getElementById("ai-config-is-openrouter").checked;if(!e)return void et.error("请先填写 API Key");if(!n)return void et.error("仅OpenRouter支持获取模型列表");const o=document.getElementById("fetch-models-btn");o.disabled=true,o.textContent="获取中...";try{const n=await it.fetchOpenRouterModels(e,t),o=document.getElementById("model-select-wrapper"),i=document.getElementById("model-select"),s=document.getElementById("model-search-input");if(!i)return void et.error("模型选择器未找到");this.allModels=n,i.innerHTML="",n.forEach(e=>{const t=document.createElement("option");t.value=e.id,t.textContent=`${e.name||e.id} (${e.context_length||"N/A"} tokens)`,t.title=e.id,i.appendChild(t);}),o&&(o.style.display="block"),i.onchange=()=>{document.getElementById("ai-config-model").value=i.value;},i.ondblclick=()=>{document.getElementById("ai-config-model").value=i.value,et.success("已选择模型");},s&&(s.value="",s.oninput=e=>{this.filterModels(e.target.value);},s.onkeydown=e=>{"Enter"===e.key&&i.options.length>0&&(i.selectedIndex=0,document.getElementById("ai-config-model").value=i.options[0].value,et.success("已选择: "+i.options[0].text));}),et.success(`已获取 ${n.length} 个模型`);}catch(i){et.error(`获取模型列表失败: ${i.message}`);}finally{o.disabled=false,o.textContent="获取模型";}}filterModels(e){if(!this.allModels)return;const t=document.getElementById("model-select");if(!t)return;const n=e.toLowerCase().trim();if(!n)return t.innerHTML="",void this.allModels.forEach(e=>{const n=document.createElement("option");n.value=e.id,n.textContent=`${e.name||e.id} (${e.context_length||"N/A"} tokens)`,n.title=e.id,t.appendChild(n);});const o=this.allModels.filter(e=>{const t=(e.id||"").toLowerCase(),o=(e.name||"").toLowerCase();return t.includes(n)||o.includes(n)});t.innerHTML="",o.forEach(e=>{const n=document.createElement("option");n.value=e.id,n.textContent=`${e.name||e.id} (${e.context_length||"N/A"} tokens)`,n.title=e.id,t.appendChild(n);});const i=document.getElementById("model-search-input");i&&(i.placeholder=o.length>0?`找到 ${o.length} 个模型`:"未找到匹配的模型");}addProgressBarMarkers(e){const t=e.querySelectorAll(".section-item[data-time]"),n=document.querySelector("video"),o=document.querySelector(".bpx-player-progress-wrap");if(!n||!o)return;const i=n.duration;if(!i)return;let s=o.querySelector(".ai-points-container");s||(s=document.createElement("div"),s.className="ai-points-container",o.appendChild(s)),s.innerHTML="",t.forEach(e=>{const t=e.getAttribute("data-time");if(!t)return;const o=t.match(/\[(\d{1,2}):(\d{2})\]/);if(!o)return;const r=60*parseInt(o[1])+parseInt(o[2]),a=r/i*100,l=document.createElement("span");l.className="bpx-player-progress-point bpx-player-progress-point-aipoint",l.style.cssText=`left: ${a}%;`,l.setAttribute("data-time",r),l.addEventListener("click",()=>{n.currentTime=r;}),s.appendChild(l);}),this._addProgressBarStyles();}removeProgressBarMarkers(){const e=document.querySelector(".ai-points-container");e&&e.remove();}_addProgressBarStyles(){if(document.querySelector("#ai-progress-styles"))return;const e=document.createElement("style");e.id="ai-progress-styles",e.textContent="\n .ai-points-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 5;\n }\n \n .bpx-player-progress-point-aipoint {\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 8px;\n height: 8px;\n background: #ff69b4;\n border: 2px solid rgba(255, 255, 255, 0.9);\n border-radius: 50%;\n opacity: 0.9;\n pointer-events: auto;\n cursor: pointer;\n transition: all 0.2s;\n box-shadow: 0 0 4px rgba(255, 105, 180, 0.6);\n }\n \n .bpx-player-progress-point-aipoint:hover {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1.5);\n box-shadow: 0 0 8px rgba(255, 105, 180, 0.9);\n }\n ",document.head.appendChild(e);}initSubtitleScroll(e){if(!e)return void we.warn("EventHandlers","字幕容器不存在,无法初始化滚动");const t=document.querySelector("#subtitle-follow-btn");Et.init(e,{followIntervalMs:200,userScrollDetectMs:300,scrollBehavior:"smooth",scrollPosition:"center",highlightClass:"current"}),Et.on("onFollowStatusChange",e=>{t&&(t.style.display=e?"none":"block"),we.debug("字幕滚动",`跟随状态改变: ${e}`);}),t&&t.addEventListener("click",()=>{we.debug("字幕滚动","点击恢复滚动"),Et.resumeAutoFollow();}),we.info("EventHandlers","字幕滚动管理器初始化完成");}bindNotionConfigModalEvents(e){e.addEventListener("click",t=>{t.target===e&&this.hideNotionConfigModal();}),document.getElementById("notion-save-btn").addEventListener("click",()=>{const e=document.getElementById("notion-api-key").value.trim(),t=document.getElementById("notion-parent-page-id").value.trim(),n=document.getElementById("notion-auto-send-enabled").checked,o=document.getElementById("notion-notes-auto-sync").checked,i={videoInfo:document.getElementById("notion-content-video-info").checked,summary:document.getElementById("notion-content-summary").checked,segments:document.getElementById("notion-content-segments").checked,subtitles:document.getElementById("notion-content-subtitles").checked};if(!e)return void It.showNotionStatus("请输入 API Key",true);if(!t)return void It.showNotionStatus("请输入目标位置(Page ID 或 Database ID)",true);const s=$e.saveNotionConfig({apiKey:e,parentPageId:t});s.success?($e.setNotionAutoSendEnabled(n),$e.setNotionNotesAutoSync(o),$e.saveNotionContentOptions(i),It.showNotionStatus("配置已保存"),setTimeout(()=>{this.hideNotionConfigModal();},1500)):It.showNotionStatus(s.error,true);}),document.getElementById("notion-cancel-btn").addEventListener("click",()=>{this.hideNotionConfigModal();});}restoreContainerState(e){const t=localStorage.getItem("subtitle-container-state");if(t)try{const n=JSON.parse(t);n.width&&(e.style.width=n.width),n.height&&(e.style.height=n.height),n.top&&(e.style.top=n.top),n.left&&(e.style.left=n.left);}catch(n){we.warn("EventHandlers","恢复容器状态失败:",n);}}parsePositionValue(e,t){return e?e.endsWith("px")?parseInt(e):e.endsWith("%")?parseInt(e)/100*t:parseInt(e)||0:0}resetContainerPosition(e){localStorage.removeItem("subtitle-container-state"),e.style.width="500px",e.style.height="600px",e.style.top="10%",e.style.left="100%",e.style.marginLeft="10px",et.success("字幕面板位置已重置");}saveContainerState(e){const t={width:e.style.width||e.offsetWidth+"px",height:e.style.height||e.offsetHeight+"px",top:e.style.top||"10%",left:e.style.left||"100%"};localStorage.setItem("subtitle-container-state",JSON.stringify(t));}bindDragEvents(e){const t=e.querySelector(".subtitle-header");if(!t)return;let n=false,o=0,i=0,s=0,r=0;const a=a=>{if(a.target.closest("button")||a.target.closest("input")||a.target.closest(".ai-icon")||a.target.closest(".notion-icon")||a.target.closest(".subtitle-close"))return;n=true,o=a.clientX,i=a.clientY;const l=e.getBoundingClientRect(),c=document.querySelector(".bpx-player-primary-area"),d=c?.getBoundingClientRect()||{left:0,top:0};s=l.left-d.left,r=l.top-d.top,t.style.cursor="grabbing",a.preventDefault();},l=t=>{if(!n)return;const a=t.clientX-o,l=t.clientY-i,c=s+a,d=r+l;e.style.left=c+"px",e.style.top=d+"px",e.style.marginLeft="0";},c=()=>{n&&(n=false,t.style.cursor="move",this.saveContainerState(e));};t.addEventListener("mousedown",a),document.addEventListener("mousemove",l),document.addEventListener("mouseup",c),e._dragCleanup=()=>{t.removeEventListener("mousedown",a),document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",c);};}bindResizeEvents(e){let t=false,n="",o=0,i=0,s=0,r=0,a=0,l=0;const c=(e,t)=>{const n=e.clientX-t.left,o=e.clientY-t.top,i=t.width,s=t.height;let r="";return o<8?r+="n":o>s-8&&(r+="s"),n<8?r+="w":n>i-8&&(r+="e"),r},d=n=>{if(t)return;const o=e.getBoundingClientRect(),i=c(n,o);e.className=e.className.replace(/\bresize-\w+\b/g,""),i&&e.classList.add(`resize-${i}`);},u=d=>{const u=e.getBoundingClientRect();n=c(d,u),n&&(d.target.closest(".subtitle-header")||(t=true,o=d.clientX,i=d.clientY,s=e.offsetWidth,r=e.offsetHeight,a=e.offsetLeft,l=e.offsetTop,d.preventDefault(),d.stopPropagation()));},p=c=>{if(!t)return;const d=c.clientX-o,u=c.clientY-i;let p=s,h=r,g=a,m=l;if(n.includes("e")&&(p=Math.max(400,Math.min(800,s+d))),n.includes("w")){const e=s-d;p=Math.max(400,Math.min(800,e)),g=a+(s-p);}if(n.includes("s")&&(h=Math.max(400,Math.min(.9*window.innerHeight,r+u))),n.includes("n")){const e=r-u;h=Math.max(400,Math.min(.9*window.innerHeight,e)),m=l+(r-h);}e.style.width=p+"px",e.style.height=h+"px",e.style.left=g+"px",e.style.top=m+"px";},h=()=>{t&&(t=false,n="",this.saveContainerState(e));};e.addEventListener("mousemove",d),e.addEventListener("mousedown",u),document.addEventListener("mousemove",p),document.addEventListener("mouseup",h),e._resizeCleanup=()=>{e.removeEventListener("mousemove",d),e.removeEventListener("mousedown",u),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",h);};}observeContainerResize(e){const t=new ResizeObserver(function(e,t){let n;return function(...o){clearTimeout(n),n=setTimeout(()=>{clearTimeout(n),e(...o);},t);}}(()=>{this.saveContainerState(e);},500));t.observe(e),e._resizeObserver=t;}};const $t=new class{constructor(){this.modal=null;}createModal(){return this.modal||(this.modal=document.createElement("div"),this.modal.id="help-modal",this.modal.className="config-modal",document.body.appendChild(this.modal)),this.modal}show(){const e=this.createModal();this.renderModal(),e.classList.add("show"),Tt.push(this);}hide(){this.modal&&this.modal.classList.remove("show"),Tt.pop(this);}renderModal(){this.modal.innerHTML='\n \n ',this.bindEvents();}bindEvents(){this.modal.addEventListener("click",e=>{e.target===this.modal&&this.hide();});const e=document.getElementById("help-close-btn");e&&e.addEventListener("click",()=>this.hide());}};const _t=new class{constructor(){this.modal=null;}createModal(){return this.modal||(this.modal=document.createElement("div"),this.modal.id="sponsorblock-modal",this.modal.className="config-modal",document.body.appendChild(this.modal)),this.modal}show(){const e=this.createModal();this.renderModal(),e.classList.add("show"),Tt.push(this);}hide(){this.modal&&this.modal.classList.remove("show"),Tt.pop(this);}renderModal(){const e=ht.getAll();this.modal.innerHTML=`\n \n `,this.bindEvents();}bindEvents(){this.modal.addEventListener("click",e=>{e.target===this.modal&&this.hide();});const e=document.getElementById("sponsorblock-save-btn");e&&e.addEventListener("click",()=>this.saveSettings());const t=document.getElementById("sponsorblock-cancel-btn");t&&t.addEventListener("click",()=>this.hide());}saveSettings(){const e={skipCategories:Array.from(this.modal.querySelectorAll('.sponsor-checkbox-item input[type="checkbox"]:checked')).map(e=>e.value),showAdBadge:this.modal.querySelector("#showAdBadge").checked,showQualityBadge:this.modal.querySelector("#showQualityBadge").checked,showProgressMarkers:this.modal.querySelector("#showProgressMarkers").checked};ht.setAll(e),this.hide(),et.info("设置已保存!\n\n✅ 勾选的类别 → 自动跳过\n⏸️ 未勾选的类别 → 手动提示(5秒)\n\n页面将刷新以应用新设置。"),setTimeout(()=>{location.reload();},2e3);}};const Pt=new class{constructor(){this.resources={eventBusSubscriptions:new Map,domListeners:new Map,mutationObservers:new Set,intervals:new Map,timeouts:new Set,rafIds:new Set,audioContexts:new Set,customCleanups:new Set},this.isDestroyed=false,this.maxIntervalDuration=3e5,this.startAutoCleanup();}trackEventBusSubscription(e,t,n="default"){this.resources.eventBusSubscriptions.has(n)||this.resources.eventBusSubscriptions.set(n,[]),this.resources.eventBusSubscriptions.get(n).push({event:e,unsubscribe:t});}trackDOMListener(e,t,n,o){const i=Symbol("listener");return this.resources.domListeners.set(i,{element:e,event:t,handler:n,options:o}),e.addEventListener(t,n,o),i}removeDOMListener(e){const t=this.resources.domListeners.get(e);t&&(t.element.removeEventListener(t.event,t.handler,t.options),this.resources.domListeners.delete(e));}trackMutationObserver(e){return this.resources.mutationObservers.add(e),e}trackInterval(e,t,n=this.maxIntervalDuration){const o=Date.now(),i=setInterval(()=>{if(Date.now()-o>n)return we.warn("ResourceManager",`定时器${i}运行超过${n}ms,自动清理`),void this.clearTrackedInterval(i);e();},t);return this.resources.intervals.set(i,{startTime:o,maxDuration:n,delay:t}),i}clearTrackedInterval(e){clearInterval(e),this.resources.intervals.delete(e);}trackTimeout(e,t){const n=setTimeout(()=>{e(),this.resources.timeouts.delete(n);},t);return this.resources.timeouts.add(n),n}clearTrackedTimeout(e){clearTimeout(e),this.resources.timeouts.delete(e);}trackRAF(e){const t=requestAnimationFrame(e);return this.resources.rafIds.add(t),t}cancelTrackedRAF(e){cancelAnimationFrame(e),this.resources.rafIds.delete(e);}trackAudioContext(e){return this.resources.audioContexts.add(e),e}addCleanup(e){this.resources.customCleanups.add(e);}startAutoCleanup(){this.autoCleanupInterval=setInterval(()=>{this.cleanupExpiredIntervals();},3e4);}cleanupExpiredIntervals(){const e=Date.now(),t=[];this.resources.intervals.forEach((n,o)=>{e-n.startTime>n.maxDuration&&(we.warn("ResourceManager",`清理超时interval: ${o}, 运行了${((e-n.startTime)/1e3).toFixed(1)}秒`),clearInterval(o),t.push(o));}),t.forEach(e=>this.resources.intervals.delete(e)),t.length>0&&we.debug("ResourceManager",`已清理${t.length}个超时定时器`);}getStats(){return {intervals:this.resources.intervals.size,timeouts:this.resources.timeouts.size,rafIds:this.resources.rafIds.size,audioContexts:this.resources.audioContexts.size,domListeners:this.resources.domListeners.size,mutationObservers:this.resources.mutationObservers.size,eventBusSubscriptions:Array.from(this.resources.eventBusSubscriptions.values()).reduce((e,t)=>e+t.length,0)}}cleanupModule(e){const t=this.resources.eventBusSubscriptions.get(e);t&&(t.forEach(({unsubscribe:t})=>{try{t();}catch(n){console.error(`[ResourceManager] 清理模块 "${e}" 订阅失败:`,n);}}),this.resources.eventBusSubscriptions.delete(e));}cleanup(){this.isDestroyed?we.warn("ResourceManager","已经销毁,跳过清理"):(we.debug("ResourceManager","开始清理资源..."),this.resources.eventBusSubscriptions.forEach((e,t)=>{e.forEach(({event:e,unsubscribe:n})=>{try{n();}catch(o){console.error(`[ResourceManager] 清理 EventBus 订阅失败 (${t}.${e}):`,o);}});}),this.resources.eventBusSubscriptions.clear(),this.resources.domListeners.forEach(({element:e,event:t,handler:n,options:o})=>{try{e.removeEventListener(t,n,o);}catch(i){console.error("[ResourceManager] 清理 DOM 监听器失败:",i);}}),this.resources.domListeners.clear(),this.resources.mutationObservers.forEach(e=>{try{e.disconnect();}catch(t){console.error("[ResourceManager] 清理 MutationObserver 失败:",t);}}),this.resources.mutationObservers.clear(),this.resources.intervals.forEach((e,t)=>{try{clearInterval(t);}catch(n){console.error("[ResourceManager] 清理 interval 失败:",n);}}),this.resources.intervals.clear(),this.autoCleanupInterval&&(clearInterval(this.autoCleanupInterval),this.autoCleanupInterval=null),this.resources.timeouts.forEach(e=>{try{clearTimeout(e);}catch(t){console.error("[ResourceManager] 清理 timeout 失败:",t);}}),this.resources.timeouts.clear(),this.resources.rafIds.forEach(e=>{try{cancelAnimationFrame(e);}catch(t){console.error("[ResourceManager] 清理 RAF 失败:",t);}}),this.resources.rafIds.clear(),this.resources.audioContexts.forEach(e=>{try{"closed"!==e.state&&e.close();}catch(t){console.error("[ResourceManager] 关闭 AudioContext 失败:",t);}}),this.resources.audioContexts.clear(),this.resources.customCleanups.forEach(e=>{try{e();}catch(t){console.error("[ResourceManager] 执行自定义清理失败:",t);}}),this.resources.customCleanups.clear(),this.isDestroyed=true,we.debug("ResourceManager","资源清理完成"));}getStats(){return {eventBusSubscriptions:Array.from(this.resources.eventBusSubscriptions.entries()).reduce((e,[t,n])=>(e[t]=n.length,e),{}),domListeners:this.resources.domListeners.size,mutationObservers:this.resources.mutationObservers.size,intervals:this.resources.intervals.size,timeouts:this.resources.timeouts.size,rafIds:this.resources.rafIds.size,audioContexts:this.resources.audioContexts.size,customCleanups:this.resources.customCleanups.size}}},Nt=location.hostname.endsWith("bilibili.com"),Mt=location.hostname.includes("youtube.com")||location.hostname.includes("youtu.be");class Lt{constructor(){this.initialized=false,this.initializing=false,this.ball=null,this.container=null,this.videoQualityService=null,this.universalAdSkipService=null,this.isBilibili=Nt,this.isYouTube=Mt,this.isPlatformSupported=false;}setupErrorHandler(){const e=window.onerror;window.onerror=(t,n,o,i,s)=>{const r=String(t||""),a=String(n||"");return a&&(a.includes("extension://")||a.includes("content.js"))?(we.debug("Main","忽略来自其他扩展的错误:",r),true):a.includes("nc-loader")||r.includes("addIceCandidate")?(we.debug("Main","忽略第三方组件错误"),true):r.includes("Extension context invalidated")?(we.debug("Main","忽略扩展上下文失效错误"),true):!!e&&e(t,n,o,i,s)},window.addEventListener("unhandledrejection",e=>{const t=e.reason,n=t?String(t.message||t):"";return n.includes("Extension context invalidated")?(e.preventDefault(),void we.debug("Main","忽略Promise中的扩展上下文失效错误")):n.includes("addIceCandidate")||n.includes("nc-loader")?(e.preventDefault(),void we.debug("Main","忽略Promise中的第三方组件错误")):void 0}),we.info("Main","全局错误处理器已设置");}async init(){if(this.initialized)we.info("Main","应用已初始化,跳过重复执行");else if(this.initializing)we.warn("Main","应用正在初始化中,跳过重复调用");else {this.initializing=true;try{if(this.setupErrorHandler(),this.isPlatformSupported=this.isBilibili||this.isYouTube,we.info("Main","平台检测: "+(this.isBilibili?"Bilibili":this.isYouTube?"YouTube":"通用模式")),we.info("Main","初始化通用服务(速度控制、笔记、截图)..."),function(){const e=document.createElement("style");e.textContent=pe,document.head.appendChild(e);}(),ot.init(),ut.init(),this.registerUniversalShortcuts(),this.registerUniversalMenuCommands(),this.isPlatformSupported){if(we.info("Main",`初始化平台专属服务: ${this.isBilibili?"Bilibili":"YouTube"}...`),Xe.init(),await this.waitForPageReady(),this.isBilibili&&$e.fixExistingConfigPrompts(),await this.initPlatformServices(),(this.isBilibili||this.isYouTube&&"/watch"===location.pathname)&&this.createUI(),this.bindEvents(),(this.isBilibili||this.isYouTube&&"/watch"===location.pathname)&&this.setupAutomation(),this.registerPlatformMenuCommands(),this.isBilibili)Ye.checkSubtitleButton(),this.observeVideoChange();else if(this.isYouTube&&"/watch"===location.pathname){const e=Xe.getSubtitleService();e&&setTimeout(async()=>{await e.checkSubtitleAvailability();},2e3),this.observeVideoChange();}}else we.info("Main","通用模式:仅提供速度控制、笔记、截图功能");this.initialized=!0,we.info("Main","✅ 应用初始化完成");}catch(e){we.error("Main","初始化失败:",e);}finally{this.initializing=false;}}}async initPlatformServices(){if(this.isBilibili)try{await bt.init(),this.videoQualityService=(e=bt.getAPI(),xt||(xt=new vt(e)),xt),this.videoQualityService.start();}catch(t){we.warn("Main","SponsorBlock初始化失败:",t.message);}var e;if(this.isBilibili||this.isYouTube)try{const e=this.createAdSkipConfig();this.universalAdSkipService=new St(e),await this.universalAdSkipService.init(),we.info("Main","通用广告跳过服务已初始化");}catch(t){we.warn("Main","通用广告跳过服务初始化失败:",t.message);}if(this.isYouTube)try{await kt.init(),we.info("Main","YouTube视频标签服务已初始化");}catch(t){we.warn("Main","YouTube视频标签服务初始化失败:",t.message);}}createAdSkipConfig(){const e=this.isYouTube?"youtube":"bilibili";return {get:t=>({autoSkip:"false"!==localStorage.getItem(`${e}_auto_skip`),skipCategories:JSON.parse(localStorage.getItem(`${e}_skip_categories`)||'["sponsor", "selfpromo"]'),showNotifications:"false"!==localStorage.getItem(`${e}_show_notifications`),showProgressMarkers:"false"!==localStorage.getItem(`${e}_show_markers`),detectNativeAds:"false"!==localStorage.getItem(`${e}_detect_native`),skipDelay:parseInt(localStorage.getItem(`${e}_skip_delay`)||"0"),muteInsteadOfSkip:"true"===localStorage.getItem(`${e}_mute_instead`)}[t]),set:(t,n)=>{localStorage.setItem(`${e}_${t}`,JSON.stringify(n));}}}registerUniversalShortcuts(){Me.register("toggleNotesPanel",()=>{Ct.togglePanel();}),Me.register("takeScreenshot",async()=>{try{await yt.captureAndSave(!1);}catch(e){console.error("[Main] 截图失败:",e),et.error("截图失败: "+e.message);}}),Me.register("speedIncrease",()=>{ut.adjustBaseSpeed(.1);}),Me.register("speedDecrease",()=>{ut.adjustBaseSpeed(-0.1);}),Me.register("speedReset",()=>{ut.resetToNormalSpeed();}),Me.register("speedDouble",()=>{ut.setToDoubleSpeed();}),this.isPlatformSupported&&Me.register("toggleSubtitlePanel",()=>{Ae.togglePanel();}),Me.startListening();}registerUniversalMenuCommands(){"undefined"!=typeof GM_registerMenuCommand&&(GM_registerMenuCommand("📝 笔记管理",()=>{Ct.togglePanel();}),GM_registerMenuCommand("⌨️ 快捷键设置",()=>{if(!At||!At.showShortcutConfigModal)return console.error("[Main] eventHandlers 或其方法未正确加载"),void et.error("快捷键设置功能未正确加载");At.showShortcutConfigModal();}),GM_registerMenuCommand("❓ 使用帮助",()=>{$t.show();}),GM_registerMenuCommand(`🔧 调试模式 (${we.isDebugMode()?"开启":"关闭"})`,()=>{const e=we.toggleDebugMode();et.info("调试模式已"+(e?"开启":"关闭")),e&&et.info("调试模式已开启,控制台将输出详细日志");}));}registerPlatformMenuCommands(){"undefined"!=typeof GM_registerMenuCommand&&(this.isBilibili&&(GM_registerMenuCommand("🤖 AI配置",()=>{At.showAIConfigModal();}),GM_registerMenuCommand("📤 Notion配置",()=>{At.showNotionConfigModal();}),GM_registerMenuCommand("🔄 重置字幕面板位置",()=>{const e=document.getElementById("subtitle-container");e?At.resetContainerPosition(e):et.warning("字幕面板未初始化,请先加载视频");}),GM_registerMenuCommand("⚡ SponsorBlock设置",()=>{_t.show();})),this.isYouTube&&GM_registerMenuCommand("🚫 YouTube广告设置",()=>{this.showYouTubeAdSettings();}));}async waitForPageReady(){return this.isBilibili?new Promise(t=>{const n=setInterval(()=>{document.querySelector(ae)&&(clearInterval(n),t());},e);}):new Promise(e=>{"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>e(),{once:true}):e();})}createUI(){let e;if(this.ball=document.createElement("div"),this.ball.id="subtitle-ball",this.ball.title="字幕提取器",this.isBilibili)e=document.querySelector(ae),e&&("relative"!==e.style.position&&"absolute"!==e.style.position&&(e.style.position="relative"),e.appendChild(this.ball));else if(this.isYouTube&&(e=document.querySelector("#movie_player")||document.querySelector(".html5-video-player"),e)){this.ball.style.right="10px",this.ball.style.top="10px",this.ball.style.transform="none",this.ball.style.zIndex="9999",e.appendChild(this.ball);const t=()=>{document.fullscreenElement||document.webkitFullscreenElement?this.ball.style.top="60px":this.ball.style.top="10px";};document.addEventListener("fullscreenchange",t),document.addEventListener("webkitfullscreenchange",t);}this.ball&&this.ball.addEventListener("click",()=>{if(this.ball.classList.contains("active")||this.ball.classList.contains("ai-summarizing"))this.container&&(this.container.classList.toggle("show"),xe.emit(M,this.container.classList.contains("show")));else if(this.ball.classList.contains("loading"))we.debug("App","字幕正在加载中...");else {Xe.getSubtitleService()&&(this.isYouTube?Je.manualFetchSubtitle().catch(e=>{we.error("App","YouTube字幕获取失败:",e),et.error("获取字幕失败: "+e.message);}):this.isBilibili&&Ye.toggleSubtitle());}}),this.createEmbeddedContainer();const t=It.createNotionConfigModal();document.body.appendChild(t),At.bindNotionConfigModalEvents(t);const n=It.createAIConfigModal();document.body.appendChild(n),At.bindAIConfigModalEvents(n);}createEmbeddedContainer(){let e;this.container=document.createElement("div"),this.container.id="subtitle-container",this.isBilibili?(e=document.querySelector(ae),e&&("relative"!==e.style.position&&"absolute"!==e.style.position&&(e.style.position="relative"),e.appendChild(this.container))):this.isYouTube?setTimeout(()=>{if(e=document.querySelector("#secondary-inner")||document.querySelector("#secondary")||document.querySelector("#related")||document.querySelector("#columns"),e){const t=e.firstElementChild;t?e.insertBefore(this.container,t):e.appendChild(this.container),this.container.style.position="relative",this.container.style.left="auto",this.container.style.top="auto",this.container.style.marginBottom="16px",this.container.style.width="100%",this.container.style.maxWidth="400px",this.container.style.height="500px",this.container.classList.add("show");}else document.body.appendChild(this.container);},1e3):document.body.appendChild(this.container);}bindEvents(){xe.on(B,e=>{if(we.info("App","监听到视频切换事件:",e),this.ball&&(this.ball.classList.remove("has-data","ai-loading"),this.updateBallStatus(f)),this.container){const e=this.container.querySelector("#subtitle-list-container");e&&(e.innerHTML='字幕列表等待加载字幕...');const t=this.container.querySelector("#summary-panel");t&&(t.innerHTML='等待字幕加载完成后生成AI总结...');}setTimeout(()=>{we.debug("App","开始重新获取字幕..."),Ye.checkSubtitleButton();},2e3);}),xe.on(k,(e,t)=>{this.renderSubtitles(e);}),xe.on(C,()=>{we.debug("App","AI总结开始,小球进入AI总结状态"),Ae.setBallStatus(S);const e=this.container?.querySelector(".ai-icon");e&&e.classList.add("loading");}),xe.on($,e=>{this.container&&It.updateAISummary(this.container,e);}),xe.on(E,(e,t)=>{we.debug("App","AI总结完成,恢复小球正常状态"),et.success("AI总结完成"),this.container&&It.updateAISummary(this.container,e),Ae.setBallStatus(v);const n=this.container?.querySelector(".ai-icon");n&&n.classList.remove("loading");}),xe.on(P,()=>{et.success("字幕已成功发送到 Notion");const e=this.container?.querySelector(".notion-icon");e&&e.classList.remove("loading");}),xe.on(I,e=>{et.handleError(e,"字幕获取");}),xe.on(A,e=>{we.debug("App","AI总结失败,恢复小球正常状态"),et.handleError(e,"AI总结"),Ae.setBallStatus(v);const t=this.container?.querySelector(".ai-icon");t&&t.classList.remove("loading");}),xe.on(N,e=>{et.handleError(e,"Notion发送");}),xe.on(L,e=>{this.updateBallStatus(e);}),xe.on(M,e=>{this.container&&(e?this.container.classList.add("show"):this.container.classList.remove("show"));});}renderSubtitles(e){if(!this.container||!e)return;this.container.innerHTML=It.renderSubtitlePanel(e);const t=Ae.getVideoKey(),n=t?Ae.getAISummary(t):null;n&&It.updateAISummary(this.container,n),At.bindSubtitlePanelEvents(this.container),we.debug("App","字幕面板已渲染");}setupAutomation(){xe.on(k,async e=>{await Fe(a);const t=$e.getAIAutoSummaryEnabled(),n=$e.getNotionAutoSendEnabled(),o=$e.getSelectedAIConfig(),i=$e.getNotionConfig(),s=Ae.getVideoKey(),r=s?Ae.getAISummary(s):null;if(t&&o&&o.apiKey&&!r)try{await it.summarize(e,!1);}catch(l){console.error("[App] 自动总结失败:",l);}else if(n&&i.apiKey)try{const t=$e.getNotionContentOptions(),n=Ae.getVideoInfo();await tt.sendToNotion({videoInfo:n,aiSummary:r,subtitleData:t.subtitles?e:null,isAuto:!0}),t.subtitles&&e&&we.debug("App","字幕已自动发送到Notion");}catch(l){console.error("[App] 自动发送到Notion失败:",l);}}),xe.on(E,async e=>{we.debug("App","AI总结完成,已由AIService处理Notion发送");});}updateBallStatus(e){if(this.ball)switch(this.ball.classList.remove("loading","active","no-subtitle","error","ai-summarizing"),e){case v:this.ball.classList.add("active"),this.ball.style.cursor="pointer",this.ball.title="字幕提取器 - 点击查看字幕";break;case x:this.ball.classList.add("no-subtitle"),this.ball.style.cursor="default",this.ball.title="该视频无字幕";break;case w:this.ball.classList.add("error"),this.ball.style.cursor="default",this.ball.title="字幕加载失败";break;case y:this.ball.classList.add("loading"),this.ball.style.cursor="default",this.ball.title="正在加载字幕...";break;case S:this.ball.classList.add("ai-summarizing"),this.ball.style.cursor="default",this.ball.title="正在AI总结...";}}observeVideoChange(){let e=location.href,t=location.href.match(/BV[1-9A-Za-z]{10}/)?.[0],n=null,o=parseInt(new URLSearchParams(window.location.search).get("p")||"1");const i=()=>{try{const e=unsafeWindow.__INITIAL_STATE__;return e?.videoData?.cid||e?.videoData?.pages?.[0]?.cid}catch(e){return null}};n=i();const s=()=>{const s=location.href,a=s.match(/BV[1-9A-Za-z]{10}/)?.[0],l=i(),c=new URLSearchParams(window.location.search),d=parseInt(c.get("p")||"1");s===e||a===t&&l===n&&d===o||(we.debug("App","检测到视频切换:",{from:`${t}_p${o}`,to:`${a}_p${d}`,oldCid:n,newCid:l}),e=s,t=a,n=l,o=d,Ae.reset(),Ye.reset(),xe.emit(B,{bvid:a,cid:l,p:d,oldP:o}),setTimeout(()=>{const e=Oe();Ae.setVideoInfo(e),Ye.checkSubtitleButton();},r));},a=history.pushState,l=history.replaceState;history.pushState=function(...e){a.apply(this,e),s();},history.replaceState=function(...e){l.apply(this,e),s();},window.addEventListener("popstate",s);const c=setInterval(s,1e3);this.urlChangeCleanup=()=>{history.pushState=a,history.replaceState=l,window.removeEventListener("popstate",s),clearInterval(c);},we.debug("App","视频切换监听已启动(使用 History API 劫持)");}showYouTubeAdSettings(){const e=document.createElement("div");if(e.className="youtube-ad-settings-modal",e.innerHTML=`\n \n \n `,!document.querySelector("#youtube-ad-settings-styles")){const e=document.createElement("style");e.id="youtube-ad-settings-styles",e.textContent='\n .youtube-ad-settings-modal {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999999;\n }\n .settings-modal-overlay {\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n }\n .settings-modal-content {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: white;\n border-radius: 8px;\n width: 500px;\n max-height: 80vh;\n overflow-y: auto;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n }\n .settings-modal-header {\n padding: 20px;\n border-bottom: 1px solid #e0e0e0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .settings-modal-header h3 {\n margin: 0;\n font-size: 18px;\n }\n .settings-close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n padding: 0;\n width: 30px;\n height: 30px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .settings-modal-body {\n padding: 20px;\n }\n .setting-item {\n margin-bottom: 15px;\n }\n .setting-item label {\n display: block;\n cursor: pointer;\n user-select: none;\n }\n .setting-item input[type="checkbox"] {\n margin-right: 8px;\n }\n .setting-item input[type="number"] {\n width: 60px;\n padding: 4px;\n border: 1px solid #ddd;\n border-radius: 4px;\n }\n .category-checkboxes {\n margin-top: 10px;\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 8px;\n }\n .category-checkboxes label {\n display: flex;\n align-items: center;\n }\n .settings-modal-footer {\n padding: 15px 20px;\n border-top: 1px solid #e0e0e0;\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n }\n .settings-modal-footer button {\n padding: 8px 16px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n }\n .settings-save-btn {\n background: #ff0000;\n color: white;\n border: none;\n }\n .settings-save-btn:hover {\n background: #cc0000;\n }\n .settings-cancel-btn {\n background: #f0f0f0;\n border: 1px solid #ddd;\n color: #333;\n }\n .settings-cancel-btn:hover {\n background: #e0e0e0;\n }\n ',document.head.appendChild(e);}document.body.appendChild(e);const t=JSON.parse(localStorage.getItem("youtube_skip_categories")||'["sponsor", "selfpromo"]');e.querySelectorAll(".skip-category").forEach(e=>{e.checked=t.includes(e.value);});const n=()=>e.remove();e.querySelector(".settings-modal-overlay").addEventListener("click",n),e.querySelector(".settings-close-btn").addEventListener("click",n),e.querySelector(".settings-cancel-btn").addEventListener("click",n),e.querySelector(".settings-save-btn").addEventListener("click",()=>{localStorage.setItem("youtube_auto_skip",e.querySelector("#youtube-auto-skip").checked),localStorage.setItem("youtube_detect_native",e.querySelector("#youtube-native-detect").checked),localStorage.setItem("youtube_show_notifications",e.querySelector("#youtube-show-notifications").checked),localStorage.setItem("youtube_show_markers",e.querySelector("#youtube-show-markers").checked),localStorage.setItem("youtube_mute_instead",e.querySelector("#youtube-mute-instead").checked),localStorage.setItem("youtube_skip_delay",e.querySelector("#youtube-skip-delay").value);const t=[];e.querySelectorAll(".skip-category:checked").forEach(e=>{t.push(e.value);}),localStorage.setItem("youtube_skip_categories",JSON.stringify(t)),this.universalAdSkipService&&this.universalAdSkipService.updateConfig({autoSkip:e.querySelector("#youtube-auto-skip").checked,detectNativeAds:e.querySelector("#youtube-native-detect").checked,showNotifications:e.querySelector("#youtube-show-notifications").checked,showProgressMarkers:e.querySelector("#youtube-show-markers").checked,muteInsteadOfSkip:e.querySelector("#youtube-mute-instead").checked,skipDelay:parseInt(e.querySelector("#youtube-skip-delay").value),skipCategories:t}),et.success("设置已保存"),n();});}cleanup(){we.debug("App","开始清理应用资源"),this.urlChangeCleanup&&this.urlChangeCleanup(),this.videoQualityService&&this.videoQualityService.stop(),bt.playerController&&bt.playerController.destroy(),ut.destroy(),searchIndex.clear(),ze.destroy(),Pt.cleanup(),we.debug("App","应用资源清理完成");}}!function(){if(window!==window.top)return void console.log("[BilibiliTools] 检测到iframe环境,跳过初始化");console.log("[BilibiliTools] 环境检查:",{isTopWindow:window===window.top,url:location.href,hostname:location.hostname,pathname:location.pathname});const e="undefined"!=typeof unsafeWindow?unsafeWindow:window,t="__BILIBILI_YOUTUBE_TOOLS_V1_2_20_INITIALIZED__",n="__BILIBILI_YOUTUBE_TOOLS_INSTANCES__";if(e[n]||(e[n]=0),e[t]){const t=e[n];return void console.warn(`[BilibiliTools] 脚本已初始化(实例 #${t}),跳过重复执行 #${e[n]+1}`)}e[t]=true,e[n]++;const o=e[n];console.log(`[BilibiliTools] 初始化脚本实例 #${o}`);const i=new Lt;i.instanceId=o;let s=false;const r=()=>{s?console.log(`[BilibiliTools] 实例 #${o} - 已经开始初始化,跳过重复调用`):(s=true,console.log(`[BilibiliTools] 实例 #${o} - 开始初始化`),i.init());};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",r,{once:true}):r(),e.__BILIBILI_TOOLS_APP__=i;}();
})();