YouTube show hidden comments
// ==UserScript==
// @name YouTube 強制留言顯示由新到舊
// @match *://*.youtube.com/*
// @version 0.4
// @author Artin
// @license MIT
// @description YouTube show hidden comments
// @grant none
// @namespace https://greasyfork.org/users/814315
// ==/UserScript==
(function() {
'use strict';
let isProcessing = false;
let checkCount = 0;
let retryCount = 0;
const maxChecks = 4;
const maxRetries = 2;
function log(message) {
console.log(`[YouTube留言排序] ${message}`);
}
function switchToNewestComments() {
if (isProcessing) {
// log('正在處理中,跳過');
return;
}
isProcessing = true;
// log('開始檢查留言排序');
try {
// 更新的選擇器,根據實際 DOM 結構
const sortButtonSelectors = [
'#sort-menu yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'#sort-menu yt-sort-filter-sub-menu-renderer yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'ytd-comments-header-renderer #sort-menu yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'#comments #sort-menu yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'#comments yt-sort-filter-sub-menu-renderer yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
// 保留原有的選擇器作為後備
'#comments yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'#comments ytd-menu-renderer button',
'ytd-comments-header-renderer yt-dropdown-menu tp-yt-paper-button'
];
let sortButton = null;
let usedSelector = '';
for (let selector of sortButtonSelectors) {
sortButton = document.querySelector(selector);
if (sortButton) {
usedSelector = selector;
break;
}
}
if (!sortButton) {
// log('未找到任何排序按鈕');
isProcessing = false;
return;
}
// log(`找到排序按鈕 (${usedSelector}),準備點擊`);
// 檢查按鈕是否可見且可點擊
const buttonRect = sortButton.getBoundingClientRect();
const isVisible = buttonRect.width > 0 && buttonRect.height > 0;
if (!isVisible) {
// log('排序按鈕不可見,跳過');
isProcessing = false;
return;
}
// 點擊排序按鈕
sortButton.click();
// 等待下拉選單出現
setTimeout(() => {
// log('尋找下拉選單項目');
// 更精確的選單項目選擇器
const menuItemSelectors = [
'#sort-menu yt-dropdown-menu a.yt-simple-endpoint',
'yt-dropdown-menu a.yt-simple-endpoint',
'tp-yt-paper-listbox a.yt-simple-endpoint'
];
let menuItems = [];
for (let selector of menuItemSelectors) {
menuItems = document.querySelectorAll(selector);
if (menuItems.length > 0) {
// log(`使用選擇器找到選單項目: ${selector}`);
break;
}
}
// log(`找到 ${menuItems.length} 個選單項目`);
let foundNewest = false;
for (let i = 0; i < menuItems.length; i++) {
const item = menuItems[i];
const itemText = item.textContent || item.innerText || '';
// log(`項目 ${i}: "${itemText.trim()}"`);
// 檢查是否為"由新到舊"選項
if (itemText.includes('由新到舊') || itemText.includes('Newest first') ||
itemText.includes('最新') || itemText.includes('新しい順')) {
// log('找到"由新到舊"選項');
// 檢查是否已經選中
const isSelected = item.classList.contains('iron-selected') ||
item.getAttribute('aria-selected') === 'true';
if (!isSelected) {
// log('切換至"由新到舊"排序');
item.click();
foundNewest = true;
} else {
// log('"由新到舊"已經選中');
foundNewest = true;
}
break;
}
}
if (!foundNewest) {
// log('未找到"由新到舊"選項,嘗試點擊第二個選項');
// 如果沒找到文字匹配,嘗試點擊第二個選項(通常是由新到舊)
if (menuItems.length >= 2) {
const secondItem = menuItems[1];
const isSelected = secondItem.classList.contains('iron-selected') ||
secondItem.getAttribute('aria-selected') === 'true';
if (!isSelected) {
// log('點擊第二個選項');
secondItem.click();
}
}
}
isProcessing = false;
}, 500);
} catch (error) {
// log(`執行錯誤: ${error.message}`);
isProcessing = false;
}
}
function debugCommentsSection() {
const commentsSection = document.querySelector('#comments');
// log(`留言區域存在: ${!!commentsSection}`);
if (commentsSection) {
// 檢查各種可能的排序選單選擇器
const selectors = [
'#sort-menu',
'#sort-menu yt-dropdown-menu',
'#sort-menu yt-sort-filter-sub-menu-renderer',
'ytd-comments-header-renderer #sort-menu',
'#comments yt-sort-filter-sub-menu-renderer',
'#comments yt-dropdown-menu',
'#comments ytd-menu-renderer'
];
selectors.forEach(selector => {
const element = document.querySelector(selector);
// log(`選擇器 "${selector}": ${!!element}`);
if (element) {
// log(` - 元素內容: ${element.textContent?.trim().substring(0, 100)}...`);
// log(` - 是否可見: ${element.offsetWidth > 0 && element.offsetHeight > 0}`);
// log(` - 元素類名: ${element.className}`);
}
});
// 檢查排序按鈕
const sortButtonSelectors = [
'#sort-menu yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'#sort-menu tp-yt-paper-button.dropdown-trigger',
'tp-yt-paper-button.dropdown-trigger'
];
sortButtonSelectors.forEach(selector => {
const button = document.querySelector(selector);
// log(`排序按鈕選擇器 "${selector}": ${!!button}`);
if (button) {
const rect = button.getBoundingClientRect();
// log(` - 按鈕位置: ${rect.width}x${rect.height} at (${rect.left}, ${rect.top})`);
// log(` - 按鈕文字: "${button.textContent?.trim()}"`);
}
});
// 檢查是否有任何包含"排序"或"sort"的元素
const allElements = commentsSection.querySelectorAll('*');
const sortElements = Array.from(allElements).filter(el => {
const text = el.textContent || '';
return text.includes('排序') || text.includes('sort') || text.includes('Sort') ||
text.includes('熱門') || text.includes('最新') || text.includes('由新到舊');
});
// log(`找到 ${sortElements.length} 個可能的排序相關元素:`);
sortElements.slice(0, 5).forEach((el, index) => {
// log(` ${index + 1}. ${el.tagName}: "${el.textContent?.trim().substring(0, 50)}..."`);
// log(` 類名: ${el.className}`);
});
}
}
function checkSortMenuReady() {
const commentsSection = document.querySelector('#comments');
if (!commentsSection) {
return false;
}
// 更新的選擇器列表
const sortMenuSelectors = [
'#sort-menu yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'#sort-menu yt-sort-filter-sub-menu-renderer yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'ytd-comments-header-renderer #sort-menu yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'#comments #sort-menu yt-dropdown-menu tp-yt-paper-button.dropdown-trigger',
'#comments yt-sort-filter-sub-menu-renderer yt-dropdown-menu tp-yt-paper-button.dropdown-trigger'
];
for (let selector of sortMenuSelectors) {
const sortButton = document.querySelector(selector);
if (sortButton) {
const buttonRect = sortButton.getBoundingClientRect();
const isVisible = buttonRect.width > 0 && buttonRect.height > 0;
if (isVisible) {
// log(`找到可用的排序按鈕 (使用選擇器: ${selector})`);
return true;
}
}
}
return false;
}
function waitForSortMenu() {
if (checkCount >= maxChecks) {
// log(`達到最大檢查次數 (${maxChecks}),開始詳細偵測`);
debugCommentsSection();
// 重試機制
if (retryCount < maxRetries) {
retryCount++;
checkCount = 0;
// log(`第 ${retryCount} 次重試`);
setTimeout(waitForSortMenu, 500);
return;
} else {
// log('達到最大重試次數,停止嘗試');
checkCount = 0;
retryCount = 0;
return;
}
}
checkCount++;
// log(`等待排序選單載入 (${checkCount}/${maxChecks})`);
if (checkSortMenuReady()) {
checkCount = 0;
retryCount = 0;
setTimeout(switchToNewestComments, 300);
} else {
// 每2次檢查就做一次詳細偵測
if (checkCount % 2 === 0) {
debugCommentsSection();
}
setTimeout(waitForSortMenu, 300);
}
}
function handlePageChange() {
if (window.location.pathname.includes('/watch')) {
// log('檢測到影片頁面');
checkCount = 0;
retryCount = 0;
isProcessing = false;
setTimeout(waitForSortMenu, 500);
}
}
// 監聽URL變化
let currentUrl = window.location.href;
function checkUrlChange() {
if (currentUrl !== window.location.href) {
currentUrl = window.location.href;
// log(`頁面變化: ${currentUrl}`);
handlePageChange();
}
}
// 使用MutationObserver監聽DOM變化
const observer = new MutationObserver((mutations) => {
checkUrlChange();
// 檢查是否有新的留言區域載入
const hasCommentsChange = mutations.some(mutation => {
return Array.from(mutation.addedNodes).some(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
return node.id === 'comments' ||
node.querySelector && node.querySelector('#comments') ||
node.querySelector && node.querySelector('#sort-menu');
}
return false;
});
});
if (hasCommentsChange && window.location.pathname.includes('/watch')) {
// log('偵測到留言區域變化');
setTimeout(() => {
if (!isProcessing) {
checkCount = 0;
waitForSortMenu();
}
}, 1000);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// 監聽pushstate和popstate事件(YouTube的SPA導航)
const originalPushState = history.pushState;
history.pushState = function() {
originalPushState.apply(history, arguments);
setTimeout(checkUrlChange, 200);
};
window.addEventListener('popstate', checkUrlChange);
// 初始化
setTimeout(handlePageChange, 500);
})();