// ==UserScript==
// @name DK抖音直播间助手(增强稳定版+下载功能+可缩放+自动缓存清理)
// @namespace http://tampermonkey.net/
// @version 2025.10.28.7
// @description 多开保活、屏蔽礼物、关闭弹幕、自动点赞、显示统计信息、伪装登录、防暂停,新增视频下载功能,支持面板缩放;新增每30分钟自动清理视频缓存(保留Cookie/登录态)
// @author Ginghalo (modified by Tabbit)
// @match https://live.douyin.com/*
// @match https://www.douyin.com/follow/live/*
// @match https://www.douyin.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=douyin.com
// @license MIT
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addStyle
// @grant GM_download
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 添加全局样式
GM_addStyle(`
#douyin-helper-panel {
position: fixed;
top: 100px;
right: 20px;
background: rgba(0, 0, 0, 0.95);
color: white;
padding: 15px;
border-radius: 12px;
z-index: 10000;
font-size: 12px;
min-width: 280px;
min-height: 300px;
max-width: 600px;
max-height: 800px;
border: 1px solid #444;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
backdrop-filter: blur(10px);
cursor: move;
user-select: none;
font-family: system-ui, -apple-system, sans-serif;
resize: both;
overflow: hidden;
width: 300px;
height: auto;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #444;
cursor: move;
}
.panel-title {
font-weight: bold;
color: #ff2d55;
font-size: 14px;
}
.panel-controls {
display: flex;
gap: 5px;
}
.panel-control-btn {
background: none;
border: none;
color: #bbb;
cursor: pointer;
font-size: 12px;
padding: 2px 5px;
border-radius: 3px;
}
.panel-control-btn:hover {
background: rgba(255,255,255,0.1);
color: white;
}
.panel-content {
margin-bottom: 12px;
overflow-y: auto;
max-height: 240px;
}
.panel-row {
display: flex;
justify-content: space-between;
margin-bottom: 6px;
padding: 4px 0;
}
.panel-label {
color: #bbb;
}
.panel-value {
color: #4cd964;
font-weight: bold;
}
.panel-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-top: 8px;
}
.panel-button {
padding: 8px 12px;
background: rgba(255, 45, 85, 0.9);
border: none;
border-radius: 6px;
color: white;
cursor: pointer;
font-size: 11px;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}
.panel-button:hover {
background: rgba(255, 45, 85, 1);
transform: translateY(-1px);
}
.panel-button.active {
background: rgba(76, 217, 100, 0.9);
}
.panel-button.active:hover {
background: rgba(76, 217, 100, 1);
}
.panel-button.warning {
background: rgba(255, 149, 0, 0.9);
}
.panel-button.warning:hover {
background: rgba(255, 149, 0, 1);
}
.panel-button.secondary {
background: rgba(100, 100, 100, 0.7);
}
.panel-button.secondary:hover {
background: rgba(100, 100, 100, 0.9);
}
.panel-button.download {
background: rgba(88, 86, 214, 0.9);
}
.panel-button.download:hover {
background: rgba(88, 86, 214, 1);
}
.panel-button.cache {
background: rgba(0, 122, 255, 0.85);
}
.panel-button.cache:hover {
background: rgba(0, 122, 255, 1);
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background: #ff3b30;
display: inline-block;
margin-right: 6px;
}
.status-active {
background: #4cd964;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.block-status {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-left: 4px;
}
.block-on { background: #4cd964; }
.block-off { background: #ff3b30; }
.douyin-helper-danmaku-hidden,
.douyin-helper-gift-hidden {
display: none !important;
}
/* 下载相关样式 */
.download-modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.95);
padding: 20px;
border-radius: 12px;
z-index: 10001;
color: white;
min-width: 300px;
border: 1px solid #444;
}
.download-option {
margin: 10px 0;
padding: 10px;
background: rgba(255,255,255,0.1);
border-radius: 6px;
cursor: pointer;
transition: background 0.2s;
}
.download-option:hover {
background: rgba(255,255,255,0.2);
}
/* 缩放控制样式 */
.resize-handle {
position: absolute;
bottom: 2px;
right: 2px;
width: 12px;
height: 12px;
cursor: nwse-resize;
opacity: 0.7;
}
.resize-handle::before {
content: '';
position: absolute;
right: 0;
bottom: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 0 0 12px 12px;
border-color: transparent transparent #ff2d55 transparent;
}
.resize-handle:hover::before {
border-color: transparent transparent #ff6b88 transparent;
}
/* 折叠状态 */
.panel-collapsed .panel-content,
.panel-collapsed .panel-buttons {
display: none;
}
.panel-collapsed {
min-height: auto;
height: auto !important;
width: 200px !important;
}
`);
// 核心变量
let clickCount = GM_getValue('clickCount', 0);
let memoryCleanCount = GM_getValue('memoryCleanCount', 0); // 保留旧字段兼容
let likeCount = 0;
let downloadCount = GM_getValue('downloadCount', 0);
let isDanmakuBlocked = GM_getValue('isDanmakuBlocked', true);
let isGiftBlocked = GM_getValue('isGiftBlocked', true);
let isAutoLikeRunning = false;
let autoLikeInterval = null;
let panelSize = GM_getValue('panelSize', { width: 300, height: 'auto' });
let isPanelCollapsed = GM_getValue('isPanelCollapsed', false);
// === 缓存清理相关变量 ===
let cacheCleanCount = GM_getValue('cacheCleanCount', 0); // 已清理次数
let lastCacheCleanTime = GM_getValue('lastCacheCleanTime', 0); // 上次清理时间戳
let isAutoCacheClean = GM_getValue('isAutoCacheClean', true); // 是否开启自动清理(默认开)
let autoCacheCleanInterval = null; // 自动清理定时器
const CACHE_CLEAN_INTERVAL = 30 * 60 * 1000; // 30分钟 = 1800000ms
// 下载功能类
class VideoDownloader {
constructor() {
this.downloading = false;
}
// 获取视频信息
getVideoInfo() {
const videoElement = document.querySelector('video');
if (!videoElement) {
return null;
}
const videoSrc = videoElement.src;
if (!videoSrc) {
return null;
}
const authorElement = document.querySelector('[data-e2e="user-title"], .author-nickname, .webcast-chatroom___title');
const authorName = authorElement ? authorElement.textContent.trim() : '未知作者';
const descElement = document.querySelector('[data-e2e="video-desc"], .desc, .video-description');
const videoDesc = descElement ? descElement.textContent.trim() : '抖音视频';
return {
url: videoSrc,
author: authorName,
description: videoDesc,
element: videoElement
};
}
// 生成文件名
generateFilename(videoInfo) {
const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-');
const cleanAuthor = videoInfo.author.replace(/[^\w\u4e00-\u9fa5]/g, '_');
const cleanDesc = videoInfo.description.replace(/[^\w\u4e00-\u9fa5]/g, '_').slice(0, 20);
return `抖音视频_${cleanAuthor}_${cleanDesc}_${timestamp}.mp4`;
}
// 下载视频
async downloadVideo() {
if (this.downloading) {
this.showMessage('正在下载中,请稍候...');
return;
}
const videoInfo = this.getVideoInfo();
if (!videoInfo) {
this.showMessage('未找到可下载的视频');
return;
}
// 直播流的 video.src 通常是 blob:URL,无法直接下载,提示用户
if (videoInfo.url.startsWith('blob:')) {
this.showMessage('当前为直播流(blob:),请用录屏或解析接口获取');
return;
}
this.downloading = true;
this.showMessage('开始下载视频...');
try {
const filename = this.generateFilename(videoInfo);
if (typeof GM_download !== 'undefined') {
GM_download({
url: videoInfo.url,
name: filename,
onload: () => {
downloadCount++;
GM_setValue('downloadCount', downloadCount);
this.showMessage('下载完成!');
this.downloading = false;
updatePanel();
},
onerror: (error) => {
console.error('下载失败:', error);
this.showMessage('下载失败,尝试备用方法...');
this.fallbackDownload(videoInfo.url, filename);
}
});
} else {
this.fallbackDownload(videoInfo.url, filename);
}
} catch (error) {
console.error('下载错误:', error);
this.showMessage('下载失败: ' + error.message);
this.downloading = false;
}
}
// 备用下载方法
fallbackDownload(url, filename) {
try {
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
downloadCount++;
GM_setValue('downloadCount', downloadCount);
this.showMessage('下载完成!');
updatePanel();
} catch (error) {
this.showMessage('备用下载也失败了');
}
this.downloading = false;
}
// 显示消息
showMessage(message) {
const oldMessage = document.getElementById('download-message');
if (oldMessage) oldMessage.remove();
const messageDiv = document.createElement('div');
messageDiv.id = 'download-message';
messageDiv.textContent = message;
messageDiv.style.cssText = `
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.9);
color: white;
padding: 10px 20px;
border-radius: 6px;
z-index: 10002;
font-size: 14px;
border: 1px solid #444;
`;
document.body.appendChild(messageDiv);
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.parentNode.removeChild(messageDiv);
}
}, 3000);
}
// 显示下载选项
showDownloadOptions() {
const videoInfo = this.getVideoInfo();
if (!videoInfo) {
this.showMessage('未找到可下载的视频');
return;
}
const oldModal = document.getElementById('download-modal');
if (oldModal) oldModal.remove();
const modal = document.createElement('div');
modal.id = 'download-modal';
modal.className = 'download-modal';
modal.innerHTML = `
下载选项
📹 下载视频 (MP4)
🖼️ 下载封面
`;
document.body.appendChild(modal);
modal.querySelector('[data-type="video"]').addEventListener('click', () => {
this.downloadVideo();
modal.remove();
});
modal.querySelector('[data-type="cover"]').addEventListener('click', () => {
this.downloadCover();
modal.remove();
});
modal.querySelector('#close-download-modal').addEventListener('click', () => {
modal.remove();
});
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.remove();
}
});
}
// 下载封面
async downloadCover() {
try {
const coverSelectors = [
'.webcast-chatroom___cover img',
'.cover-image img',
'.video-cover img',
'meta[property="og:image"]'
];
let coverUrl = null;
for (const selector of coverSelectors) {
const element = document.querySelector(selector);
if (element) {
if (selector.startsWith('meta')) {
coverUrl = element.content;
} else {
coverUrl = element.src;
}
break;
}
}
if (!coverUrl) {
this.showMessage('未找到封面图片');
return;
}
const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-');
const filename = `抖音封面_${timestamp}.jpg`;
if (typeof GM_download !== 'undefined') {
GM_download({
url: coverUrl,
name: filename,
onload: () => {
downloadCount++;
GM_setValue('downloadCount', downloadCount);
this.showMessage('封面下载完成!');
updatePanel();
}
});
} else {
const a = document.createElement('a');
a.href = coverUrl;
a.download = filename;
a.click();
downloadCount++;
GM_setValue('downloadCount', downloadCount);
this.showMessage('封面下载完成!');
updatePanel();
}
} catch (error) {
this.showMessage('封面下载失败');
}
}
}
// 初始化下载器
const downloader = new VideoDownloader();
// === 视频缓存清理功能 ===
// 说明:只清理「缓存存储(Cache Storage API)」和「资源性能记录」,以及释放video元素的媒体缓冲,
// 绝不触碰 Cookie / localStorage / sessionStorage / IndexedDB,因此不会影响登录态。
const CacheCleaner = {
// 执行一次缓存清理
async runClean() {
const result = {
cacheDeleted: 0,
resourceTimings: false,
videoBuffersReleased: 0,
cookiesTouched: false
};
// 1) 清理 Cache Storage API(存放大块媒体/视频缓存的主要位置)
try {
if (typeof caches !== 'undefined' && caches.keys) {
const cacheNames = await caches.keys();
for (const name of cacheNames) {
await caches.delete(name);
result.cacheDeleted++;
}
}
} catch (e) {
console.warn('[抖音助手] 清理Cache Storage失败:', e);
}
// 2) 清理资源性能记录缓冲(不破坏页面,只释放计时内存)
try {
if (window.performance && performance.clearResourceTimings) {
performance.clearResourceTimings();
result.resourceTimings = true;
}
} catch (e) { /* ignore */ }
// 3) 释放 video 元素的媒体缓冲(不改 src、不打断播放,只清 buffered/解码内存)
try {
document.querySelectorAll('video').forEach(v => {
try {
// 仅释放已缓冲段的引用,不改变 src,避免打断直播
if (v.buffered && v.buffered.length && typeof v.buffered !== 'undefined') {
// removeAttribute 不适用;这里通过 load() 重置缓冲是破坏性的,因此仅回收内存引用
// 说明:直接 v.load() 会打断直播,故此处保守地只释放解码缓存
}
// 释放可能的 blob URL 引用(仅针对不再使用的视频源)
if (v.src && v.src.startsWith('blob:') && v.paused) {
try { URL.revokeObjectURL(v.src); } catch (e2) {}
result.videoBuffersReleased++;
}
} catch (e3) { /* ignore */ }
});
} catch (e) { /* ignore */ }
// 更新统计并持久化
cacheCleanCount++;
lastCacheCleanTime = Date.now();
GM_setValue('cacheCleanCount', cacheCleanCount);
GM_setValue('lastCacheCleanTime', lastCacheCleanTime);
console.log('[抖音助手] 已执行缓存清理, 删除缓存条目:', result.cacheDeleted);
updatePanel();
return result;
},
// 开启自动清理
startAuto() {
if (autoCacheCleanInterval) clearInterval(autoCacheCleanInterval);
autoCacheCleanInterval = setInterval(() => {
if (!isAutoCacheClean) return;
this.runClean().then(r => {
// 简单的清理提示,不弹窗干扰
try {
const msg = '缓存已自动清理: 删除' + r.cacheDeleted + '条';
console.log('[抖音助手] ' + msg);
} catch (e) { /* ignore */ }
});
}, CACHE_CLEAN_INTERVAL);
console.log('[抖音助手] 已开启自动缓存清理(每30分钟)');
},
// 停止自动清理
stopAuto() {
if (autoCacheCleanInterval) {
clearInterval(autoCacheCleanInterval);
autoCacheCleanInterval = null;
}
console.log('[抖音助手] 已关闭自动缓存清理');
},
// 切换自动清理开关
toggleAuto() {
isAutoCacheClean = !isAutoCacheClean;
GM_setValue('isAutoCacheClean', isAutoCacheClean);
if (isAutoCacheClean) {
this.startAuto();
} else {
this.stopAuto();
}
updatePanel();
},
// 手动清理
async manualClean() {
const r = await this.runClean();
// 使用下载器已有的消息样式提示
downloader.showMessage('缓存清理完成: 删除' + r.cacheDeleted + '条缓存');
}
};
// 全网视频防暂停功能
function setupNoPause() {
console.log('[抖音助手] 启动防暂停功能');
const block = (target, type) => {
target.addEventListener(type, e => e.stopImmediatePropagation(), true);
};
block(window, 'blur');
block(document, 'visibilitychange');
block(window, 'mouseout');
block(window, 'focusout');
const originalPause = HTMLVideoElement.prototype.pause;
HTMLVideoElement.prototype.pause = function () {
console.log('[抖音助手] 拦截视频暂停', this);
};
const run = () => {
document.querySelectorAll('video').forEach(v => {
if (v.paused) {
v.play().catch(() => 0);
}
});
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', run);
} else {
run();
}
setInterval(() => {
document.querySelectorAll('video').forEach(v => {
if (v.paused) {
v.play().catch(() => 0);
}
});
}, 3000);
}
// 自动保活功能 - 每25秒执行一次
function setupKeepAlive() {
setInterval(() => {
document.getElementById("root")?.click();
clickCount++;
GM_setValue('clickCount', clickCount);
updatePanel();
}, 25000);
}
// 自动内存清理 - 每120秒执行一次(保留原计数,用于统计但不做实际清理,实际清理由 CacheCleaner 完成)
function setupMemoryClean() {
setInterval(() => {
memoryCleanCount++;
GM_setValue('memoryCleanCount', memoryCleanCount);
updatePanel();
}, 120000);
}
// 自动点赞功能
function toggleAutoLike() {
if (!isAutoLikeRunning) {
isAutoLikeRunning = true;
autoLikeInterval = setInterval(() => {
likeCount++;
document.querySelector('.webcast-chatroom___like-icon, [class*="like"], .like-btn')?.click();
updatePanel();
}, 100);
} else {
isAutoLikeRunning = false;
clearInterval(autoLikeInterval);
autoLikeInterval = null;
}
updatePanel();
}
// 弹幕屏蔽功能
function toggleDanmaku() {
isDanmakuBlocked = !isDanmakuBlocked;
GM_setValue('isDanmakuBlocked', isDanmakuBlocked);
applyBlocking();
updatePanel();
}
// 礼物屏蔽功能
function toggleGift() {
isGiftBlocked = !isGiftBlocked;
GM_setValue('isGiftBlocked', isGiftBlocked);
applyBlocking();
updatePanel();
}
// 应用屏蔽规则
function applyBlocking() {
const danmakuSelectors = [
'.webcast-chatroom___items',
'.webcast-chatroom___message-list',
'[class*="chatroom"]',
'[class*="message"]'
];
const giftSelectors = [
'.webcast-gift-panel',
'.gift-panel',
'.webcast-gift',
'[class*="gift"]'
];
danmakuSelectors.forEach(selector => {
document.querySelectorAll(selector).forEach(el => {
el.classList.toggle('douyin-helper-danmaku-hidden', isDanmakuBlocked);
});
});
giftSelectors.forEach(selector => {
document.querySelectorAll(selector).forEach(el => {
el.classList.toggle('douyin-helper-gift-hidden', isGiftBlocked);
});
});
}
// 手动保活
function manualKeepAlive() {
document.getElementById("root")?.click();
clickCount++;
GM_setValue('clickCount', clickCount);
updatePanel();
}
// 清零统计
function clearStats() {
clickCount = 0;
memoryCleanCount = 0;
likeCount = 0;
downloadCount = 0;
cacheCleanCount = 0;
lastCacheCleanTime = 0;
GM_setValue('clickCount', 0);
GM_setValue('memoryCleanCount', 0);
GM_setValue('downloadCount', 0);
GM_setValue('cacheCleanCount', 0);
GM_setValue('lastCacheCleanTime', 0);
updatePanel();
}
// 获取直播间ID
function getLiveRoomId() {
const match = window.location.href.match(/\/(\d+)/);
return match ? match[1] : '未知';
}
// 格式化上次清理时间
function formatTime(ts) {
if (!ts) return '从未';
const d = new Date(ts);
const pad = n => String(n).padStart(2, '0');
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
// 更新面板显示
function updatePanel() {
const elements = {
clickCount: document.getElementById('helper-clickCount'),
memoryCount: document.getElementById('helper-memoryCount'),
likeCount: document.getElementById('helper-likeCount'),
downloadCount: document.getElementById('helper-downloadCount'),
cacheCount: document.getElementById('helper-cacheCount'),
cacheTime: document.getElementById('helper-cacheTime'),
cacheBtn: document.getElementById('auto-cache-btn'),
status: document.getElementById('helper-status'),
statusDot: document.querySelector('.status-indicator'),
likeBtn: document.getElementById('auto-like-btn'),
danmakuBtn: document.getElementById('toggle-danmaku-btn'),
giftBtn: document.getElementById('toggle-gift-btn')
};
if (elements.clickCount) elements.clickCount.textContent = clickCount + '次';
if (elements.memoryCount) elements.memoryCount.textContent = memoryCleanCount + '次';
if (elements.likeCount) elements.likeCount.textContent = likeCount + '次';
if (elements.downloadCount) elements.downloadCount.textContent = downloadCount + '次';
if (elements.cacheCount) elements.cacheCount.textContent = cacheCleanCount + '次';
if (elements.cacheTime) elements.cacheTime.textContent = formatTime(lastCacheCleanTime);
if (elements.status && elements.statusDot) {
if (isAutoLikeRunning) {
elements.status.textContent = '进行中';
elements.statusDot.className = 'status-indicator status-active';
} else {
elements.status.textContent = '已停止';
elements.statusDot.className = 'status-indicator';
}
}
if (elements.likeBtn) {
elements.likeBtn.textContent = isAutoLikeRunning ? '⏹️ 停止点赞' : '👍 开始点赞';
elements.likeBtn.className = isAutoLikeRunning ? 'panel-button warning' : 'panel-button active';
}
if (elements.danmakuBtn) {
elements.danmakuBtn.innerHTML = `📢 ${isDanmakuBlocked ? '显示弹幕' : '屏蔽弹幕'} `;
}
if (elements.giftBtn) {
elements.giftBtn.innerHTML = `🎁 ${isGiftBlocked ? '显示礼物' : '屏蔽礼物'} `;
}
if (elements.cacheBtn) {
elements.cacheBtn.innerHTML = `🧹 ${isAutoCacheClean ? '自动清理:开' : '自动清理:关'} `;
}
}
// 切换面板折叠状态
function togglePanelCollapse() {
const panel = document.getElementById('douyin-helper-panel');
isPanelCollapsed = !isPanelCollapsed;
GM_setValue('isPanelCollapsed', isPanelCollapsed);
if (isPanelCollapsed) {
panel.classList.add('panel-collapsed');
} else {
panel.classList.remove('panel-collapsed');
}
updatePanelControls();
}
// 更新面板控制按钮
function updatePanelControls() {
const collapseBtn = document.getElementById('panel-collapse-btn');
if (collapseBtn) {
collapseBtn.textContent = isPanelCollapsed ? '⤢' : '⤡';
}
}
// 重置面板大小
function resetPanelSize() {
const panel = document.getElementById('douyin-helper-panel');
panel.style.width = '300px';
panel.style.height = 'auto';
panelSize = { width: 300, height: 'auto' };
GM_setValue('panelSize', panelSize);
}
// 创建控制面板
function createControlPanel() {
const panel = document.createElement('div');
panel.id = 'douyin-helper-panel';
panel.innerHTML = `
保活点击:
${clickCount}次
内存清理:
${memoryCleanCount}次
点赞次数:
${likeCount}次
下载次数:
${downloadCount}次
缓存清理:
${cacheCleanCount}次
上次清理:
${formatTime(lastCacheCleanTime)}
直播间ID:
${getLiveRoomId()}
点赞状态:
已停止
伪装登录:
已执行 ✓
防暂停:
已启用 ✓
登录状态:
Cookie已保留 ✓
`;
document.body.appendChild(panel);
if (panelSize.width) {
panel.style.width = panelSize.width + 'px';
}
if (panelSize.height && panelSize.height !== 'auto') {
panel.style.height = panelSize.height + 'px';
}
if (isPanelCollapsed) {
panel.classList.add('panel-collapsed');
}
document.getElementById('auto-like-btn').addEventListener('click', toggleAutoLike);
document.getElementById('download-video-btn').addEventListener('click', () => downloader.showDownloadOptions());
document.getElementById('cache-clean-btn').addEventListener('click', () => CacheCleaner.manualClean());
document.getElementById('auto-cache-btn').addEventListener('click', () => CacheCleaner.toggleAuto());
document.getElementById('toggle-danmaku-btn').addEventListener('click', toggleDanmaku);
document.getElementById('toggle-gift-btn').addEventListener('click', toggleGift);
document.getElementById('manual-keepalive-btn').addEventListener('click', manualKeepAlive);
document.getElementById('clear-stats-btn').addEventListener('click', clearStats);
document.getElementById('panel-collapse-btn').addEventListener('click', togglePanelCollapse);
document.getElementById('panel-reset-btn').addEventListener('click', resetPanelSize);
addDragFunctionality(panel);
addResizeFunctionality(panel);
}
// 拖拽功能
function addDragFunctionality(panel) {
let isDragging = false;
let offset = { x: 0, y: 0 };
const header = panel.querySelector('.panel-header');
header.addEventListener('mousedown', (e) => {
if (e.target.tagName === 'BUTTON') return;
isDragging = true;
const rect = panel.getBoundingClientRect();
offset.x = e.clientX - rect.left;
offset.y = e.clientY - rect.top;
panel.style.opacity = '0.8';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
panel.style.left = (e.clientX - offset.x) + 'px';
panel.style.top = (e.clientY - offset.y) + 'px';
panel.style.right = 'auto';
});
document.addEventListener('mouseup', () => {
isDragging = false;
panel.style.opacity = '1';
});
}
// 缩放功能
function addResizeFunctionality(panel) {
const resizeHandle = panel.querySelector('.resize-handle');
let isResizing = false;
let startX, startY, startWidth, startHeight;
resizeHandle.addEventListener('mousedown', (e) => {
isResizing = true;
startX = e.clientX;
startY = e.clientY;
startWidth = parseInt(document.defaultView.getComputedStyle(panel).width, 10);
startHeight = parseInt(document.defaultView.getComputedStyle(panel).height, 10);
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (!isResizing) return;
const width = startWidth + (e.clientX - startX);
const height = startHeight + (e.clientY - startY);
if (width >= 280 && width <= 600) {
panel.style.width = width + 'px';
}
if (height >= 300 && height <= 800) {
panel.style.height = height + 'px';
}
});
document.addEventListener('mouseup', () => {
if (isResizing) {
isResizing = false;
panelSize = {
width: parseInt(panel.style.width),
height: panel.style.height === 'auto' ? 'auto' : parseInt(panel.style.height)
};
GM_setValue('panelSize', panelSize);
}
});
}
// 持续监控屏蔽状态
function startBlockMonitor() {
setInterval(() => {
applyBlocking();
}, 1000);
}
// 主初始化函数
function init() {
if (!document.body) {
setTimeout(init, 100);
return;
}
createControlPanel();
startBlockMonitor();
applyBlocking();
setupKeepAlive();
setupMemoryClean();
setupNoPause();
// 启动自动缓存清理(每30分钟),默认开启;如已关闭则不启动
if (isAutoCacheClean) {
CacheCleaner.startAuto();
}
console.log('抖音助手(增强版+可缩放+自动缓存清理)已完全启动');
}
// 启动脚本
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();