动态粉粉嫩嫩,功能:1. 美化页面;2. 隐藏个人动态发布框;3. 隐藏右侧热门话题;4. 隐藏up发布的广告动态。优化了样式注入、MutationObserver等性能问题。
// ==UserScript== // @name Bilibili 动态美化(优化版) // @namespace http://tampermonkey.net/ // @version 0.7 // @description 动态粉粉嫩嫩,功能:1. 美化页面;2. 隐藏个人动态发布框;3. 隐藏右侧热门话题;4. 隐藏up发布的广告动态。优化了样式注入、MutationObserver等性能问题。 // @author Water WHNI // @match https://t.bilibili.com/* // @match https://www.bilibili.com/ // @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @license MIT // ==/UserScript== (function () { 'use strict'; /*** 默认设置与用户配置 ***/ const defaultSettings = { customBackgroundURL: 'https://i0.hdslb.com/bfs/article/bfecb9a12cb9708d8d79bb9c17532e347747aeaf.jpg@1256w_708h_!web-article-pic.avif', hideElementsEnabled: true, hideRightSidebar: true, hidePostBar: true, autoFrash: true, autoClickInterval: 5, enableAutoClick: true, backgroundTransparency: 61, backgroundTransparency2: 81, backgroundTransparencyFloat: 91 }; const settings = {}; for (const key in defaultSettings) { settings[key] = GM_getValue(key, defaultSettings[key]); } /*** 合并主样式 ***/ const mainStyles = ` .bili-live-card, .floor-single-card, .adblock-tips { display: none !important; } .bili-dyn-card-video__body, .bili-dyn-card-live__body, .bili-dyn-card-pgc__body { border: none !important; } .bili-dyn-sidebar { right: 5vw !important; } .bili-header__channel { background: none !important; } .bili-dyn-up-list__item__name.bili-ellipsis, .bili-dyn-time.fs-small, .item-desc, .bili-dyn-action, .bili-dyn-more__btn, .bili-dyn-card-video__stat__item, #bili-header-container span, svg { color: rgb(251, 114, 153) !important; } .bili-dyn-interaction__item__desc .bili-rich-text__content { color: #2f3238e0 !important; } .header-upload-entry { background-color: #fc8bab6b !important; } .bili-dyn-more__btn:hover { background-color: #fa5a5742 !important; border-radius: 50% !important; } .bili-dyn-card-video__desc, .bili-dyn-publishing__hint { color: #424549 !important; } .bili-dyn-list-notification.fs-small { color: rgb(251, 114, 153) !important; } .bili-dyn-content { border: 2px solid transparent !important; border-radius: 10px !important; box-shadow: 0 0 0 rgb(251, 114, 153) !important; transition: box-shadow 0.3s ease-in-out !important; } .bili-dyn-content:hover { box-shadow: 0 0 15px rgb(251, 114, 153), 0 0 15px rgb(251, 114, 153) !important; background-color: #ffffff80 !important; } .bili-dyn-up-list__item__face { border: 1px solid transparent !important; box-shadow: 0 0 0 rgb(251, 114, 153) !important; transition: box-shadow 0.3s ease-in-out !important; } .bili-dyn-up-list__item__face:hover { box-shadow: 0 0 5px rgb(251, 114, 153), 0 0 5px rgb(251, 114, 153) !important; } .bili-dyn-up-list__nav.next .bili-dyn-up-list__nav__shadow { background: linear-gradient(90deg, hsla(0, 0%, 100%, 0), rgb(251 114 153 / 60%) !important; } .bili-dyn-up-list__nav__shim { background: rgb(251 114 153 / 60%) !important; } .bili-dyn-up-list__nav.prev .bili-dyn-up-list__nav__shadow { background: linear-gradient(270deg, hsla(0, 0%, 100%, 0), rgb(251 114 153 / 60%) !important; } .bili-album__watch__content { height: 30vw !important; } .bili-album__watch__content img { height: 30vw !important; max-width: 60% !important; } :root { --bg1: rgba(255,255,255,${settings.backgroundTransparency / 100}) !important; --bg2: rgba(255,255,255,${settings.backgroundTransparency2 / 100}) !important; --bg1_float: rgba(255,255,255,${settings.backgroundTransparencyFloat / 100}) !important; } `; GM_addStyle(mainStyles); /*** 条件样式合并注入 ***/ let additionalStyles = ''; if (settings.hideRightSidebar) { additionalStyles += ` .right { display: none !important; } #app > div.bili-dyn-home--member > main { width: 70vw !important; } `; } if (settings.hidePostBar) { additionalStyles += ` .bili-dyn-publishing { display: none !important; } #app > div.bili-dyn-home--member > main > section:nth-child(1) { display: none !important; } .bili-dyn-up-list__window { padding: 20px 0 !important; margin-top: 2px !important; } `; } if (additionalStyles) { GM_addStyle(additionalStyles); } /*** 样式节点复用:背景图 & 背景透明度 ***/ const bgImageStyleEl = GM_addStyle(''); // 用于背景图样式 const updateBackgroundImage = (url) => { bgImageStyleEl.innerHTML = ` .bg { background-image: url("${url}") !important; background-size: cover !important; background-attachment: fixed !important; background-position: center center !important; background-repeat: no-repeat !important; height: 100% !important; } `; }; updateBackgroundImage(settings.customBackgroundURL); const transparencyStyleEl = GM_addStyle(''); // 用于透明度变量 const updateTransparency = (transparency, tB2, bg1F) => { transparencyStyleEl.innerHTML = ` :root { --bg1: rgba(255,255,255,${transparency/100}) !important; --bg2: rgba(255,255,255,${tB2/100}) !important; --bg1_float: rgba(255,255,255,${bg1F/100}) !important; } `; }; updateTransparency(settings.backgroundTransparency, settings.backgroundTransparency2, settings.backgroundTransparencyFloat); /*** 隐藏广告动态的逻辑(加入防抖处理) ***/ const hideSpecificElements = () => { document.querySelectorAll('.bili-dyn-list__item').forEach(item => { if (item.querySelector('.bili-rich-text-module.goods')) { item.style.display = 'none'; } }); }; // 简单防抖函数 const debounce = (fn, delay) => { let timer; return (...args) => { if (timer) clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); }; }; const debouncedHide = debounce(hideSpecificElements, 100); if (settings.hideElementsEnabled) { hideSpecificElements(); new MutationObserver(debouncedHide).observe(document.body, { childList: true, subtree: true }); } /*** 定时自动点击“加载新动态” ***/ const checkAndClick = () => { const selector = '#app > div.bili-dyn-home--member > main > section:nth-child(3) > div.bili-dyn-list > div.bili-dyn-list__notification > div'; const element = document.querySelector(selector); if (element) { try { element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); } catch (e) { const event = document.createEvent('Event'); event.initEvent('click', true, true); element.dispatchEvent(event); } } }; let autoClickIntervalId; const setupAutoClick = () => { if (settings.enableAutoClick) { autoClickIntervalId = setInterval(checkAndClick, settings.autoClickInterval * 1000); } }; setupAutoClick(); /*** 菜单与交互设置(基本逻辑保持不变) ***/ const createToggle = (label, key) => { const container = document.createElement('div'); container.style.cssText = ` margin-bottom: 10px; display: flex; align-items: center; justify-content: space-between; `; const toggleLabel = document.createElement('label'); toggleLabel.innerText = label; toggleLabel.style.margin = '0'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = settings[key]; checkbox.style.marginLeft = '10px'; checkbox.onchange = () => settings[key] = checkbox.checked; container.append(toggleLabel, checkbox); return { container, checkbox }; }; GM_registerMenuCommand('设置', () => { const modal = document.createElement('div'); modal.style.cssText = ` position: fixed; top: 8vh; right: 1vw; padding: 20px; background-color: #fff; box-shadow: 0 0 15px rgba(0, 0, 0, 0.3); border-radius: 10px; z-index: 9999; width: 320px; font-family: Arial, sans-serif; overflow: auto; `; const modalHeader = document.createElement('div'); modalHeader.style.cssText = ` font-size: 20px; font-weight: bold; margin-bottom: 15px; text-align: center; `; modalHeader.innerText = '设置'; // 背景图片输入及应用 const bgInputContainer = document.createElement('div'); bgInputContainer.style.cssText = ` display: flex; align-items: center; margin-bottom: 10px; width: 100%; `; const bgInputLabel = document.createElement('label'); bgInputLabel.innerText = '背景图片URL: '; bgInputLabel.style.flex = '0 0 35%'; const bgInput = document.createElement('input'); bgInput.type = 'text'; bgInput.value = settings.customBackgroundURL; bgInput.style.cssText = ` flex: 1; padding: 5px; border: 1px solid #ccc; border-radius: 5px; margin-left: 10px; overflow: hidden; text-overflow: ellipsis; `; const applyBgButton = document.createElement('button'); applyBgButton.innerText = '应用'; applyBgButton.style.cssText = ` width: 100%; padding: 5px 10px; background-color: #12a9df; color: white; border: none; border-radius: 5px; cursor: pointer; margin-bottom: 5px; `; applyBgButton.onclick = () => { const newURL = bgInput.value; GM_setValue('customBackgroundURL', newURL); updateBackgroundImage(newURL); }; bgInputContainer.append(bgInputLabel, bgInput); // 创建开关 const { container: hideUpAdContainer, checkbox: hideUpAdCheckbox } = createToggle('隐藏UP广告动态', 'hideElementsEnabled'); const { container: hideSidebarContainer, checkbox: hideSidebarCheckbox } = createToggle('隐藏右边栏', 'hideRightSidebar'); const { container: hidePostBarContainer, checkbox: hidePostBarCheckbox } = createToggle('隐藏动态发布', 'hidePostBar'); const { container: timerToggleContainer, checkbox: timerToggleCheckbox } = createToggle('自动加载新动态', 'enableAutoClick'); // 点击间隔输入框 const intervalContainer = document.createElement('div'); intervalContainer.style.cssText = ` display: flex; align-items: center; margin-bottom: 10px; width: 100%; `; const intervalLabel = document.createElement('label'); intervalLabel.innerText = '点击间隔 (秒): '; intervalLabel.style.flex = '0 0 35%'; const intervalInput = document.createElement('input'); intervalInput.type = 'number'; intervalInput.min = '1'; intervalInput.value = settings.autoClickInterval || 5; intervalInput.style.cssText = ` flex: 1; padding: 5px; margin-left: 10px; border: 1px solid #ccc; border-radius: 5px; `; intervalInput.oninput = () => { const interval = Math.max(1, parseInt(intervalInput.value)); settings.autoClickInterval = interval; GM_setValue('autoClickInterval', interval); if (settings.enableAutoClick) { clearInterval(autoClickIntervalId); autoClickIntervalId = setInterval(checkAndClick, interval * 1000); } }; intervalContainer.append(intervalLabel, intervalInput); // 背景透明度滑块 const sliderContainer = document.createElement('div'); sliderContainer.style.cssText = ` display: flex; align-items: center; margin-bottom: 10px; width: 100%; `; const sliderLabel = document.createElement('label'); sliderLabel.innerText = '背景透明度: '; sliderLabel.style.flex = '0 0 35%'; const slider = document.createElement('input'); slider.type = 'range'; slider.min = '0'; slider.max = '100'; slider.value = settings.backgroundTransparency; slider.style.cssText = ` flex: 1; margin-left: 5px; `; slider.oninput = () => { const transparency = parseInt(slider.value); settings.backgroundTransparency2 = Math.min(transparency + 20, 100); settings.backgroundTransparencyFloat = Math.min(transparency + 50, 100); GM_setValue('backgroundTransparency', transparency); GM_setValue('backgroundTransparency2', settings.backgroundTransparency2); GM_setValue('backgroundTransparencyFloat', settings.backgroundTransparencyFloat); updateTransparency(transparency, settings.backgroundTransparency2, settings.backgroundTransparencyFloat); }; sliderContainer.append(sliderLabel, slider); // 按钮容器 const buttonContainer = document.createElement('div'); buttonContainer.style.cssText = ` display: flex; justify-content: space-between; margin-top: 15px; `; const closeButton = document.createElement('button'); closeButton.innerText = '关闭'; closeButton.style.cssText = ` padding: 5px 10px; background-color: #f44336; color: white; border: none; border-radius: 5px; cursor: pointer; `; closeButton.onclick = () => document.body.removeChild(modal); const saveButton = document.createElement('button'); saveButton.innerText = '保存'; saveButton.style.cssText = ` padding: 5px 10px; background-color: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; `; saveButton.onclick = () => { GM_setValue('hideElementsEnabled', hideUpAdCheckbox.checked); GM_setValue('hideRightSidebar', hideSidebarCheckbox.checked); GM_setValue('hidePostBar', hidePostBarCheckbox.checked); GM_setValue('enableAutoClick', timerToggleCheckbox.checked); GM_setValue('autoClickInterval', Math.max(1, parseInt(intervalInput.value))); location.reload(); }; buttonContainer.append(saveButton, closeButton); modal.append( modalHeader, bgInputContainer, applyBgButton, hideUpAdContainer, hideSidebarContainer, hidePostBarContainer, timerToggleContainer, intervalContainer, sliderContainer, buttonContainer ); document.body.appendChild(modal); }); })();