您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
混合觸發模式:滑鼠游標自動展開查看更多 + 點讚 + 影片音量調整 + 左下角控制面板
当前为
// ==UserScript== // @name Facebook 自動展開與互動增強 // @namespace http://tampermonkey.net/ // @version 2025.05.14.12 // @description 混合觸發模式:滑鼠游標自動展開查看更多 + 點讚 + 影片音量調整 + 左下角控制面板 // @author You // @match https://www.facebook.com/* // @grant GM_setValue // @grant GM_getValue // @license MIT // ==/UserScript== (function() { // 常數與狀態初始化 const CLICK_INTERVAL = 500; const HIDDEN_STYLE_SELECTOR = '.xwib8y2.x1y1aw1k.xwya9rg.x1n2onr6'; const state = { lastClickTime: 0, likeCoolingDown: false, panelCollapsed: false, DEFAULT_VOLUME: GM_getValue('DEFAULT_VOLUME', 0.2), COLUMN_COUNT: GM_getValue('COLUMN_COUNT', 3), buttons: { like: GM_getValue('likeEnabled', true), seeMore: GM_getValue('seeMoreEnabled', true), otherExpand: GM_getValue('otherExpandEnabled', true), volume: GM_getValue('volumeEnabled', true), columns: GM_getValue('columnsEnabled', false), hideStyle: GM_getValue('hideStyleEnabled', false), wideLayout: GM_getValue('wideLayoutEnabled', false) } }; // 效能優化:快取常用元素 let cachedElements = { panel: null, videoElements: null, lastVideoCheck: 0 }; // 控制面板創建 function createControlPanel() { const panel = document.createElement('div'); Object.assign(panel.style, { position: 'fixed', left: '0px', bottom: '30px', zIndex: '9999', display: 'flex', flexDirection: 'column', gap: '5px', backgroundColor: 'transparent', padding: '10px', borderRadius: '8px' }); try { // 按鈕創建函數 const createButton = (text, key, action) => { const btn = document.createElement('button'); Object.assign(btn.style, { padding: '8px 12px', border: 'none', borderRadius: '4px', cursor: 'pointer', fontWeight: 'bold', width: '40px', textAlign: 'center' }); btn.innerText = text; btn.addEventListener('click', () => { state.buttons[key] = !state.buttons[key]; GM_setValue(`${key}Enabled`, state.buttons[key]); updateButtonStyle(btn, state.buttons[key]); action && action(); }); updateButtonStyle(btn, state.buttons[key]); return btn; }; // 創建主要功能按鈕 panel.append( createButton('讚', 'like'), createButton('看', 'seeMore'), createButton('回', 'otherExpand'), createButton('音', 'volume', () => state.buttons.volume && processAllVideos()) ); // 音量控制組(固定黑色背景白字樣式) const volumeControlGroup = createControlGroup([ createSmallButton('-', () => adjustVolume(-0.1)), createSmallButton('+', () => adjustVolume(0.1)) ]); panel.append(volumeControlGroup); // 欄位控制(如果可用) if (hasColumnCountCSS()) { panel.append( createButton('欄', 'columns', () => state.buttons.columns && applyColumnCount()), createControlGroup([ createSmallButton('-', () => adjustColumnCount(-1)), createSmallButton('+', () => adjustColumnCount(1)) ]) ); } // 其他功能按鈕 panel.append( createButton('動', 'hideStyle', toggleStyleVisibility) ); // 寬版佈局按鈕(如果可用) if (hasWideLayoutCSS()) { panel.append( createButton('放', 'wideLayout', toggleWideLayout) ); } // 折疊按鈕(固定黑色背景白字樣式) const collapseBtn = document.createElement('button'); Object.assign(collapseBtn.style, { padding: '8px 12px', border: 'none', borderRadius: '4px', cursor: 'pointer', fontWeight: 'bold', width: '40px', textAlign: 'center', backgroundColor: '#000000', color: '#FFFFFF' }); collapseBtn.innerText = state.panelCollapsed ? 'Δ' : '∇'; collapseBtn.addEventListener('click', () => { state.panelCollapsed = !state.panelCollapsed; GM_setValue('panelCollapsed', state.panelCollapsed); collapseBtn.innerText = state.panelCollapsed ? 'Δ' : '∇'; togglePanelCollapse(); }); panel.append(collapseBtn); document.body.appendChild(panel); cachedElements.panel = panel; state.panelCollapsed && togglePanelCollapse(); } catch {} } // 輔助函數 function createControlGroup(buttons) { const group = document.createElement('div'); Object.assign(group.style, { display: 'flex', justifyContent: 'space-between', width: '40px', marginTop: '-5px' }); buttons && buttons.forEach(btn => group.append(btn)); return group; } function createSmallButton(text, action) { const btn = document.createElement('button'); Object.assign(btn.style, { padding: '2px 0', border: '1px solid #000000', borderRadius: '4px', cursor: 'pointer', fontSize: '12px', width: '20px', textAlign: 'center', backgroundColor: '#000000', color: '#FFFFFF' }); btn.innerText = text; btn.addEventListener('click', action); return btn; } function updateButtonStyle(btn, isActive) { Object.assign(btn.style, { backgroundColor: isActive ? '#1877f2' : '#e4e6eb', color: isActive ? 'white' : '#65676b' }); } // 面板折疊功能 function togglePanelCollapse() { const buttons = cachedElements.panel.querySelectorAll('button'); buttons.forEach(btn => { if (!['Δ', '∇', '+', '-'].includes(btn.innerText)) { btn.style.display = state.panelCollapsed ? 'none' : 'block'; } }); } // 寬版佈局檢測與切換 function hasWideLayoutCSS() { return Array.from(document.styleSheets).some(sheet => { try { return Array.from(sheet.cssRules).some(rule => rule.media && rule.media.mediaText.includes('min-width: 1900px') ); } catch {} }); } function toggleWideLayout() { Array.from(document.styleSheets).forEach(sheet => { try { Array.from(sheet.cssRules).forEach(rule => { if (rule.media && (rule.media.mediaText.includes('min-width: 1900px') || rule.media.mediaText.includes('min-width: 9999px'))) { rule.media.mediaText = state.buttons.wideLayout ? rule.media.mediaText.replace('9999px', '1900px') : rule.media.mediaText.replace('1900px', '9999px'); } }); } catch {} }); } // 樣式切換功能 function toggleStyleVisibility() { document.querySelectorAll(HIDDEN_STYLE_SELECTOR).forEach(el => { el.style.display = state.buttons.hideStyle ? 'none' : ''; }); } // 欄位佈局功能 function hasColumnCountCSS() { return getComputedStyle(document.documentElement).getPropertyValue('--column-count').trim() !== ''; } function applyColumnCount() { if (state.buttons.columns) { document.documentElement.style.setProperty('--column-count', state.COLUMN_COUNT); } } function adjustColumnCount(change) { state.COLUMN_COUNT = Math.max(1, state.COLUMN_COUNT + change); GM_setValue('COLUMN_COUNT', state.COLUMN_COUNT); state.buttons.columns && applyColumnCount(); } // 音量控制 function adjustVolume(change) { state.DEFAULT_VOLUME = Math.min(1, Math.max(0, state.DEFAULT_VOLUME + change)); GM_setValue('DEFAULT_VOLUME', state.DEFAULT_VOLUME); state.buttons.volume && processAllVideos(); } function processAllVideos() { const now = Date.now(); // 每5秒才重新查詢一次video元素 if (now - cachedElements.lastVideoCheck > 5000) { cachedElements.videoElements = document.querySelectorAll('video'); cachedElements.lastVideoCheck = now; } cachedElements.videoElements && cachedElements.videoElements.forEach(video => { try { if (typeof video.volume === 'number') { video.volume = state.DEFAULT_VOLUME; video.muted = false; } } catch {} }); } // 自動互動功能 const debouncedHandleOtherButtons = debounce(handleOtherButtons, 300); document.addEventListener('mouseover', function(event) { const target = event.target; if (state.buttons.seeMore && isSeeMoreButton(target) && checkClickInterval()) { safeClick(target); } }); function handleOtherButtons() { if (!state.buttons.otherExpand) return; document.querySelectorAll('div[role="button"]:not([aria-expanded="true"])').forEach(btn => { if (isOtherExpandButton(btn) && checkClickInterval()) { safeClick(btn); } }); } document.addEventListener('mouseover', function(event) { if (!state.buttons.like || state.likeCoolingDown) return; const target = event.target.closest('div[aria-label="讚"]'); if (target && target.getAttribute('aria-pressed') !== 'true' && isButtonVisible(target)) { state.likeCoolingDown = true; setTimeout(() => { state.likeCoolingDown = false; }, 1000); safeClick(target); } }); // 工具函數 function isSeeMoreButton(element) { return element?.getAttribute?.('role') === 'button' && element.getAttribute('aria-expanded') !== 'true' && element.textContent.trim() === '查看更多'; } function isOtherExpandButton(element) { const text = element?.textContent?.trim(); return text && text !== '查看更多' && (/^查看全部\d+則回覆$/.test(text) || /.+已回覆/.test(text) || /^查看 \d+ 則回覆$/.test(text)); } function checkClickInterval() { const now = Date.now(); if (now - state.lastClickTime > CLICK_INTERVAL) { state.lastClickTime = now; return true; } return false; } function safeClick(element) { element?.click?.(); } function isButtonVisible(button) { if (!button) return false; const rect = button.getBoundingClientRect(); return rect.width > 0 && rect.height > 0 && rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth); } function debounce(func, wait) { let timeout; return function() { const context = this, args = arguments; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } // 初始化 function init() { createControlPanel(); (state.buttons.seeMore || state.buttons.otherExpand) && setInterval(debouncedHandleOtherButtons, 800); const observer = new MutationObserver(() => { state.buttons.seeMore && state.buttons.otherExpand && handleOtherButtons(); state.buttons.volume && processAllVideos(); state.buttons.columns && applyColumnCount(); state.buttons.hideStyle && toggleStyleVisibility(); state.buttons.wideLayout !== undefined && toggleWideLayout(); }); observer.observe(document.body, { childList: true, subtree: true }); // 初始狀態應用 state.buttons.volume && processAllVideos(); state.buttons.columns && applyColumnCount(); state.buttons.hideStyle && toggleStyleVisibility(); state.buttons.wideLayout !== undefined && toggleWideLayout(); } // 啟動腳本 if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } })();