Browse Source

成功 1 版

torsen
TorsenLi 1 year ago
parent
commit
6932b720df
  1. 7
      douyin/.cursor-tutor.code-workspace
  2. 442
      douyin/background.js
  3. 55
      douyin/content.js
  4. 21
      douyin/manifest.json
  5. 134
      douyin/popup.html
  6. 674
      douyin/popup.js

7
douyin/.cursor-tutor.code-workspace

@ -0,0 +1,7 @@
{
"folders": [
{
"path": "."
}
]
}

442
douyin/background.js

@ -4,33 +4,193 @@ chrome.runtime.onInstalled.addListener(() => {
console.log("抖音扩展已安装");
});
// 添加代理可用性检测函数
async function checkProxyAvailability(proxyConfig) {
return new Promise((resolve) => {
const timeoutDuration = 10000; // 增加超时时间到10秒
console.log(`正在测试代理 ${proxyConfig.host}:${proxyConfig.port} 的可用性...`);
// 使用 XMLHttpRequest 来测试代理
const xhr = new XMLHttpRequest();
xhr.timeout = timeoutDuration;
// 设置超时处理
const timeoutHandler = setTimeout(() => {
xhr.abort();
console.log(`代理 ${proxyConfig.host}:${proxyConfig.port} 测试超时`);
resolve(false);
}, timeoutDuration);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
clearTimeout(timeoutHandler);
if (xhr.status === 200) {
console.log(`代理 ${proxyConfig.host}:${proxyConfig.port} 测试成功`);
resolve(true);
} else {
console.log(`代理 ${proxyConfig.host}:${proxyConfig.port} 测试失败,状态码: ${xhr.status}`);
resolve(false);
}
}
};
xhr.onerror = function() {
clearTimeout(timeoutHandler);
console.log(`代理 ${proxyConfig.host}:${proxyConfig.port} 连接错误`);
resolve(false);
};
try {
// 使用 HTTPS 测试
xhr.open('GET', 'https://www.douyin.com/favicon.ico', true);
xhr.send();
} catch (error) {
clearTimeout(timeoutHandler);
console.error(`代理测试出错:`, error);
resolve(false);
}
});
}
// 添加一个全局变量来存储每个窗口的代理设置
const windowProxyMap = new Map();
// 修改代理设置函数
function setProxyForWindow(proxyConfig, windowId, callback) {
const maxRetries = 3;
let retryCount = 0;
function trySetProxy() {
console.log(`窗口 ${windowId} 设置代理尝试 ${retryCount + 1}/${maxRetries}:`, proxyConfig);
// 存储当前窗口的代理设置
windowProxyMap.set(windowId, proxyConfig);
// 设置新的代理
const config = {
value: {
mode: "fixed_servers",
rules: {
singleProxy: {
scheme: "http",
host: proxyConfig.host,
port: parseInt(proxyConfig.port)
},
bypassList: [
"localhost",
"127.0.0.1",
"<local>"
]
}
},
scope: "regular"
};
chrome.proxy.settings.set(
config,
function() {
if (chrome.runtime.lastError) {
console.error('设置代理失败:', chrome.runtime.lastError);
handleError(chrome.runtime.lastError);
return;
}
// 验证代理设置
chrome.proxy.settings.get(
{ incognito: false },
function(config) {
console.log(`窗口 ${windowId} 当前代理配置:`, config);
if (config.value.mode === "fixed_servers") {
// 只刷新当前窗口的标签页
chrome.tabs.query({ windowId: windowId }, function(tabs) {
let refreshedCount = 0;
if (tabs.length === 0) {
callback(null, true);
return;
}
tabs.forEach(function(tab) {
chrome.tabs.reload(tab.id, { bypassCache: true }, function() {
refreshedCount++;
if (refreshedCount === tabs.length) {
callback(null, true);
}
});
});
});
} else {
handleError(new Error('代理设置验证失败'));
}
}
);
}
);
}
function handleError(error) {
if (retryCount < maxRetries - 1) {
retryCount++;
setTimeout(trySetProxy, 2000);
} else {
callback(error);
}
}
trySetProxy();
}
// 消息监听器
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'checkIncognitoWindows') {
chrome.windows.getAll({ populate: true }, (windows) => {
console.log('获取到所有窗口数量:', windows.length);
const incognitoWindows = windows.filter(w => w.incognito);
console.log('找到无痕窗口数量:', incognitoWindows.length);
const windowDetails = incognitoWindows.map(w => ({
id: w.id,
type: w.type,
state: w.state,
tabCount: w.tabs ? w.tabs.length : 0,
firstTabUrl: w.tabs && w.tabs[0] ? w.tabs[0].url : 'no tabs'
}));
console.log('无痕窗口详情:', windowDetails);
sendResponse({
count: incognitoWindows.length,
windows: windowDetails,
allWindowsCount: windows.length,
timestamp: new Date().toISOString()
});
});
return true;
}
if (request.action === 'openIncognitoDouyin') {
chrome.windows.create({
incognito: true,
url: "https://www.douyin.com"
}, function(window) {
console.log('抖音隐身窗口已打开');
// 这里可以添加自动登录的逻辑
console.log('抖音无痕窗口已打开');
});
} else if (request.action === 'openLiveIncognito') {
chrome.windows.create({
incognito: true,
url: request.url
}, function(window) {
console.log('直播隐身窗口已打开');
console.log('直播无痕窗口已打开');
});
}
//执行登录
if (request.action === 'login') {
console.log('收到登录请求');
// 登录数据
const loginData = {
uname: request.username,
upass: request.password
};
// 在这里处理登录逻辑
fetch('https://douyin.xingtongworld.com/api/passport/login?t=crx', {
method: 'POST',
headers: {
@ -42,18 +202,11 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
.then(data => {
console.log('登录结果:', data);
if (data.status === 200) {
// 这里可以添加登录成功后的操作
sendResponse({ status: 'success' });
// 保存登录状态
chrome.storage.local.set({ loginStatus: true });
// 保存登录信息
chrome.storage.local.set({ loginStatus: true });
chrome.storage.local.set({ loginInfo: loginData });
// 保存登录时间
chrome.storage.local.set({ loginTime: new Date().toLocaleString() });
// 保存登录token
chrome.storage.local.set({ loginTime: new Date().toLocaleString() });
chrome.storage.local.set({ loginToken: data.token });
// 保存登录cookie
chrome.cookies.set({
url: 'https://douyin.xingtongworld.com',
name: 'sessionid',
@ -70,11 +223,264 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
});
}
// 添加状态检查功能
if (request.action === 'checkStatus') {
// 执行状态检查的逻辑
// 这里只是一个示例,您需要根据实际需求实现检查逻辑
let status = '正常';
sendResponse({status: status});
}
if (request.action === 'openLiveWithProxy') {
chrome.windows.create({
url: request.url,
incognito: true,
type: 'normal'
}, (window) => {
if (window) {
// 等待窗口创建完成后再设置代理
setTimeout(() => {
setProxyForWindow(
request.proxy,
window.id,
(error, success) => {
if (error) {
console.error('设置代理失败:', error);
sendResponse({ success: false, error: error.message });
} else {
console.log('代理已设置到新创建的无痕窗口');
sendResponse({ success: true });
}
}
);
}, 1000);
} else {
console.error('创建窗口失败');
sendResponse({ success: false, error: '创建窗口失败' });
}
});
return true;
}
if (request.action === 'setWindowProxy') {
chrome.windows.getAll({ populate: true }, (windows) => {
const incognitoWindows = windows.filter(w => w.incognito);
if (incognitoWindows.length > 0) {
const proxyList = request.proxyList;
console.log('可用代理列表:', proxyList);
if (proxyList.length < incognitoWindows.length) {
sendResponse({
success: false,
error: `代理数量不足,需要 ${incognitoWindows.length} 个代理,但只有 ${proxyList.length}`
});
return;
}
let completedCount = 0;
let errors = [];
// 为每个窗口单独设置代理
incognitoWindows.forEach((window, index) => {
const proxy = proxyList[index];
const [host, port] = proxy.split(':');
if (!host || !port) {
errors.push(`代理格式错误: ${proxy}`);
completedCount++;
checkComplete();
return;
}
// 为每个窗口设置代理时先激活该窗口
chrome.windows.update(window.id, { focused: true }, () => {
setTimeout(() => {
setProxyForWindow(
{ host, port: parseInt(port) },
window.id,
(error, success) => {
if (error) {
errors.push(`窗口 ${window.id} 设置代理失败: ${error.message}`);
}
completedCount++;
checkComplete();
}
);
}, index * 3000); // 每个窗口间隔3秒
});
});
function checkComplete() {
if (completedCount === incognitoWindows.length) {
if (errors.length > 0) {
sendResponse({
success: false,
error: errors.join('\n')
});
} else {
sendResponse({
success: true,
message: `已为 ${incognitoWindows.length} 个无痕窗口设置独立代理`
});
}
}
}
} else {
sendResponse({ success: false, error: '未找到无痕窗��' });
}
});
return true;
}
if (request.action === 'clearProxy') {
chrome.proxy.settings.clear(
{
scope: "regular"
},
() => {
if (chrome.runtime.lastError) {
console.error('清除代理失败:', chrome.runtime.lastError);
sendResponse({ success: false, error: chrome.runtime.lastError.message });
} else {
console.log('代理设置已完全清除');
sendResponse({ success: true });
}
}
);
return true;
}
chrome.webRequest.onCompleted.addListener(
function(details) {
console.log("请求完成:", details);
},
{urls: ["<all_urls>"]}
);
});
chrome.windows.onCreated.addListener((window) => {
console.log('新窗口创建:', {
id: window.id,
incognito: window.incognito,
type: window.type,
state: window.state,
alwaysOnTop: window.alwaysOnTop,
focused: window.focused,
timestamp: new Date().toISOString()
});
});
chrome.tabs.onCreated.addListener((tab) => {
console.log('新标签创建:', {
id: tab.id,
windowId: tab.windowId,
url: tab.url
});
});
// 修改错误监听器,添加更多需要忽略的错误类型
chrome.webRequest.onErrorOccurred.addListener(
function(details) {
// 扩展需要忽略的错误类型列表
const ignoredErrors = [
'net::ERR_ABORTED', // 请求中断
'net::ERR_NETWORK_CHANGED', // 网络变化
'net::ERR_CONNECTION_CLOSED', // 连接关闭
'net::ERR_CACHE_MISS', // 缓存未命中
'net::ERR_EMPTY_RESPONSE', // 空响应
'net::ERR_FAILED', // 一般性失败
'net::ERR_TIMED_OUT' // 超时
];
// 忽略的资源类型
const ignoredResourceTypes = [
'font', // 字体文件
'image', // 图片
'media', // 媒体文件
'stylesheet', // CSS文件
'other' // 其他资源
];
if (details.error &&
!ignoredErrors.includes(details.error) &&
!ignoredResourceTypes.includes(details.type)) {
// 只记录重要的错误
const errorInfo = {
错误类型: details.error,
URL: details.url,
时间: new Date(details.timeStamp).toLocaleString(),
标签页ID: details.tabId,
请求类型: details.type
};
// 如果是代理相关错误,添加更多信息
if (details.error.toLowerCase().includes('proxy') ||
details.error.toLowerCase().includes('connection_refused')) {
errorInfo.代理错误 = true;
errorInfo.IP地址 = details.ip || '未知';
console.error('代理相关错误:\n' +
Object.entries(errorInfo)
.map(([key, value]) => `${key}: ${value}`)
.join('\n')
);
} else if (details.error.toLowerCase().includes('cert')) {
// 证书相关错误
console.warn('证书相关错误:\n' +
Object.entries(errorInfo)
.map(([key, value]) => `${key}: ${value}`)
.join('\n')
);
} else {
// 其他重要错误
console.error('重要网络错误:\n' +
Object.entries(errorInfo)
.map(([key, value]) => `${key}: ${value}`)
.join('\n')
);
}
}
},
{urls: ["<all_urls>"]}
);
chrome.windows.onRemoved.addListener((windowId) => {
console.log('窗口被关闭:', {
id: windowId,
timestamp: new Date().toISOString()
});
});
chrome.windows.onFocusChanged.addListener((windowId) => {
if (windowId !== chrome.windows.WINDOW_ID_NONE) {
console.log('窗口点改变:', windowId);
}
});
// 添加窗口焦点变化监听器
chrome.windows.onFocusChanged.addListener((windowId) => {
if (windowId !== chrome.windows.WINDOW_ID_NONE) {
const proxyConfig = windowProxyMap.get(windowId);
if (proxyConfig) {
console.log(`窗口 ${windowId} 获得焦点,恢复其代理设置:`, proxyConfig);
chrome.proxy.settings.set({
value: {
mode: "fixed_servers",
rules: {
singleProxy: {
scheme: "http",
host: proxyConfig.host,
port: parseInt(proxyConfig.port)
},
bypassList: ["localhost", "127.0.0.1", "<local>"]
}
},
scope: "regular"
});
}
}
});
// 添加窗口关闭监听器
chrome.windows.onRemoved.addListener((windowId) => {
console.log(`窗口 ${windowId} 被关闭,移除其代理设置`);
windowProxyMap.delete(windowId);
});

55
douyin/content.js

@ -0,0 +1,55 @@
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log('收到消息:', request);
if (request.action === 'checkOnlineStatus') {
const isDouyin = window.location.hostname.includes('douyin.com');
sendResponse({isDouyin: isDouyin});
} else if (request.action === 'checkViewers') {
const viewersCounts = [];
const liveRooms = document.querySelectorAll('[data-e2e="user-card"]');
liveRooms.forEach(room => {
const viewersElement = room.querySelector('[data-e2e="watch-count"]');
if (viewersElement) {
const viewersText = viewersElement.textContent.trim();
const viewers = parseViewersCount(viewersText);
const roomTitle = room.querySelector('[data-e2e="video-title"]')?.textContent.trim() || '未知直播间';
viewersCounts.push({ room: roomTitle, viewers: viewers });
}
});
sendResponse({viewersCounts: viewersCounts});
} else if (request.action === 'getCurrentRoomId') {
try {
const url = window.location.href;
const match = url.match(/live\.douyin\.com\/([^/?]+)/);
if (match && match[1]) {
sendResponse({ roomId: match[1] });
} else {
const roomIdElement = document.querySelector('[data-room-id]');
if (roomIdElement) {
sendResponse({ roomId: roomIdElement.getAttribute('data-room-id') });
} else {
sendResponse({ error: '未找到直播间ID' });
}
}
} catch (error) {
console.error('获取直播间ID时出错:', error);
sendResponse({ error: error.message });
}
return true; // 保持消息通道开启
}
return true; // 保持消息通道开放
});
function parseViewersCount(viewersText) {
const number = parseFloat(viewersText.replace(/[^0-9.]/g, ''));
const unit = viewersText.replace(/[0-9.]/g, '').trim();
switch(unit) {
case '万':
return number * 10000;
case '亿':
return number * 100000000;
default:
return number;
}
}
console.log('内容脚本已加载');

21
douyin/manifest.json

@ -7,15 +7,28 @@
"tabs",
"storage",
"windows",
"cookies"
"cookies",
"scripting",
"proxy",
"webRequest"
],
"host_permissions": [
"https://douyin.xingtongworld.com/"
"https://douyin.xingtongworld.com/*",
"https://*.douyin.com/*",
"https://api64.ipify.org/*",
"<all_urls>"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
}
}
},
"content_scripts": [
{
"matches": ["*://*.douyin.com/*"],
"js": ["content.js"]
}
],
"incognito": "spanning"
}

