自动展开 YouTube 视频页面的所有评论和回复
当前为
// ==UserScript==
// @name YouTube Auto Expand Comments and Replies
// @name:zh-CN YouTube 自动展开评论和回复
// @name:zh-TW YouTube 自動展開評論和回覆
// @name:ja YouTube コメントと返信を自動展開
// @name:ko YouTube 댓글 및 답글 자동 확장
// @name:es Expansión automática de comentarios y respuestas de YouTube
// @name:fr Expansion automatique des commentaires et réponses YouTube
// @name:de Automatische Erweiterung von YouTube-Kommentaren und Antworten
// @namespace https://github.com/SuperNG6/YouTube-Comment-Script
// @author SuperNG6
// @version 1.3
// @description Automatically expand all comments and replies on YouTube video pages
// @license MIT
// @description:zh-CN 自动展开 YouTube 视频页面的所有评论和回复
// @description:zh-TW 自動展開 YouTube 視頻頁面的所有評論和回覆
// @description:ja YouTube動画ページのすべてのコメントと返信を自動的に展開します
// @description:ko YouTube 동영상 페이지의 모든 댓글과 답글을 자동으로 확장합니다
// @description:es Expande automáticamente todos los comentarios y respuestas en las páginas de videos de YouTube
// @description:fr Développe automatiquement tous les commentaires et réponses sur les pages vidéo YouTube
// @description:de Erweitert automatisch alle Kommentare und Antworten auf YouTube-Videoseiten
// @match https://www.youtube.com/watch?v=*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 配置参数
const config = {
checkInterval: 500, // 常规检查间隔
observerTimeout: 3000, // 观察器超时时间
maxRetries: 10, // 最大重试次数
debug: false // 调试模式
};
let retryCount = 0;
let observer = null;
function log(...args) {
if (config.debug) console.log('[YouTube Auto Expand]', ...args);
}
// 更可靠的选择器
const selectors = {
commentsContainer: 'ytd-comments#comments',
commentReplies: 'ytd-comment-replies-renderer',
viewMoreComments: 'ytd-continuation-item-renderer #button', // 主评论的"查看更多"按钮
showRepliesButton: '#more-replies > yt-button-shape > button', // 回复按钮
showHiddenReplies: 'ytd-comment-replies-renderer yt-button-shape' // 隐藏的回复按钮
};
function clickVisibleElements(selector) {
const elements = [...document.querySelectorAll(selector)];
return elements.filter(el => {
if (el.offsetParent !== null && !el.disabled) {
try {
el.scrollIntoView({behavior: "auto", block: "center"});
el.click();
log('Clicked:', selector);
return true;
} catch (error) {
log('Click error:', error);
}
}
return false;
}).length > 0;
}
function expandElements() {
let clickedSomething = false;
// 处理主评论的"查看更多评论"按钮
clickedSomething |= clickVisibleElements(selectors.viewMoreComments);
// 处理回复按钮
clickedSomething |= clickVisibleElements(selectors.showRepliesButton);
// 处理可能存在的隐藏回复
clickedSomething |= clickVisibleElements(selectors.showHiddenReplies);
return clickedSomething;
}
function startObservation() {
const commentsContainer = document.querySelector(selectors.commentsContainer);
if (!commentsContainer) {
if (retryCount++ < config.maxRetries) {
setTimeout(startObservation, config.checkInterval);
log(`Retrying to find comments container (${retryCount}/${config.maxRetries})`);
}
return;
}
observer = new MutationObserver((mutations) => {
if (expandElements()) {
// 如果检测到变化并执行了点击,稍后再检查
setTimeout(() => expandElements(), config.checkInterval);
}
});
observer.observe(commentsContainer, {
childList: true,
subtree: true,
attributes: false,
characterData: false
});
// 初始执行
setTimeout(() => {
expandElements();
// 处理无限滚动加载
window.addEventListener('scroll', () => expandElements());
}, 500);
log('Observation started');
}
function init() {
if (!document.querySelector(selectors.commentsContainer)) {
// 如果评论区还没加载,等待直到加载完成
const waitForComments = setInterval(() => {
if (document.querySelector(selectors.commentsContainer)) {
clearInterval(waitForComments);
startObservation();
}
}, config.checkInterval);
// 设置超时停止检测
setTimeout(() => {
clearInterval(waitForComments);
log('Comments container not found within timeout');
}, config.observerTimeout);
} else {
startObservation();
}
}
// 启动脚本
if (document.readyState === 'loading') {
window.addEventListener('DOMContentLoaded', init);
} else {
setTimeout(init, 500);
}
})();