// ==UserScript== // @name 把B站评论区挪到右边,边看视频边看评论test // @namespace http://tampermonkey.net/ // @version 2025.04.18 // @description 将B站评论区移动到右侧容器 // @author FruitJellies // @match https://www.bilibili.com/video/* // @match https://www.bilibili.com/list/* // @icon https://www.bilibili.com/favicon.ico // @grant GM_addStyle // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; const path = window.location.pathname; // 配置对象 const CONFIG = { containerSelector: "#mirror-vdcon > div.right-container", playlistContainerSelector: "#mirror-vdcon > div.playlist-container--right", commentAppSelector: "#commentapp", playlistTargetPositionSelector:"#mirror-vdcon > div.playlist-container--right > div.recommend-list-container", targetPositionSelector: ".rcmd-tab", observerConfig: { childList: true, subtree: true, attributes: false }, timeoutDuration: 9999999999, // 999……秒超时 styleSettings: { containerWidth: "22%", containerHeight: "110vh" } }; // 全局变量 let observer = null; let timeoutId = null; let isCommentsMoved = false; let originalPosition = null; let cachedElements = {}; // 缓存DOM元素 function getCachedElement(selector) { if (!cachedElements[selector]) { cachedElements[selector] = document.querySelector(selector); } return cachedElements[selector]; } // 安全DOM操作 function safeDOMOperation(operation) { try { return operation(); } catch (error) { console.error('[BCTR] DOM操作失败:', error); return null; } } // 初始化容器样式 function initContainerStyles() { const commonStyles = ` width: ${CONFIG.styleSettings.containerWidth}; height: ${CONFIG.styleSettings.containerHeight}; overflow-y: scroll !important; scrollbar-width: none; `; GM_addStyle(` ${CONFIG.playlistContainerSelector}, ${CONFIG.containerSelector} { ${commonStyles} } ${CONFIG.playlistContainerSelector}::-webkit-scrollbar, ${CONFIG.containerSelector}::-webkit-scrollbar { display: none; } body { overflow: auto !important; } `); } // 处理评论区移动 function handleCommentsMove() { return safeDOMOperation(() => { const commentApp = getCachedElement(CONFIG.commentAppSelector); const shadowContent = commentApp?.querySelector('bili-comments')?.shadowRoot?.querySelector('#contents'); const targetPositionSelector = path.startsWith('/list/') ? CONFIG.playlistTargetPositionSelector : CONFIG.targetPositionSelector; const targetPosition = getCachedElement(targetPositionSelector); if (!commentApp || !targetPosition || !shadowContent) { return false; } // 保存原始位置 if (!originalPosition) { originalPosition = commentApp.parentNode; } targetPosition.parentNode.insertBefore(commentApp, targetPosition); console.log('[BCTR] 评论区移动成功'); isCommentsMoved = true; return true; }); } // 恢复评论区到原始位置 function restoreCommentsPosition() { return safeDOMOperation(() => { const commentApp = getCachedElement(CONFIG.commentAppSelector); if (!commentApp || !originalPosition) { return false; } originalPosition.appendChild(commentApp); console.log('[BCTR] 评论区恢复成功'); isCommentsMoved = false; return true; }); } // 切换评论区位置 function toggleCommentsPosition() { isCommentsMoved ? restoreCommentsPosition() : handleCommentsMove(); } // 创建切换按钮 function createToggleButton() { const titleElement = path.startsWith('/list/') ?getCachedElement("#mirror-vdcon > div.playlist-container--left > div.video-info-container.mac > div.video-info-title > div > h1 > a") :getCachedElement("#viewbox_report > div.video-info-title > div > h1"); if (!titleElement) return; const toggleBtn = document.createElement('button'); toggleBtn.className = 'comment-toggle-btn'; toggleBtn.textContent = '⇄'; toggleBtn.title = '切换评论区位置'; toggleBtn.addEventListener('click', toggleCommentsPosition); titleElement.appendChild(toggleBtn); const style = document.createElement('style'); style.textContent = ` .comment-toggle-btn { border-radius: 6px !important; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; margin-left: 12px; background-color: #fb7299; color: white; border: none; cursor: pointer; vertical-align: middle; font-size: 14px; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); position: relative; overflow: hidden; box-sizing: border-box; z-index: 1; } @media (prefers-color-scheme: dark) { .comment-toggle-btn { background-color: #ff85ad; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } `; document.head.appendChild(style); } // 清理资源 function cleanupResources() { if (observer) { observer.disconnect(); observer = null; } if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } cachedElements = {}; console.log('[BCTR] 已释放观察器和定时器'); } // MutationObserver回调 function mutationCallback(mutationsList) { for (const mutation of mutationsList) { if (mutation.type === 'childList' && handleCommentsMove()) { cleanupResources(); createToggleButton(); break; } } } //禁用标题超链接 function disableTitleLink() { const titleLink = document.querySelector("#mirror-vdcon > div.playlist-container--left > div.video-info-container.mac > div.video-info-title > div > h1 > a"); if (titleLink) { titleLink.removeAttribute('href'); titleLink.style.cursor = 'default'; titleLink.style.textDecoration = 'none'; titleLink.style.color = 'inherit'; console.log('[BCTR] 已禁用标题超链接'); } } // 初始化函数 function init() { initContainerStyles(); if (path.startsWith('/list/')) disableTitleLink(); // 更精确地选择观察目标 const observeTarget = document.body || document.documentElement; observer = new MutationObserver(mutationCallback); observer.observe(observeTarget, CONFIG.observerConfig); timeoutId = setTimeout(() => { console.warn('[BCTR] 操作超时,终止检测'); cleanupResources(); }, CONFIG.timeoutDuration); console.log('[BCTR] 脚本初始化完成'); } // 启动脚本 try { init(); } catch (error) { console.error('[BCTR] 脚本初始化失败:', error); cleanupResources(); } })();