您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动切换抖音到最高可用画质(4K>2K>1080P>720P),支持自定义检测时间间隔
// ==UserScript== // @name 抖音自动切换最高画质 // @namespace http://tampermonkey.net/ // @version 1.2 // @description 自动切换抖音到最高可用画质(4K>2K>1080P>720P),支持自定义检测时间间隔 // @author zpc5560 // @match *://*.douyin.com/* // @grant none // @icon http://www.missyuan.net/uploads/allimg/190118/11341Q918-11.jpg // ==/UserScript== (function() { 'use strict'; let isQualitySwitched = false; let currentQuality = null; let lastAttemptTime = 0; let currentVideoSrc = null; let currentTransformValue = 'translate3d(0px, 0px, 0px)'; const DEFAULT_CHECK_INTERVAL = 5 * 60 * 1000; // 默认5分钟 const MAX_CHECK_INTERVAL = 60 * 60 * 1000; // 最大1小时 let CHECK_INTERVAL = DEFAULT_CHECK_INTERVAL; let checkTimer = null; // 定义画质优先级 const qualityPriority = [ { name: '超清 4K', minHeight: 2160 }, { name: '超清 2K', minHeight: 1440 }, { name: '高清 1080P', minHeight: 1080 }, { name: '高清 720P', minHeight: 720 } ]; // 创建设置按钮 function createSettingsButton() { const button = document.createElement('button'); button.textContent = '设置检测间隔'; button.style.cssText = ` position: fixed; bottom: 90px; left: 20px; z-index: 999999; padding: 8px 12px; background-color: rgba(34, 34, 34, 0.9); color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transition: all 0.3s ease; `; button.addEventListener('click', showSettingsDialog); document.body.appendChild(button); } // 显示设置对话框 function showSettingsDialog() { const dialog = document.createElement('div'); dialog.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); z-index: 10000; min-width: 300px; `; const currentInterval = CHECK_INTERVAL / 1000; const minutes = Math.floor(currentInterval / 60); const seconds = currentInterval % 60; dialog.innerHTML = ` <h3 style="margin: 0 0 15px 0; color: #333;">设置检测间隔</h3> <div style="margin-bottom: 15px;"> <label style="display: inline-block; width: 50px; color: #666;">分钟:</label> <input type="number" id="minutes" value="${minutes}" min="0" max="60" style="width: 60px; padding: 4px;"> </div> <div style="margin-bottom: 15px;"> <label style="display: inline-block; width: 50px; color: #666;">秒钟:</label> <input type="number" id="seconds" value="${seconds}" min="0" max="59" style="width: 60px; padding: 4px;"> </div> <div style="color: #666; font-size: 12px; margin-bottom: 15px;"> 注意:总时间不能超过1小时 </div> <div style="text-align: right;"> <button id="cancelBtn" style="margin-right: 10px; padding: 6px 12px; background: #f5f5f5; border: 1px solid #ddd; border-radius: 4px; cursor: pointer;">取消</button> <button id="saveBtn" style="padding: 6px 12px; background: #1890ff; color: white; border: none; border-radius: 4px; cursor: pointer;">保存</button> </div> `; document.body.appendChild(dialog); const minutesInput = dialog.querySelector('#minutes'); const secondsInput = dialog.querySelector('#seconds'); const saveBtn = dialog.querySelector('#saveBtn'); const cancelBtn = dialog.querySelector('#cancelBtn'); // 保存设置 saveBtn.addEventListener('click', () => { const minutes = parseInt(minutesInput.value) || 0; const seconds = parseInt(secondsInput.value) || 0; const totalSeconds = minutes * 60 + seconds; if (totalSeconds === 0) { alert('检测间隔不能为0'); return; } if (totalSeconds > 3600) { alert('检测间隔不能超过1小时'); return; } CHECK_INTERVAL = totalSeconds * 1000; localStorage.setItem('douyinQualityCheckInterval', CHECK_INTERVAL.toString()); resetState(); document.body.removeChild(dialog); }); // 取消设置 cancelBtn.addEventListener('click', () => { document.body.removeChild(dialog); }); } // 获取当前选中的画质 function getCurrentQuality() { const selectedItem = document.querySelector('.virtual .item.selected'); return selectedItem ? selectedItem.textContent.trim() : null; } // 移除悬停效果 function removeHoverEffect() { const mouseOutEvent = new MouseEvent('mouseout', { bubbles: true, cancelable: true, view: window }); const qualityButton = document.querySelector('.gear.isSmoothSwitchClarityLogin'); if (qualityButton) { qualityButton.dispatchEvent(mouseOutEvent); } } // 检查画质是否需要切换 function checkQualityNeedsSwitch() { const currentSelectedQuality = getCurrentQuality(); const currentTime = Date.now(); if (!currentQuality || currentSelectedQuality !== currentQuality || currentTime - lastAttemptTime >= CHECK_INTERVAL) { isQualitySwitched = false; switchToHighQuality(); } } // 检查视频源是否更改 function checkVideoSourceChanged() { const videoElement = document.querySelector('video'); const transformElement = document.querySelector('.kkbhJDRa.MvotIm_G'); if (videoElement && transformElement) { const newVideoSrc = videoElement.src; const newTransformValue = transformElement.style.transform; if (newVideoSrc !== currentVideoSrc || newTransformValue !== currentTransformValue) { currentVideoSrc = newVideoSrc; currentTransformValue = newTransformValue; isQualitySwitched = false; switchToHighQuality(); } } } function switchToHighQuality() { if (isQualitySwitched) return; const qualityButton = document.querySelector('.gear.isSmoothSwitchClarityLogin'); if (qualityButton) { const mouseOverEvent = new MouseEvent('mouseover', { bubbles: true, cancelable: true, view: window }); qualityButton.dispatchEvent(mouseOverEvent); setTimeout(() => { const qualityOptions = Array.from(document.querySelectorAll('.virtual .item')); let selectedOption = null; for (const quality of qualityPriority) { const option = qualityOptions.find(opt => opt.textContent.includes(quality.name) ); if (option) { selectedOption = option; break; } } if (selectedOption) { selectedOption.click(); currentQuality = selectedOption.textContent.trim(); lastAttemptTime = Date.now(); console.log(`已切换到${currentQuality}画质`); isQualitySwitched = true; startQualityCheck(); } else { const smartOption = qualityOptions.find(opt => opt.textContent.includes('智能') ); if (smartOption) { smartOption.click(); currentQuality = '智能'; lastAttemptTime = Date.now(); console.log('未找到720P或更高画质,暂时切换到智能画质'); isQualitySwitched = true; startQualityCheck(); } } setTimeout(removeHoverEffect, 100); }, 500); } else { console.log('画质选择按钮未找到'); } } // 启动定时检测 function startQualityCheck() { if (checkTimer) { clearInterval(checkTimer); } checkTimer = setInterval(() => { console.log('定时检测视频源中...'); checkVideoSourceChanged(); }, CHECK_INTERVAL); } // 停止定时检测 function stopQualityCheck() { if (checkTimer) { clearInterval(checkTimer); checkTimer = null; } } // 使用 MutationObserver 监听页面变化 const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.type === 'childList' || mutation.type === 'attributes') { const videoElement = document.querySelector('video'); const transformElement = document.querySelector('.kkbhJDRa.MvotIm_G'); if (videoElement && transformElement && !isQualitySwitched) { checkVideoSourceChanged(); } } }); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true }); // 在页面切换时重置状态 function resetState() { isQualitySwitched = false; currentQuality = null; lastAttemptTime = 0; currentVideoSrc = null; currentTransformValue = 'translate3d(0px, 0px, 0px)'; stopQualityCheck(); startQualityCheck(); } // 初始化检测间隔 function initCheckInterval() { const savedInterval = localStorage.getItem('douyinQualityCheckInterval'); if (savedInterval) { const interval = parseInt(savedInterval); if (!isNaN(interval) && interval > 0 && interval <= MAX_CHECK_INTERVAL) { CHECK_INTERVAL = interval; } } } window.addEventListener('urlchange', resetState); window.addEventListener('load', () => { initCheckInterval(); createSettingsButton(); resetState(); switchToHighQuality(); }); window.addEventListener('unload', () => { stopQualityCheck(); }); // 初始启动 setTimeout(() => { initCheckInterval(); createSettingsButton(); resetState(); }, 1000); })();