YouTube 自動展開評論和回覆

自動展開 YouTube 視頻頁面的所有評論和回覆

目前為 2025-01-27 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name YouTube Auto Expand Comments and Replies
  3. // @name:zh-CN YouTube 自动展开评论和回复
  4. // @name:zh-TW YouTube 自動展開評論和回覆
  5. // @name:ja YouTube コメントと返信を自動展開
  6. // @name:ko YouTube 댓글 및 답글 자동 확장
  7. // @name:es Expansión automática de comentarios y respuestas de YouTube
  8. // @name:fr Expansion automatique des commentaires et réponses YouTube
  9. // @name:de Automatische Erweiterung von YouTube-Kommentaren und Antworten
  10. // @namespace https://github.com/SuperNG6/YouTube-Comment-Script
  11. // @author SuperNG6
  12. // @version 1.3
  13. // @description Automatically expand all comments and replies on YouTube video pages
  14. // @license MIT
  15. // @description:zh-CN 自动展开 YouTube 视频页面的所有评论和回复
  16. // @description:zh-TW 自動展開 YouTube 視頻頁面的所有評論和回覆
  17. // @description:ja YouTube動画ページのすべてのコメントと返信を自動的に展開します
  18. // @description:ko YouTube 동영상 페이지의 모든 댓글과 답글을 자동으로 확장합니다
  19. // @description:es Expande automáticamente todos los comentarios y respuestas en las páginas de videos de YouTube
  20. // @description:fr Développe automatiquement tous les commentaires et réponses sur les pages vidéo YouTube
  21. // @description:de Erweitert automatisch alle Kommentare und Antworten auf YouTube-Videoseiten
  22. // @match https://www.youtube.com/watch?v=*
  23. // @grant none
  24. // ==/UserScript==
  25.  
  26. (function() {
  27. 'use strict';
  28.  
  29. // 配置参数
  30. const config = {
  31. checkInterval: 500, // 常规检查间隔
  32. observerTimeout: 3000, // 观察器超时时间
  33. maxRetries: 10, // 最大重试次数
  34. debug: false // 调试模式
  35. };
  36.  
  37. let retryCount = 0;
  38. let observer = null;
  39.  
  40. function log(...args) {
  41. if (config.debug) console.log('[YouTube Auto Expand]', ...args);
  42. }
  43.  
  44. // 更可靠的选择器
  45. const selectors = {
  46. commentsContainer: 'ytd-comments#comments',
  47. commentReplies: 'ytd-comment-replies-renderer',
  48. viewMoreComments: 'ytd-continuation-item-renderer #button', // 主评论的"查看更多"按钮
  49. showRepliesButton: '#more-replies > yt-button-shape > button', // 回复按钮
  50. showHiddenReplies: 'ytd-comment-replies-renderer yt-button-shape' // 隐藏的回复按钮
  51. };
  52.  
  53. function clickVisibleElements(selector) {
  54. const elements = [...document.querySelectorAll(selector)];
  55. return elements.filter(el => {
  56. if (el.offsetParent !== null && !el.disabled) {
  57. try {
  58. el.scrollIntoView({behavior: "auto", block: "center"});
  59. el.click();
  60. log('Clicked:', selector);
  61. return true;
  62. } catch (error) {
  63. log('Click error:', error);
  64. }
  65. }
  66. return false;
  67. }).length > 0;
  68. }
  69.  
  70. function expandElements() {
  71. let clickedSomething = false;
  72. // 处理主评论的"查看更多评论"按钮
  73. clickedSomething |= clickVisibleElements(selectors.viewMoreComments);
  74. // 处理回复按钮
  75. clickedSomething |= clickVisibleElements(selectors.showRepliesButton);
  76. // 处理可能存在的隐藏回复
  77. clickedSomething |= clickVisibleElements(selectors.showHiddenReplies);
  78.  
  79. return clickedSomething;
  80. }
  81.  
  82. function startObservation() {
  83. const commentsContainer = document.querySelector(selectors.commentsContainer);
  84. if (!commentsContainer) {
  85. if (retryCount++ < config.maxRetries) {
  86. setTimeout(startObservation, config.checkInterval);
  87. log(`Retrying to find comments container (${retryCount}/${config.maxRetries})`);
  88. }
  89. return;
  90. }
  91.  
  92. observer = new MutationObserver((mutations) => {
  93. if (expandElements()) {
  94. // 如果检测到变化并执行了点击,稍后再检查
  95. setTimeout(() => expandElements(), config.checkInterval);
  96. }
  97. });
  98.  
  99. observer.observe(commentsContainer, {
  100. childList: true,
  101. subtree: true,
  102. attributes: false,
  103. characterData: false
  104. });
  105.  
  106. // 初始执行
  107. setTimeout(() => {
  108. expandElements();
  109. // 处理无限滚动加载
  110. window.addEventListener('scroll', () => expandElements());
  111. }, 500);
  112.  
  113. log('Observation started');
  114. }
  115.  
  116. function init() {
  117. if (!document.querySelector(selectors.commentsContainer)) {
  118. // 如果评论区还没加载,等待直到加载完成
  119. const waitForComments = setInterval(() => {
  120. if (document.querySelector(selectors.commentsContainer)) {
  121. clearInterval(waitForComments);
  122. startObservation();
  123. }
  124. }, config.checkInterval);
  125. // 设置超时停止检测
  126. setTimeout(() => {
  127. clearInterval(waitForComments);
  128. log('Comments container not found within timeout');
  129. }, config.observerTimeout);
  130. } else {
  131. startObservation();
  132. }
  133. }
  134.  
  135. // 启动脚本
  136. if (document.readyState === 'loading') {
  137. window.addEventListener('DOMContentLoaded', init);
  138. } else {
  139. setTimeout(init, 500);
  140. }
  141. })();