134
douyin/popup.html

@ -2,43 +2,121 @@
<html>
<head>
<meta charset="UTF-8">
<title>抖音圣火</title>
<title>抖音助手</title>
<style>
body {
width: 200px;
width: 390px;
padding: 10px;
}
input, button {
width: 100%;
margin-top: 5px;
.input-group {
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 10px;
}
input {
padding: 5px;
width: 100px;
}
button {
padding: 8px 15px;
margin: 5px 0;
width: 100%;
background-color: #1890ff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
label {
display: block;
margin-top: 10px;
font-weight: bold;
button:hover {
background-color: #40a9ff;
}
.section {
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
</style>
</head>
<body>
<span class="userinfo" id="userinfo"></span>
<label for="username">账号:</label>
<input type="text" id="username" placeholder="输入账号">
<label for="password">密码:</label>
<input type="password" id="password" placeholder="输入密码">
<button id="login">登录</button>
<button id="openIncognito">打开抖音隐身窗口</button>
<label for="liveId">直播间ID:</label>
<input type="text" id="liveId" placeholder="输入直播间ID">
<button id="openLive">打开直播窗口</button>
<!-- 无痕模式窗口部分 -->
<div class="section">
<div class="input-group">
<label>无痕窗口数量:</label>
<input type="number" id="incognitoCount" min="1" max="10" value="1">
</div>
<button id="batchOpenIncognito">批量打开无痕窗口</button>
<button id="openIncognito">打开单个无痕窗口</button>
</div>
<!-- 直播间部分 -->
<div class="section">
<div class="input-group">
<label>直播间ID:</label>
<input type="text" id="liveId" placeholder="输入直播ID">
</div>
<button id="openLive">打开直播窗口</button>
</div>
<!-- 登录部分 -->
<div class="section">
<div class="input-group">
<label>用户名:</label>
<input type="text" id="username" placeholder="输入用户名">
</div>
<div class="input-group">
<label>密码:</label>
<input type="password" id="password" placeholder="输入密码">
</div>
<button id="login">登录</button>
<div id="userinfo"></div>
</div>
<!-- 直播间管理部分 -->
<div class="section">
<div class="input-group">
<label>房间ID:</label>
<input type="text" id="liveRoomId" placeholder="输入房间ID">
</div>
<button id="openLiveRoom">打开指定直播间</button>
<button id="getCurrentRoomId">获取当前直播间ID</button>
<button id="checkDuplicateRooms">检查重复直播间</button>
<button id="checkViewers">查看观众数量</button>
<div id="liveRoomCount"></div>
<div id="currentRoomId"></div>
<div id="duplicateRoomsStatus"></div>
</div>
<!-- 代理管理部分 -->
<div class="section">
<div class="input-group">
<label>代理IP列表:</label>
<textarea id="proxyList" placeholder="格式:IP:端口&#10;例如:192.168.1.1:8080" rows="5" style="width: 100%; margin-bottom: 10px;"></textarea>
</div>
<button id="saveProxies">保存代理</button>
<button id="updateProxies">更新代理</button>
<button id="clearProxy">清除代理</button>
<div id="proxyStatus"></div>
</div>
<!-- 任务管理部分 -->
<div class="section">
<div class="input-group">
<label>任务列表:</label>
<textarea id="taskList" placeholder="格式:直播间ID-代理IP:端口&#10;例如:123456-192.168.1.1:8080" rows="5" style="width: 100%; margin-bottom: 10px;"></textarea>
</div>
<button id="saveTasks">保存任务</button>
<button id="executeTasks">执行任务</button>
<div id="taskStatus"></div>
</div>
<!-- 状态检查部分 -->
<button id="checkOnlineStatus">检查在线状态</button>
<button id="checkButton">检查状态</button>
<button id="checkIncognito">检查无痕窗口</button>
<div id="incognitoStatus"></div>
<script src="popup.js"></script>
</body>
</html>
</html>

674
douyin/popup.js

@ -1,113 +1,530 @@
// 将所有的 DOM 操作移到 DOMContentLoaded 事件监听器内部
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM 已加载完成');
var usernameInput = document.getElementById('username');
var passwordInput = document.getElementById('password');
var liveIdInput = document.getElementById('liveId');
const openIncognitoButton = document.getElementById('openIncognito');
const openLiveButton = document.getElementById('openLive');
const loginButton = document.getElementById('login');
const checkButton = document.getElementById('checkButton');
const userinfoElement = document.getElementById('userinfo');
console.log('元素检查:',
'usernameInput:', !!usernameInput,
'passwordInput:', !!passwordInput,
'liveIdInput:', !!liveIdInput,
'openIncognitoButton:', !!openIncognitoButton,
'openLiveButton:', !!openLiveButton,
'loginButton:', !!loginButton,
'checkButton:', !!checkButton,
'userinfoElement:', !!userinfoElement
);
// 如果已经登录,提取local中信息
// 获取所有需要的元素
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')
};
// 检查登录状态
chrome.storage.local.get(['loginStatus', 'loginInfo'], function(data) {
if (data.loginStatus && userinfoElement) {
userinfoElement.textContent = '已登录:' + data.loginInfo.uname;
if (data.loginStatus && elements.userinfoElement) {
elements.userinfoElement.textContent = '已登录:' + data.loginInfo.uname;
}
});
// 打开抖音
if (openIncognitoButton) {
openIncognitoButton.addEventListener('click', function() {
console.log('打开隐身窗口按钮被点击');
const username = usernameInput ? usernameInput.value : '';
const password = passwordInput ? passwordInput.value : '';
// 批量打开无痕窗口
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);
chrome.runtime.sendMessage({
action: 'openIncognitoDouyin',
username: username,
password: password
}, function(response) {
if (response && response.success) {
console.log('隐身窗口已打开,准备提交登录');
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
action: 'submitLogin',
username: username,
password: password
});
});
} else {
console.error('打开隐身窗口失败');
}
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 : ''
});
});
} else {
console.error('未找到打开隐身窗口按钮');
}
// 打开直播间
if (openLiveButton && liveIdInput) {
openLiveButton.addEventListener('click', () => {
if (elements.openLiveButton && elements.liveIdInput) {
elements.openLiveButton.addEventListener('click', () => {
console.log('打开直播间按钮被点击');
const liveId = liveIdInput.value.trim();
const liveId = elements.liveIdInput.value.trim();
if (liveId) {
const liveUrl = `https://live.douyin.com/${liveId}`;
chrome.runtime.sendMessage({ action: 'openLiveIncognito', url: liveUrl });
} else {
console.error('未输入直播ID');
alert('请输入直播ID');
}
});
} else {
console.error('未找到打开直播间按钮或直播ID输入框');
}
// 登录
if (loginButton && usernameInput && passwordInput) {
loginButton.addEventListener('click', function() {
console.log('登录按钮被点击');
const username = usernameInput.value.trim();
const password = passwordInput.value.trim();
// 打开指定直播间
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;
} else {
chrome.runtime.sendMessage({ action: 'login', username: username, password: password });
}
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;
}
}
});
} else {
console.error('未找到登录按钮或用户名/密码输入框');
}
// 添加新的检查按钮功能
if (checkButton) {
checkButton.addEventListener('click', function() {
console.log('检查状态按钮被点击');
chrome.runtime.sendMessage({action: 'checkStatus'}, function(response) {
console.log('状态检查结果:', response);
alert('状态检查结果: ' + (response && response.status ? response.status : '未知'));
// 加载保存的代理列表
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));
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);
}
});
});
} else {
console.error('未找到检查状态按钮');
}
});
// 辅助函数:获取直播间人数
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') {
@ -120,4 +537,111 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
}
});
console.log('popup.js 脚本已加载完成');
// 修改执行任务的函数
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) {
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;
}
// 修改更新代理按钮的处理逻辑中的代理设置部分
async function setProxyWithRetry(proxy, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const [proxyHost, proxyPort] = proxy.split(':');
const response = await chrome.runtime.sendMessage({
action: 'setWindowProxy',
proxy: {
host: proxyHost,
port: parseInt(proxyPort)
}
});
if (response.success) {
return true;
}
// 如果设置失败,等待后重试
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
} catch (error) {
console.error(`代理设置重试 ${i + 1} 失败:`, error);
if (i === maxRetries - 1) {
throw error;
}
}
}
return false;
}

Loading…
Cancel
Save