// ==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();
})();