// ==UserScript== // @name YouTube字幕自动中文 // @namespace http://tampermonkey.net/ // @version 2.1 // @description 自动开启YouTube字幕并切换至中文(简体)| 更多实用脚本👉关注公众号:【极客脚本库】 // @author 大角牛软件/u2222223(极客脚本库) // @match https://www.youtube.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_addStyle // @license MIT // ==/UserScript== (function () { 'use strict'; const CONFIG = { targetLang: ['中文(简体)', '中文', 'Chinese (Simplified)', 'Chinese'], autoTranslate: ['自动翻译', 'Auto-translate'], subtitles: ['字幕', 'Subtitles/CC'], retryInterval: 500, maxRetries: 10 }; const LOGGER = { info: (msg) => console.log(`✅ [YouTube字幕自动中文] ${msg}`), promo: () => console.log('📌 更多黑科技脚本 & 加入交流群 → 公众号:极客脚本库(回复“交流群”)') }; // --- Trusted Types Policy (for YouTube CSP) --- let policy; if (window.trustedTypes && window.trustedTypes.createPolicy) { try { policy = window.trustedTypes.createPolicy('geek_script_policy', { createHTML: (string) => string }); } catch (e) { console.warn('[YouTube字幕自动中文] 无法创建 Trusted Types 策略:', e); } } const getTrustedHTML = (html) => { if (policy) return policy.createHTML(html); return html; }; // --- UI & Modal Logic (Extracted for Global Access) --- function showContactModal(isFirstRun = false) { // 移除旧弹窗 const oldModal = document.getElementById('geek-modal'); if (oldModal) oldModal.remove(); // 注入样式 GM_addStyle(` #geek-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 999999; display: flex; justify-content: center; align-items: center; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } .geek-modal-content { background: #fff; padding: 25px; border-radius: 12px; width: 380px; max-width: 90vw; box-shadow: 0 4px 20px rgba(0,0,0,0.2); text-align: center; position: relative; animation: geek-fadein 0.3s ease-out; } .geek-modal-title { font-size: 20px; font-weight: bold; color: #333; margin-bottom: 10px; } .geek-modal-subtitle { font-size: 14px; color: #666; margin-bottom: 15px; } .geek-modal-tip-box { background: #fff8e1; border: 1px solid #ffe0b2; border-radius: 8px; padding: 12px; margin: 15px 0; text-align: left; } .geek-modal-text { font-size: 14px; line-height: 1.6; color: #333; margin-bottom: 5px; } .geek-highlight { color: #e67e22; font-weight: bold; } .geek-footer-tip { font-size: 12px; color: #999; margin-top: 10px; padding-top: 8px; border-top: 1px dashed #ffe0b2; } .geek-qr-container { margin: 15px 0; position: relative; min-height: 150px; } .geek-qr-img { width: 200px; height: 200px; border-radius: 8px; } .geek-error-box { display: none; border: 1px solid #ffcdd2; background: #ffebee; color: #c62828; padding: 10px; border-radius: 8px; font-size: 13px; } .geek-btn { display: block; width: 100%; padding: 10px 0; margin-top: 15px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s; } .geek-btn-primary { background: #2196f3; color: white; } .geek-btn-primary:hover { background: #1976d2; } .geek-btn-secondary { background: transparent; color: #999; } .geek-btn-secondary:hover { color: #666; } @keyframes geek-fadein { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } } `); // 构建HTML const modal = document.createElement('div'); modal.id = 'geek-modal'; let title = isFirstRun ? '🚀 脚本运行成功' : '加入油猴爱好者群 / 反馈BUG'; let subtitle = isFirstRun ? '
本弹窗仅首次显示,后续不再打扰
' : ''; let tipBoxContent = ''; if (isFirstRun) { tipBoxContent = `
🔥 关注公众号【极客脚本库】
回复 “交流群” 加入油猴爱好者群 & 获取更多脚本
`; } else { tipBoxContent = `
关注公众号【极客脚本库】
回复 “交流群” 获取群号 & 反馈BUG
`; } const btnClass = isFirstRun ? 'geek-btn-secondary' : 'geek-btn-primary'; const btnText = isFirstRun ? '我知道了' : '关闭'; modal.innerHTML = getTrustedHTML(`
${title}
${subtitle}
公众号二维码
⚠️ 图片加载失败(可能被当前网站安全策略拦截),请手动搜索关注公众号:极客脚本库,回复“交流群”即可
${tipBoxContent}
`); document.body.appendChild(modal); // 事件绑定 const closeBtn = modal.querySelector('#geek-close-btn'); closeBtn.onclick = () => modal.remove(); modal.onclick = (e) => { if (e.target === modal) modal.remove(); }; // 图片错误处理 const img = modal.querySelector('.geek-qr-img'); const errBox = modal.querySelector('.geek-error-box'); img.onerror = () => { img.style.display = 'none'; errBox.style.display = 'block'; }; } class SubtitleManager { constructor() { this.videoElement = null; this.observer = null; // 将初始化逻辑包裹在 try-catch 中,确保即使出错也不影响菜单注册(虽然现在菜单注册已经移出去了) try { this.init(); } catch (e) { console.error('[YouTube字幕自动中文] 初始化失败:', e); } } init() { LOGGER.info('已运行'); LOGGER.promo(); // this.setupMenu(); // 菜单注册已移至外部 this.checkFirstRun(); this.startPageObserver(); } startPageObserver() { // 使用 MutationObserver 监听页面导航(YouTube是SPA) const bodyObserver = new MutationObserver(() => { if (window.location.href.includes('watch')) { this.detectVideoPlayer(); } }); bodyObserver.observe(document.body, { childList: true, subtree: true }); if (window.location.href.includes('watch')) { this.detectVideoPlayer(); } } detectVideoPlayer() { const video = document.querySelector('video'); if (video && video !== this.videoElement) { this.videoElement = video; this.bindVideoEvents(); } } bindVideoEvents() { if (!this.videoElement) return; // 视频加载数据后尝试操作 this.videoElement.addEventListener('loadeddata', () => { setTimeout(() => this.executeTranslationFlow(), 1000); }); // 尝试跳过广告 this.videoElement.addEventListener('canplay', () => { const skipBtn = document.querySelector('.ytp-ad-skip-button-icon') || document.querySelector('.ytp-ad-skip-button') || document.querySelector('.ytp-skip-ad-button'); if (skipBtn) skipBtn.click(); }); } async executeTranslationFlow() { // 开启字幕 const ccBtn = document.querySelector('.ytp-subtitles-button[aria-pressed="false"]'); if (ccBtn) ccBtn.click(); // 进入设置菜单 const settingsBtn = document.querySelector('.ytp-settings-button'); if (!settingsBtn) return; settingsBtn.click(); await this.sleep(200); // 查找字幕菜单 const menuItems = document.querySelectorAll('.ytp-menuitem'); const subMenu = Array.from(menuItems).find(item => CONFIG.subtitles.some(key => item.innerText.includes(key)) ); if (!subMenu) { settingsBtn.click(); // 关闭菜单 return; } subMenu.click(); await this.sleep(200); // 尝试直接选择中文 const langItems = document.querySelectorAll('.ytp-menuitem'); const targetLangItem = Array.from(langItems).find(item => CONFIG.targetLang.some(key => item.innerText.includes(key)) ); if (targetLangItem) { targetLangItem.click(); // 点击视频区域关闭菜单(模拟用户行为) document.querySelector('#movie_player')?.click(); } else { // 尝试自动翻译 const autoTransItem = Array.from(langItems).find(item => CONFIG.autoTranslate.some(key => item.innerText.includes(key)) ); if (autoTransItem) { autoTransItem.click(); await this.sleep(200); // 在自动翻译列表中找中文 const autoLangItems = document.querySelectorAll('.ytp-menuitem'); const autoTargetItem = Array.from(autoLangItems).find(item => CONFIG.targetLang.some(key => item.innerText.includes(key)) ); if (autoTargetItem) { autoTargetItem.click(); } } } // 确保菜单关闭 if (document.querySelector('.ytp-popup-settings')) { settingsBtn.click(); } } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } checkFirstRun() { const hasRun = GM_getValue('has_run_v1', false); if (!hasRun) { setTimeout(() => { showContactModal(true); GM_setValue('has_run_v1', true); }, 2000); } } } // --- Main Execution --- // 1. 立即注册菜单,确保按钮存在 try { if (typeof GM_registerMenuCommand !== 'undefined') { GM_registerMenuCommand("💬 反馈BUG & 加入油猴爱好者群", () => showContactModal(false)); } else { console.warn('[YouTube字幕自动中文] GM_registerMenuCommand 未定义,菜单可能无法显示'); } } catch (e) { console.error('[YouTube字幕自动中文] 菜单注册失败:', e); } // 2. 启动逻辑 new SubtitleManager(); })();