doufire 前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

723 lines
25 KiB

document.addEventListener('DOMContentLoaded', function() {
console.log('DOM 已加载完成');
// 获取所有需要的元素
const elements = {
usernameInput: document.getElementById('username'),
passwordInput: document.getElementById('password'),
liveIdInput: document.getElementById('liveId'),
openIncognitoButton: document.getElementById('openIncognito'),
openLiveButton: document.getElementById('openLive'),
loginButton: document.getElementById('login'),
userinfoElement: document.getElementById('userinfo'),
checkOnlineStatusButton: document.getElementById('checkOnlineStatus'),
liveRoomIdInput: document.getElementById('liveRoomId'),
openLiveRoomButton: document.getElementById('openLiveRoom'),
checkViewersButton: document.getElementById('checkViewers'),
liveRoomCountElement: document.getElementById('liveRoomCount'),
batchOpenIncognitoBtn: document.getElementById('batchOpenIncognito'),
incognitoCountInput: document.getElementById('incognitoCount'),
getCurrentRoomIdButton: document.getElementById('getCurrentRoomId'),
currentRoomIdElement: document.getElementById('currentRoomId'),
taskListTextarea: document.getElementById('taskList'),
saveTasksButton: document.getElementById('saveTasks'),
executeTasksButton: document.getElementById('executeTasks'),
taskStatusElement: document.getElementById('taskStatus'),
checkDuplicateRoomsButton: document.getElementById('checkDuplicateRooms'),
duplicateRoomsStatusElement: document.getElementById('duplicateRoomsStatus'),
proxyListTextarea: document.getElementById('proxyList'),
saveProxiesButton: document.getElementById('saveProxies'),
updateProxiesButton: document.getElementById('updateProxies'),
proxyStatusElement: document.getElementById('proxyStatus'),
clearProxyButton: document.getElementById('clearProxy'),
checkIncognito: document.getElementById('checkIncognito'),
checkCurrentProxy: document.getElementById('checkCurrentProxy'),
currentProxyStatus: document.getElementById('currentProxyStatus')
};
// 检查登录状态
chrome.storage.local.get(['loginStatus', 'loginInfo'], function(data) {
if (data.loginStatus && elements.userinfoElement) {
elements.userinfoElement.textContent = '已登录:' + data.loginInfo.uname;
}
});
// 批量打开无痕窗口
if (elements.batchOpenIncognitoBtn && elements.incognitoCountInput) {
elements.batchOpenIncognitoBtn.addEventListener('click', async () => {
const count = parseInt(elements.incognitoCountInput.value) || 1;
const actualCount = Math.min(Math.max(count, 1), 10);
for (let i = 0; i < actualCount; i++) {
await chrome.runtime.sendMessage({
action: 'openIncognitoDouyin',
username: elements.usernameInput ? elements.usernameInput.value : '',
password: elements.passwordInput ? elements.passwordInput.value : ''
});
await new Promise(resolve => setTimeout(resolve, 500));
}
});
}
// 打开单个无痕窗口
if (elements.openIncognitoButton) {
elements.openIncognitoButton.addEventListener('click', function() {
console.log('打开无痕窗口按钮被点击');
chrome.runtime.sendMessage({
action: 'openIncognitoDouyin',
username: elements.usernameInput ? elements.usernameInput.value : '',
password: elements.passwordInput ? elements.passwordInput.value : ''
});
});
}
// 打开直播间
if (elements.openLiveButton && elements.liveIdInput) {
elements.openLiveButton.addEventListener('click', () => {
console.log('打开直播间按钮被点击');
const liveId = elements.liveIdInput.value.trim();
if (liveId) {
const liveUrl = `https://live.douyin.com/${liveId}`;
chrome.runtime.sendMessage({ action: 'openLiveIncognito', url: liveUrl });
} else {
alert('请输入直播ID');
}
});
}
// 打开指定直播间
if (elements.openLiveRoomButton && elements.liveRoomIdInput) {
elements.openLiveRoomButton.addEventListener('click', function() {
console.log('打开指定直播间按钮被点击');
const liveRoomId = elements.liveRoomIdInput.value.trim();
if (liveRoomId) {
const liveRoomUrl = `https://live.douyin.com/${liveRoomId}`;
chrome.tabs.create({ url: liveRoomUrl });
} else {
alert('请输入直播间ID');
}
});
}
// 查看观众数量
if (elements.checkViewersButton) {
elements.checkViewersButton.addEventListener('click', async function() {
console.log('查看观众数量按钮被点击');
try {
const count = await getLiveRoomCount();
if (elements.liveRoomCountElement) {
elements.liveRoomCountElement.textContent = count ? `观众数量: ${count}` : '无法获取观众数量';
}
} catch (error) {
console.error('获取观众数量失败:', error);
alert('获取观众数量失败');
}
});
}
// 登录功能
if (elements.loginButton && elements.usernameInput && elements.passwordInput) {
elements.loginButton.addEventListener('click', function() {
const username = elements.usernameInput.value.trim();
const password = elements.passwordInput.value.trim();
if (!username || !password) {
alert('请输入账号和密码!');
return;
}
chrome.runtime.sendMessage({ action: 'login', username, password });
});
}
// 检查在线状态
if (elements.checkOnlineStatusButton) {
elements.checkOnlineStatusButton.addEventListener('click', function() {
injectContentScriptAndSendMessage('checkOnlineStatus');
});
}
// 获取当前直播间ID
if (elements.getCurrentRoomIdButton) {
elements.getCurrentRoomIdButton.addEventListener('click', async function() {
console.log('获取当前直播间ID按钮被点击');
try {
const tabs = await chrome.tabs.query({active: true, currentWindow: true});
if (!tabs[0]) {
throw new Error('未找到活动标签页');
}
const response = await chrome.tabs.sendMessage(tabs[0].id, {
action: 'getCurrentRoomId'
});
if (response && response.roomId) {
elements.currentRoomIdElement.textContent = `当前直播间ID: ${response.roomId}`;
// 可选:自动填充到输入框
if (elements.liveRoomIdInput) {
elements.liveRoomIdInput.value = response.roomId;
}
} else {
elements.currentRoomIdElement.textContent = '未能获取直播间ID';
}
} catch (error) {
console.error('获取直播间ID失败:', error);
alert('获取直播间ID失败,请确保您在抖音直播页');
}
});
}
// 加载保存的任务
chrome.storage.local.get(['tasks'], function(data) {
if (data.tasks && elements.taskListTextarea) {
elements.taskListTextarea.value = data.tasks.join('\n');
}
});
// 保存任务按钮
if (elements.saveTasksButton && elements.taskListTextarea) {
elements.saveTasksButton.addEventListener('click', function() {
const tasks = elements.taskListTextarea.value
.split('\n')
.map(task => task.trim())
.filter(task => task.length > 0)
.map(task => {
// 验证务格式
const parts = task.split('-');
if (parts.length !== 2) {
throw new Error(`任务格式错误: ${task}\n正确格式: 直播间ID-代理IP:端口`);
}
const [roomId, proxy] = parts;
if (!roomId || !proxy || !proxy.includes(':')) {
throw new Error(`任务格式错误: ${task}\n正确格式: 直播间ID-代理IP:端口`);
}
return task;
});
chrome.storage.local.set({ tasks: tasks }, function() {
if (elements.taskStatusElement) {
elements.taskStatusElement.textContent = `已存 ${tasks.length} 个任务`;
setTimeout(() => {
elements.taskStatusElement.textContent = '';
}, 2000);
}
});
});
}
// 执行任务按钮
if (elements.executeTasksButton) {
elements.executeTasksButton.addEventListener('click', async function() {
try {
const data = await chrome.storage.local.get(['tasks']);
const tasks = data.tasks || [];
if (tasks.length === 0) {
alert('没有可执行的任务');
return;
}
if (elements.taskStatusElement) {
elements.taskStatusElement.textContent = '开始执行任务...';
}
for (let i = 0; i < tasks.length; i++) {
const task = tasks[i];
if (elements.taskStatusElement) {
elements.taskStatusElement.textContent = `正在执行任务 ${i + 1}/${tasks.length}`;
}
// 这里执行具体任务
await executeTask(task);
// 任务之间添加延迟
await new Promise(resolve => setTimeout(resolve, 1000));
}
if (elements.taskStatusElement) {
elements.taskStatusElement.textContent = '所有任务执行完成';
setTimeout(() => {
elements.taskStatusElement.textContent = '';
}, 2000);
}
} catch (error) {
console.error('执行任务时出错:', error);
if (elements.taskStatusElement) {
elements.taskStatusElement.textContent = '执行任务时出错: ' + error.message;
}
}
});
}
// 修改检查重复直播间功能
if (elements.checkDuplicateRoomsButton) {
elements.checkDuplicateRoomsButton.addEventListener('click', async function() {
console.log('检查重复直播间按钮被点击');
try {
// 首先获取当前窗口
const currentWindow = await chrome.windows.getCurrent({
populate: true // 取窗中的所有标签页
});
// 只检��当前窗口中的标签页
const liveRooms = new Map(); // 存储直播间ID和第一次出现的标签页信息
const duplicates = new Map(); // 存储重复的直播间信息
// 遍历当前窗口的所有标签页
for (const tab of currentWindow.tabs) {
const match = tab.url.match(/live\.douyin\.com\/([^/?]+)/);
if (match) {
const roomId = match[1];
if (liveRooms.has(roomId)) {
// 发现重复,记录重复的标签页信息
if (!duplicates.has(roomId)) {
// 第一次发现重复,将原始标签页信息也加入到重复列表
duplicates.set(roomId, {
original: liveRooms.get(roomId),
duplicates: []
});
}
duplicates.get(roomId).duplicates.push({
tabId: tab.id,
url: tab.url
});
} else {
// 记录第一次出现的标签页信息
liveRooms.set(roomId, {
tabId: tab.id,
url: tab.url
});
}
}
}
// 显示结果并处理重复
if (elements.duplicateRoomsStatusElement) {
if (duplicates.size > 0) {
let message = '当前窗口发现并处理重复的直播间:\n';
// 处理每个重复的直播间
for (const [roomId, info] of duplicates) {
message += `房间ID ${roomId}:\n`;
message += `- 保留标签页 ${info.original.tabId}\n`;
// 关闭重复的标签页
for (const dupTab of info.duplicates) {
message += `- 关闭标签页 ${dupTab.tabId}\n`;
try {
await chrome.tabs.remove(dupTab.tabId);
} catch (error) {
console.error(`关闭标签页 ${dupTab.tabId} 失败:`, error);
}
}
// 切换到留的标签页
try {
await chrome.tabs.update(info.original.tabId, { active: true });
} catch (error) {
console.error(`切换到标签页 ${info.original.tabId} 失败:`, error);
}
}
elements.duplicateRoomsStatusElement.textContent = message;
} else {
elements.duplicateRoomsStatusElement.textContent = '当前窗口未发现重复的直播间';
}
// 5秒后清除状态信息
setTimeout(() => {
elements.duplicateRoomsStatusElement.textContent = '';
}, 5000);
}
} catch (error) {
console.error('检查重复直播间时出错:', error);
if (elements.duplicateRoomsStatusElement) {
elements.duplicateRoomsStatusElement.textContent = '检查失败: ' + error.message;
}
}
});
}
// 加载保存的代理列表
chrome.storage.local.get(['proxyList'], function(data) {
if (data.proxyList && elements.proxyListTextarea) {
elements.proxyListTextarea.value = data.proxyList.join('\n');
}
});
// 保存代理按钮
if (elements.saveProxiesButton && elements.proxyListTextarea) {
elements.saveProxiesButton.addEventListener('click', function() {
try {
const proxies = elements.proxyListTextarea.value
.split('\n')
.map(proxy => proxy.trim())
.filter(proxy => proxy.length > 0)
.map(proxy => {
// 验证代理格式
if (!validateProxy(proxy)) {
throw new Error(`代理格式错误: ${proxy}\n正确格式: IP:端口`);
}
return proxy;
});
chrome.storage.local.set({ proxyList: proxies }, function() {
if (elements.proxyStatusElement) {
elements.proxyStatusElement.textContent = `已保存 ${proxies.length} 个代理`;
setTimeout(() => {
elements.proxyStatusElement.textContent = '';
}, 2000);
}
});
} catch (error) {
console.error('保存代理时出错:', error);
if (elements.proxyStatusElement) {
elements.proxyStatusElement.textContent = error.message;
}
}
});
}
// 修改更新代理按钮的处理逻辑
if (elements.updateProxiesButton && elements.proxyListTextarea) {
elements.updateProxiesButton.addEventListener('click', async function() {
try {
// 获取代理列表
const proxyList = elements.proxyListTextarea.value
.split('\n')
.map(proxy => proxy.trim())
.filter(proxy => proxy.length > 0 && validateProxy(proxy))
.map(proxy => parseProxy(proxy)); // 解析代理字符串
if (proxyList.length === 0) {
throw new Error('没有可用的代理');
}
// 发送消息给background script,包含完整的代理列表
const response = await chrome.runtime.sendMessage({
action: 'setWindowProxy',
proxyList: proxyList
});
if (response.success) {
if (elements.proxyStatusElement) {
elements.proxyStatusElement.textContent = response.message;
setTimeout(() => {
elements.proxyStatusElement.textContent = '';
}, 3000);
}
} else {
throw new Error(response.error || '更新代理失败');
}
} catch (error) {
console.error('更新代理时出错:', error);
if (elements.proxyStatusElement) {
elements.proxyStatusElement.textContent = error.message;
setTimeout(() => {
elements.proxyStatusElement.textContent = '';
}, 3000);
}
}
});
}
// 添加清除代理按钮功能
if (elements.clearProxyButton) {
elements.clearProxyButton.addEventListener('click', async function() {
try {
// 发送消息给background script清除代理
await chrome.runtime.sendMessage({
action: 'clearProxy'
});
// 获取所有无痕窗口
const windows = await chrome.windows.getAll({
windowTypes: ['normal'],
populate: true
});
// 刷新所有无痕窗口的标签页
for (const window of windows) {
if (window.incognito) {
for (const tab of window.tabs) {
await chrome.tabs.reload(tab.id, { bypassCache: true });
// 添加短暂延迟,避免同时刷新太多标签页
await new Promise(resolve => setTimeout(resolve, 200));
}
}
}
if (elements.proxyStatusElement) {
elements.proxyStatusElement.textContent = '已清除所有代理设置';
setTimeout(() => {
elements.proxyStatusElement.textContent = '';
}, 3000);
}
} catch (error) {
console.error('清除代理时出错:', error);
if (elements.proxyStatusElement) {
elements.proxyStatusElement.textContent = '清除代理失败: ' + error.message;
setTimeout(() => {
elements.proxyStatusElement.textContent = '';
}, 3000);
}
}
});
}
// 检查无痕窗口数量
if (elements.checkIncognito) {
elements.checkIncognito.addEventListener('click', function() {
chrome.runtime.sendMessage({ action: 'checkIncognitoWindows' }, function(response) {
const statusDiv = document.getElementById('incognitoStatus');
if (response.count === 0) {
statusDiv.textContent = '当前没有无痕窗口';
} else {
statusDiv.textContent = `当前有 ${response.count} 个无痕窗口`;
// 可选:显示详细信息
const details = response.windows.map(w =>
`窗口ID: ${w.id}, 类型: ${w.type}, 标签数: ${w.tabCount}`
).join('\n');
console.log('无痕窗口详情:', details);
}
});
});
}
// 添加查看当前代理的功能
if (elements.checkCurrentProxy) {
elements.checkCurrentProxy.addEventListener('click', async function() {
try {
// 获取当前窗口
const currentWindow = await chrome.windows.getCurrent();
// 获取代理信息
const proxyInfo = await chrome.runtime.sendMessage({
action: 'getCurrentProxy',
windowId: currentWindow.id
});
// 显示代理信息
if (elements.currentProxyStatus) {
if (proxyInfo.success) {
if (proxyInfo.proxy) {
const proxyText = `当前窗口ID: ${currentWindow.id}\n` +
`代理服务器: ${proxyInfo.proxy.host}:${proxyInfo.proxy.port}\n` +
`用户名: ${proxyInfo.proxy.username}`;
elements.currentProxyStatus.textContent = proxyText;
} else {
elements.currentProxyStatus.textContent = '当前窗口未设置代理';
}
} else {
elements.currentProxyStatus.textContent = proxyInfo.error || '获取代理信息失败';
}
// 3秒后清除状态信息
setTimeout(() => {
elements.currentProxyStatus.textContent = '';
}, 3000);
}
} catch (error) {
console.error('查看代理信息失败:', error);
if (elements.currentProxyStatus) {
elements.currentProxyStatus.textContent = '查看代理信息失败: ' + error.message;
}
}
});
}
});
// 辅助函数:获取直播间人数
async function getLiveRoomCount() {
try {
const tabs = await chrome.tabs.query({active: true, currentWindow: true});
if (!tabs[0]) return null;
const response = await chrome.tabs.sendMessage(tabs[0].id, {action: "getLiveRoomCount"});
return response.count;
} catch (error) {
console.error("获取直播间人数失败:", error);
return null;
}
}
// 辅助函数:注入内容脚本并发送消息
function injectContentScriptAndSendMessage(action) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
if (!tabs[0]) {
alert('无法获取当前标签页');
return;
}
chrome.scripting.executeScript({
target: {tabId: tabs[0].id},
files: ['content.js']
}, function() {
if (chrome.runtime.lastError) {
console.error('注入脚本失败:', chrome.runtime.lastError);
return;
}
chrome.tabs.sendMessage(tabs[0].id, {action: action}, function(response) {
if (chrome.runtime.lastError) {
console.error('发送消息失败:', chrome.runtime.lastError);
return;
}
console.log('收到响应:', response);
});
});
});
}
// 监听登录结果
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.action === 'loginResult') {
const userinfoElement = document.getElementById('userinfo');
if (request.status === 'success' && userinfoElement) {
userinfoElement.textContent = '已登录:' + request.uname;
} else {
alert('登录失败:' + (request.message || '未知错误'));
}
}
});
// 修改执行任务的函数
async function executeTask(task) {
try {
// 解析任务字符串
const [roomId, proxyString] = task.split('-');
const [proxyHost, proxyPort] = proxyString.split(':');
// 验证数据
if (!roomId || !proxyHost || !proxyPort) {
throw new Error(`任务格式错误: ${task}`);
}
// 构建直播间URL
const liveUrl = `https://live.douyin.com/${roomId}`;
// 发送消息给background script,包含代理信息
await chrome.runtime.sendMessage({
action: 'openLiveWithProxy',
url: liveUrl,
proxy: {
host: proxyHost,
port: proxyPort
}
});
console.log(`已执行任务: 打开直播间 ${roomId}, 使用代理 ${proxyHost}:${proxyPort}`);
} catch (error) {
console.error(`执行任务 "${task}" 时出错:`, error);
throw error;
}
}
// 添加任务格式验证函数
function validateTask(task) {
const parts = task.split('-');
if (parts.length !== 2) return false;
const [roomId, proxy] = parts;
if (!roomId || !proxy) return false;
const [host, port] = proxy.split(':');
if (!host || !port) return false;
// 简单的IP格式验证
const isValidIp = host.split('.').length === 4 &&
host.split('.').every(num => {
const n = parseInt(num);
return !isNaN(n) && n >= 0 && n <= 255;
});
// 简单的端口验证
const isValidPort = !isNaN(parseInt(port)) &&
parseInt(port) > 0 &&
parseInt(port) <= 65535;
return isValidIp && isValidPort;
}
// 修改代理验证函数
function validateProxy(proxy) {
try {
// 移除 http:// 前缀(如果存在)
if (proxy.startsWith('http://')) {
proxy = proxy.substring(7);
}
let host, port;
if (proxy.includes('@')) {
// 带认证信息的格式
const [auth, address] = proxy.split('@');
// 验证认证信息
const [username, password] = auth.split(':');
if (!username || !password) return false;
[host, port] = address.split(':');
} else {
// 简单格式
[host, port] = proxy.split(':');
}
if (!host || !port) return false;
// 验证IP格式
const isValidIp = host.split('.').length === 4 &&
host.split('.').every(num => {
const n = parseInt(num);
return !isNaN(n) && n >= 0 && n <= 255;
});
// 验证端口
const isValidPort = !isNaN(parseInt(port)) &&
parseInt(port) > 0 &&
parseInt(port) <= 65535;
return isValidIp && isValidPort;
} catch (error) {
console.error('代理格式验证失败:', error);
return false;
}
}
// 修改代理解析函数
function parseProxy(proxyString) {
try {
// 处理完整的代理URL格式
if (proxyString.startsWith('http://')) {
// 移除 'http://' 前缀
proxyString = proxyString.substring(7);
}
let username = "", password = "", host = "", port = "";
if (proxyString.includes('@')) {
// 带认证信息的格式 username:password@host:port
const [auth, address] = proxyString.split('@');
[username, password] = auth.split(':');
[host, port] = address.split(':');
} else {
// 简单格式 host:port
[host, port] = proxyString.split(':');
}
if (!host || !port) {
throw new Error(`代理格式错误: ${proxyString}`);
}
return {
username,
password,
host,
port: parseInt(port)
};
} catch (error) {
console.error('解析代理字符串失败:', error);
throw new Error(`代理格式错误: ${proxyString}\n正确格式: http://username:password@host:port`);
}
}