This commit is contained in:
cheney 2026-07-17 20:35:47 +08:00
parent 5bbfe35c9c
commit 4ddbbe066d
8 changed files with 307 additions and 406 deletions

176
.gitignore vendored
View File

@ -1,176 +1,2 @@
node_modules/.package-lock.json
node_modules/.bin/playwright
node_modules/.bin/playwright-core
node_modules/.bin/playwright-core.cmd
node_modules/.bin/playwright-core.ps1
node_modules/.bin/playwright.cmd
node_modules/.bin/playwright.ps1
node_modules/playwright/cli.js
node_modules/playwright/index.d.ts
node_modules/playwright/index.js
node_modules/playwright/index.mjs
node_modules/playwright/jsx-runtime.js
node_modules/playwright/jsx-runtime.mjs
node_modules/playwright/LICENSE
node_modules/playwright/NOTICE
node_modules/playwright/package.json
node_modules/playwright/README.md
node_modules/playwright/test.d.ts
node_modules/playwright/test.js
node_modules/playwright/test.mjs
node_modules/playwright/ThirdPartyNotices.txt
node_modules/playwright/lib/errorContext.js
node_modules/playwright/lib/globals.js
node_modules/playwright/lib/index.js
node_modules/playwright/lib/isomorphic.js
node_modules/playwright/lib/isomorphic.js.txt
node_modules/playwright/lib/package.js
node_modules/playwright/lib/program.js
node_modules/playwright/lib/util.js
node_modules/playwright/lib/agents/agentParser.js
node_modules/playwright/lib/agents/copilot-setup-steps.yml
node_modules/playwright/lib/agents/generateAgents.js
node_modules/playwright/lib/agents/playwright-test-coverage.prompt.md
node_modules/playwright/lib/agents/playwright-test-generate.prompt.md
node_modules/playwright/lib/agents/playwright-test-generator.agent.md
node_modules/playwright/lib/agents/playwright-test-heal.prompt.md
node_modules/playwright/lib/agents/playwright-test-healer.agent.md
node_modules/playwright/lib/agents/playwright-test-plan.prompt.md
node_modules/playwright/lib/agents/playwright-test-planner.agent.md
node_modules/playwright/lib/cli/reportActions.js
node_modules/playwright/lib/cli/testActions.js
node_modules/playwright/lib/common/index.js
node_modules/playwright/lib/common/index.js.txt
node_modules/playwright/lib/loader/loaderProcessEntry.js
node_modules/playwright/lib/loader/loaderProcessEntry.js.txt
node_modules/playwright/lib/matchers/expect.js
node_modules/playwright/lib/matchers/expect.js.LICENSE
node_modules/playwright/lib/matchers/expect.js.txt
node_modules/playwright/lib/mcp/test/browserBackend.js
node_modules/playwright/lib/mcp/test/generatorTools.js
node_modules/playwright/lib/mcp/test/plannerTools.js
node_modules/playwright/lib/mcp/test/seed.js
node_modules/playwright/lib/mcp/test/streams.js
node_modules/playwright/lib/mcp/test/testBackend.js
node_modules/playwright/lib/mcp/test/testContext.js
node_modules/playwright/lib/mcp/test/testTool.js
node_modules/playwright/lib/mcp/test/testTools.js
node_modules/playwright/lib/runner/index.js
node_modules/playwright/lib/runner/index.js.txt
node_modules/playwright/lib/transform/babelBundle.js
node_modules/playwright/lib/transform/babelBundle.js.LICENSE
node_modules/playwright/lib/transform/babelBundle.js.txt
node_modules/playwright/lib/transform/esmLoader.js
node_modules/playwright/lib/transform/esmLoader.js.LICENSE
node_modules/playwright/lib/transform/esmLoader.js.txt
node_modules/playwright/lib/worker/workerProcessEntry.js
node_modules/playwright/lib/worker/workerProcessEntry.js.txt
node_modules/playwright/types/test.d.ts
node_modules/playwright/types/testReporter.d.ts
node_modules/playwright-core/browsers.json
node_modules/playwright-core/cli.js
node_modules/playwright-core/index.d.ts
node_modules/playwright-core/index.js
node_modules/playwright-core/index.mjs
node_modules/playwright-core/LICENSE
node_modules/playwright-core/NOTICE
node_modules/playwright-core/package.json
node_modules/playwright-core/README.md
node_modules/playwright-core/ThirdPartyNotices.txt
node_modules/playwright-core/bin/install_media_pack.ps1
node_modules/playwright-core/bin/install_webkit_wsl.ps1
node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh
node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh
node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1
node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh
node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh
node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1
node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh
node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh
node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1
node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh
node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh
node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1
node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh
node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh
node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1
node_modules/playwright-core/lib/bootstrap.js
node_modules/playwright-core/lib/coreBundle.js
node_modules/playwright-core/lib/package.js
node_modules/playwright-core/lib/serverRegistry.js
node_modules/playwright-core/lib/serverRegistry.js.LICENSE
node_modules/playwright-core/lib/utilsBundle.js
node_modules/playwright-core/lib/utilsBundle.js.LICENSE
node_modules/playwright-core/lib/xdg-open
node_modules/playwright-core/lib/entry/cliDaemon.js
node_modules/playwright-core/lib/entry/dashboardApp.js
node_modules/playwright-core/lib/entry/mcp.js
node_modules/playwright-core/lib/entry/oopBrowserDownload.js
node_modules/playwright-core/lib/server/deviceDescriptorsSource.json
node_modules/playwright-core/lib/server/chromium/appIcon.png
node_modules/playwright-core/lib/server/electron/loader.js
node_modules/playwright-core/lib/tools/cli-client/channelSessions.js
node_modules/playwright-core/lib/tools/cli-client/cli.js
node_modules/playwright-core/lib/tools/cli-client/help.json
node_modules/playwright-core/lib/tools/cli-client/minimist.js
node_modules/playwright-core/lib/tools/cli-client/output.js
node_modules/playwright-core/lib/tools/cli-client/program.js
node_modules/playwright-core/lib/tools/cli-client/registry.js
node_modules/playwright-core/lib/tools/cli-client/session.js
node_modules/playwright-core/lib/tools/cli-client/skill/SKILL.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/element-attributes.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/playwright-tests.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/request-mocking.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/running-code.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/session-management.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/spec-driven-testing.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/storage-state.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/test-generation.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/tracing.md
node_modules/playwright-core/lib/tools/cli-client/skill/references/video-recording.md
node_modules/playwright-core/lib/tools/dashboard/appIcon.png
node_modules/playwright-core/lib/tools/trace/SKILL.md
node_modules/playwright-core/lib/tools/utils/extension.js
node_modules/playwright-core/lib/tools/utils/socketConnection.js
node_modules/playwright-core/lib/vite/dashboard/index.html
node_modules/playwright-core/lib/vite/dashboard/playwright-logo.svg
node_modules/playwright-core/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf
node_modules/playwright-core/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg
node_modules/playwright-core/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg
node_modules/playwright-core/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg
node_modules/playwright-core/lib/vite/dashboard/assets/index-BY2S1tHT.css
node_modules/playwright-core/lib/vite/dashboard/assets/index-C_5TMfeg.js
node_modules/playwright-core/lib/vite/dashboard/assets/safari-na3_-uQk.svg
node_modules/playwright-core/lib/vite/htmlReport/index.html
node_modules/playwright-core/lib/vite/htmlReport/report.css
node_modules/playwright-core/lib/vite/htmlReport/report.js
node_modules/playwright-core/lib/vite/recorder/index.html
node_modules/playwright-core/lib/vite/recorder/playwright-logo.svg
node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule-DeBYQozu.js
node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule-DYBRYzYX.css
node_modules/playwright-core/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf
node_modules/playwright-core/lib/vite/recorder/assets/index-4ZiSSCmn.css
node_modules/playwright-core/lib/vite/recorder/assets/index-Bq-mQf8S.js
node_modules/playwright-core/lib/vite/traceViewer/codeMirrorModule.DYBRYzYX.css
node_modules/playwright-core/lib/vite/traceViewer/codicon.DCmgc-ay.ttf
node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.CjdS-WJx.css
node_modules/playwright-core/lib/vite/traceViewer/index.CzXZzn5A.css
node_modules/playwright-core/lib/vite/traceViewer/index.DMMX1gXU.js
node_modules/playwright-core/lib/vite/traceViewer/index.html
node_modules/playwright-core/lib/vite/traceViewer/manifest.webmanifest
node_modules/playwright-core/lib/vite/traceViewer/playwright-logo.svg
node_modules/playwright-core/lib/vite/traceViewer/snapshot.html
node_modules/playwright-core/lib/vite/traceViewer/snapshot.v8KI4P3m.js
node_modules/playwright-core/lib/vite/traceViewer/sw.bundle.js
node_modules/playwright-core/lib/vite/traceViewer/uiMode.BZQ54Kgt.css
node_modules/playwright-core/lib/vite/traceViewer/uiMode.html
node_modules/playwright-core/lib/vite/traceViewer/uiMode.Ut8wwJNp.js
node_modules/playwright-core/lib/vite/traceViewer/xtermModule.DYP7pi_n.css
node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-LEHpjmcn.js
node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-BNmKHKpQ.js
node_modules/playwright-core/lib/vite/traceViewer/assets/urlMatch-BYQrIQwR.js
node_modules/playwright-core/lib/vite/traceViewer/assets/xtermModule-CsJ4vdCR.js
node_modules/playwright-core/types/protocol.d.ts
node_modules/playwright-core/types/structs.d.ts
node_modules/playwright-core/types/types.d.ts
node_modules/*
config.json

View File

@ -1,210 +0,0 @@
// 获取抖音 Cookie 和 sec_user_id 的 Playwright 脚本
// 用法: node get-cookie.js
// 会自动打开 Chrome 浏览器,请扫码登录抖音
import { chromium } from "playwright";
import { writeFileSync, readFileSync } from "fs";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const CONFIG_PATH = resolve(__dirname, "config.json");
async function main() {
console.log("🚀 启动浏览器...");
const browser = await chromium.launch({
channel: "chrome",
headless: false,
args: ["--disable-blink-features=AutomationControlled"],
});
const context = await browser.newContext({
viewport: { width: 1366, height: 768 },
userAgent:
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
});
const page = await context.newPage();
// 监听网络请求,捕获 sec_user_id
let capturedSecUserId = null;
page.on("request", (request) => {
const url = request.url();
if (url.includes("follow") || url.includes("aweme")) {
try {
const postData = request.postData();
if (postData && postData.includes("sec_user_id")) {
const parsed = JSON.parse(postData);
if (parsed.sec_user_id) {
capturedSecUserId = parsed.sec_user_id;
console.log("✅ 从请求中捕获到 sec_user_id:", capturedSecUserId);
}
}
} catch (e) {
// 忽略解析错误
}
}
});
// 也监听响应,从 body 中提取 sec_user_id
page.on("response", async (response) => {
const url = response.url();
if (url.includes("user/self") || url.includes("aweme")) {
try {
const body = await response.text();
const match = body.match(/"sec_uid":"([^"]+)"/);
if (match && !capturedSecUserId) {
capturedSecUserId = match[1];
console.log("✅ 从响应中捕获到 sec_user_id:", capturedSecUserId);
}
} catch (e) {
// 忽略
}
}
});
console.log("📱 正在打开抖音登录页...");
await page.goto("https://www.douyin.com/", {
waitUntil: "domcontentloaded",
timeout: 30000,
});
console.log("🔑 请在浏览器中扫码登录抖音...");
console.log(" (等待登录完成,检测到登录后会自动继续)");
// 等待登录成功:检测 cookie 中是否有 sessionid
await waitForLogin(context);
console.log("✅ 登录成功!");
// 导航到个人主页以触发 sec_user_id 相关请求
console.log("📋 正在访问个人主页获取 sec_user_id...");
await page.goto("https://www.douyin.com/user/self?from_tab_name=main", {
waitUntil: "networkidle",
timeout: 30000,
});
// 等待页面加载
await page.waitForTimeout(3000);
// 尝试从页面数据中提取 sec_user_id
if (!capturedSecUserId) {
capturedSecUserId = await extractSecUserIdFromPage(page);
}
// 如果还没获取到,尝试点击关注按钮触发请求
if (!capturedSecUserId) {
console.log("🖱️ 尝试触发关注列表请求以获取 sec_user_id...");
try {
// 点击关注按钮
const followBtn = page.locator('[data-e2e="follow-count"]').first();
if (await followBtn.isVisible({ timeout: 5000 })) {
await followBtn.click();
await page.waitForTimeout(3000);
}
} catch (e) {
console.log(" 未能找到关注按钮,尝试其他方式...");
}
// 再次尝试从请求中获取
if (!capturedSecUserId) {
capturedSecUserId = await extractSecUserIdFromPage(page);
}
}
// 获取所有 cookies
const cookies = await context.cookies();
const cookieString = cookies
.map((c) => `${c.name}=${c.value}`)
.join("; ");
console.log("\n========================================");
console.log("📋 获取结果:");
console.log("========================================");
console.log("Cookie:", cookieString.substring(0, 200) + "...");
console.log("sec_user_id:", capturedSecUserId || "❌ 未获取到");
console.log("========================================\n");
// 读取现有配置
let config = {};
try {
config = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
} catch (e) {
console.log(" 未找到现有配置,将创建新配置");
}
// 更新配置
config.cookie = cookieString;
if (capturedSecUserId) {
config.sec_user_id = capturedSecUserId;
}
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 4), "utf8");
console.log(`💾 配置已保存到: ${CONFIG_PATH}`);
if (!capturedSecUserId) {
console.log("\n⚠ 未能自动获取 sec_user_id");
console.log(" 请参考 README 手动获取:");
console.log(" 1. 按 F12 打开开发者工具 -> Network");
console.log(" 2. 筛选 'follow'");
console.log(" 3. 点击关注按钮,在请求 Payload 中找到 sec_user_id");
console.log(" 4. 手动填入 config.json");
}
await browser.close();
console.log("👋 浏览器已关闭,脚本执行完毕");
}
// 等待用户登录成功
async function waitForLogin(context) {
return new Promise((resolve) => {
const checkInterval = setInterval(async () => {
const cookies = await context.cookies();
const hasSession = cookies.some((c) => c.name === "sessionid");
if (hasSession) {
clearInterval(checkInterval);
resolve();
}
}, 2000);
});
}
// 从页面中提取 sec_user_id
async function extractSecUserIdFromPage(page) {
// 方法1: 从页面 URL 提取
const url = page.url();
const urlMatch = url.match(/user\/([^?]+)/);
if (urlMatch && urlMatch[1] !== "self") {
return urlMatch[1];
}
// 方法2: 从页面 HTML 中的 __INITIAL_STATE__ 提取
try {
const html = await page.content();
const match = html.match(/"sec_uid":"([^"]+)"/);
if (match) return match[1];
} catch (e) {
// 忽略
}
// 方法3: 从 window.__INITIAL_STATE__ 提取
try {
const secUid = await page.evaluate(() => {
const state = window.__INITIAL_STATE__;
if (state?.user?.sec_uid) return state.user.sec_uid;
return null;
});
if (secUid) return secUid;
} catch (e) {
// 忽略
}
return null;
}
main().catch((err) => {
console.error("❌ 脚本执行出错:", err.message);
process.exit(1);
});

View File

@ -4,12 +4,16 @@
"description": "宸茬煡 Cookie 鍙?sec_user_id, 瀹炵幇娓呯┖鏀惰棌鍜岀偣璧炲姛鑳?",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" \u0026\u0026 exit 1",
"get-cookie": "node get-cookie.js"
"loop": "node cli.js loop",
"unfavorite": "node cli.js unfavorite",
"sync": "node cli.js sync",
"uncollect": "node cli.js uncollect",
"get-cookie": "node cli.js get-cookie"
},
"author": "",
"license": "ISC",
"dependencies": {
"playwright": "^1.61.1"
}
},
"type": "module"
}

68
src/cli.js Normal file
View File

@ -0,0 +1,68 @@
// 抖音小云 CLI 工具
// 用法:
// node cli.js get-cookie 获取抖音 cookies 并同步到 douxiaoyun
// node cli.js sync 将本地 cookies 同步到 douxiaoyun
// node cli.js unfavorite 取消点赞(单次执行)
// node cli.js uncollect 取消收藏(单次执行)
// node cli.js loop 循环模式每10秒取消点赞
const cmd = process.argv[2];
const validCommands = ["cookies", "sync", "unfavorite", "uncollect", "loop"];
if (!cmd || !validCommands.includes(cmd)) {
console.log("抖音小云 CLI 工具\n");
console.log("用法: node cli.js <命令>\n");
console.log("可用命令:");
console.log(" cookies 获取抖音 cookies 并同步到 douxiaoyun");
console.log(" sync 将本地 cookies 同步到 douxiaoyun");
console.log(" unfavorite 取消点赞(单次执行)");
console.log(" uncollect 取消收藏(单次执行)");
console.log(" loop 循环模式每10秒取消点赞");
process.exit(1);
}
async function main() {
console.log("cmd=" + cmd)
switch (cmd) {
case "cookies":
console.log("🔑 获取抖音 cookies...");
const { main: getCookie } = await import("./get-cookie.js");
await getCookie();
break;
case "sync":
console.log("🔄 同步 cookies 到 douxiaoyun...");
const { syncToDouxiaoyun } = await import("./sync-douxiaoyun.js");
const { readFileSync } = await import("fs");
const { resolve, dirname } = await import("path");
const { fileURLToPath } = await import("url");
const __dir = dirname(fileURLToPath(import.meta.url));
const config = JSON.parse(readFileSync(resolve(__dir, "src", "config.json"), "utf8"));
await syncToDouxiaoyun(config.cookie, config.sec_user_id);
break;
case "unfavorite":
console.log("💔 取消点赞...");
const { getAndUnFavorite } = await import("./index.js");
await getAndUnFavorite();
break;
case "uncollect":
console.log("📦 取消收藏...");
const { getAndUnCollection } = await import("./index.js");
await getAndUnCollection();
break;
case "loop":
console.log("🔄 启动循环模式每10秒取消点赞...");
const mod = await import("./index.js");
await mod.getAndUnFavorite();
setInterval(() => { mod.getAndUnFavorite(); }, 10 * 1000);
break;
}
}
main().catch((err) => {
console.error("❌ 执行出错:", err.message);
process.exit(1);
});

102
src/get-cookie.js Normal file
View File

@ -0,0 +1,102 @@
// 获取抖音 Cookie 和 sec_user_id 的 Playwright 脚本
// 用法: node get-cookie.js
// 会自动打开 Chrome 浏览器,请扫码登录抖音
// 登录完成后自动同步 cookies 到 douxiaoyun 服务
import { chromium } from "playwright";
import { writeFileSync, readFileSync } from "fs";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";
import { syncToDouxiaoyun } from "./sync-douxiaoyun.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const CONFIG_PATH = resolve(__dirname, "config.json");
// ============================================================
// 保存配置到本地 config.json
// ============================================================
function saveConfig(cookieString, secUserId) {
let config = {};
try {
config = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
} catch (e) {
console.log(" 未找到现有配置,将创建新配置");
}
config.cookie = cookieString;
if (secUserId) {
config.sec_user_id = secUserId;
}
config.updatedAt = new Date().toISOString();
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 4), "utf8");
console.log(`💾 配置已保存到: ${CONFIG_PATH}`);
console.log(` updatedAt: ${config.updatedAt}`);
if (!secUserId) {
console.log("\n⚠ 未能自动获取 sec_user_id");
console.log(" 请参考 README 手动获取:");
console.log(" 1. 按 F12 打开开发者工具 -> Network");
console.log(" 2. 筛选 'follow'");
console.log(" 3. 点击关注按钮,在请求 Payload 中找到 sec_user_id");
console.log(" 4. 手动填入 config.json");
}
}
// ============================================================
// 辅助函数
// ============================================================
// 等待用户登录成功
async function waitForLogin(context) {
return new Promise((resolve) => {
const checkInterval = setInterval(async () => {
const cookies = await context.cookies();
const hasSession = cookies.some((c) => c.name === "sessionid");
if (hasSession) {
clearInterval(checkInterval);
resolve();
}
}, 2000);
});
}
// 从页面中提取 sec_user_id
async function extractSecUserIdFromPage(page) {
// 方法1: 从页面 URL 提取
const url = page.url();
const urlMatch = url.match(/user\/([^?]+)/);
if (urlMatch && urlMatch[1] !== "self") {
return urlMatch[1];
}
// 方法2: 从页面 HTML 中的 __INITIAL_STATE__ 提取
try {
const html = await page.content();
const match = html.match(/"sec_uid":"([^"]+)"/);
if (match) return match[1];
} catch (e) {
// 忽略
}
// 方法3: 从 window.__INITIAL_STATE__ 提取
try {
const secUid = await page.evaluate(() => {
const state = window.__INITIAL_STATE__;
if (state?.user?.sec_uid) return state.user.sec_uid;
return null;
});
if (secUid) return secUid;
} catch (e) {
// 忽略
}
return null;
}
main().catch((err) => {
console.error("❌ 脚本执行出错:", err.message);
process.exit(1);
});
export { main };

View File

@ -1,6 +1,8 @@
// 读取配置文件
import { readFileSync } from 'fs';
const config = JSON.parse(readFileSync('./src/config.json', 'utf8'));
import { readFileSync } from "fs";
import { fileURLToPath } from "url";
import { dirname, resolve } from "path";
const __dirname = dirname(fileURLToPath(import.meta.url));
const config = JSON.parse(readFileSync(resolve(__dirname, "config.json"), "utf8"));
const { cookie, sec_user_id } = config;
async function getCollection() {
@ -71,13 +73,13 @@ async function getAndUnCollection() {
async function unCollection(ids) {
try {
// 构建 aweme_type_map
// 鏋勫缓 aweme_type_map
const aweme_type_map = {};
ids.forEach(id => {
aweme_type_map[id] = 0;
});
// 构建请求体
// 鏋勫缓璇锋眰浣?
const body = `aweme_ids=${ids.join('%2C')}&aweme_type_map=${encodeURIComponent(JSON.stringify(aweme_type_map))}`;
const response = await fetch("https://www.douyin.com/aweme/v1/web/aweme/cancel/collect/multi/?device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&pc_libra_divert=Windows&update_version_code=170400&support_h265=1&support_dash=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=122.0.6261.95&browser_online=true&engine_name=Blink&engine_version=122.0.6261.95&os_name=Windows&os_version=10&cpu_core_num=8&device_memory=8&platform=PC&downlink=2.25&effective_type=4g&round_trip_time=200&webid=7588123201441105427&uifid=e438e504399eecf9c2f65594851517a53fcd0a47c3feace6f386418d12bbc04d0e409b50ec8a21ef6eff4b825cd64059646e0a366a371675723852d9a6540fb6f5091520701820efa27f3a3704dddb313966d30cb1eb174337518d6be3053846f8e3a789519374cdfccbab779ff03ecc6f7e7de633af65c7c8023a60b56e88d25276be703f2bf75e67ae6889151319ddab78703305a3c9034797e4620f16cafc7027bf0cb4e50041e1bf97725dd3c1906f45d3565d6b31aadf8fcfd836827d98&verifyFp=verify_mjmrx3qn_TELLC7l8_syRO_4t1Z_9xE4_wiK4naxXhlHj&fp=verify_mjmrx3qn_TELLC7l8_syRO_4t1Z_9xE4_wiK4naxXhlHj&msToken=gm3y5Z8Zs-ESl5ZxONjXIQQqhHn6XZvoBLS-ciy0w_wtvszmbAWR_jjXM5F2wLyFkgdBC6MQ2INL4FOCi85sI53qpaOs_yY3A7Fh7WevXbpsIzkD7sQKIjrgVEgbIOAlc4O1zGiU_tLoi2X9ZsIP5TlVg6p9ecYALNzAjwkdLvg%3D&a_bogus=OfsjDwtLEq5jadFbmODstl2UvSoANTWyk-TKRHaPtPYoPhlTXmNPQq4NJoiV5VZzWYphwKZHGD5UGdxb8U1r8CnkwmhkuF7fAT%2FnI60o%2FqwgGts%2FDqmDC0YzzwBFUOJNl%2FCfiAm5Ws0x2VnRVH5gAp2ae5zqQbfgWNpIp%2FG9jDS8psyTno%2FnCcYWH7L%3D", {
@ -186,13 +188,13 @@ async function getAndUnFavorite() {
async function unFavorites(ids) {
try {
// 构建 item_type_map
// 鏋勫缓 item_type_map
const item_type_map = {};
ids.forEach(id => {
item_type_map[id] = 0;
});
// 构建请求体
// 鏋勫缓璇锋眰浣?
const body = `aweme_ids=${ids.join('%2C')}&item_type_map=${encodeURIComponent(JSON.stringify(item_type_map))}`;
const response = await fetch("https://www.douyin.com/aweme/v1/web/cancel/item/digg/multi/?device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&pc_libra_divert=Windows&update_version_code=170400&support_h265=1&support_dash=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=122.0.6261.95&browser_online=true&engine_name=Blink&engine_version=122.0.6261.95&os_name=Windows&os_version=10&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=100&webid=7588123201441105427&uifid=e438e504399eecf9c2f65594851517a53fcd0a47c3feace6f386418d12bbc04d0e409b50ec8a21ef6eff4b825cd64059646e0a366a371675723852d9a6540fb6f5091520701820efa27f3a3704dddb313966d30cb1eb174337518d6be3053846f8e3a789519374cdfccbab779ff03ecc6f7e7de633af65c7c8023a60b56e88d25276be703f2bf75e67ae6889151319ddab78703305a3c9034797e4620f16cafc7027bf0cb4e50041e1bf97725dd3c1906f45d3565d6b31aadf8fcfd836827d98&msToken=F0kPDGU38Gd8N6XXWgz-L8OtZkRJ7A_CXcll-C3uMUXHrW3Yz1BM2227vKwOEKgiCeyc4qASII7SoiNRVDUGx5oUd_lhMCnFlQlnzoO4D8Rm4p5VsSn4pZgkl0Wmhz27vn8FHeONpv9g0VFvM_XFIAJzDh9thrKpo0FiNzv0KT4%3D&a_bogus=OjsRhH77YNWnOVMG8cDitWclrH6ANBuyVaT2bjIT9NYYahFb5uPpKz-Ocqwdm5NwRSBzwHQHJDAuGddG8UXt2C9kLmZDShXyCG29I8vL0qNpbMU8gN8YC8kFKwsTWbhi-%2FQriC6R1ssr2VVRnr5DAQdGH5zHQcDgWqB5p2tyrDC83TyTIo%2FveahQ&verifyFp=verify_mjmrx3qn_TELLC7l8_syRO_4t1Z_9xE4_wiK4naxXhlHj&fp=verify_mjmrx3qn_TELLC7l8_syRO_4t1Z_9xE4_wiK4naxXhlHj", {
@ -233,18 +235,16 @@ async function unFavorites(ids) {
// 测试函数
async function test() {
// 测试获取喜欢列表并取消喜欢
await getAndUnFavorite();
// 测试获取收藏列表并取消收藏
// await getAndUnCollection();
}
test();
setInterval(() => {
// 导出函数供 CLI 调用
export { getAndUnFavorite, getAndUnCollection, getFavorite, getCollection };
// 直接运行时执行默认行为(循环取消点赞)
const isMain = process.argv[1] && (process.argv[1].includes("index.js") || process.argv[1].includes("cli.js"));
if (isMain && !process.argv.includes("--export")) {
console.log("启动循环模式每10秒检查并取消点赞...");
test();
}, 10 * 1000);
setInterval(() => { test(); }, 10 * 1000);
}

11
src/server-config.json Normal file
View File

@ -0,0 +1,11 @@
{
"apiUrl": "http://dsv6.honor3.com:10101/api/config/update",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZG91eWluIiwianRpIjoiYzQ2ODc3MzMtY2I3OS00OWNmLTg2ODMtODc1MGJjMzRmYzYzIiwiZXhwIjoxNzg0ODkwMjExLCJpc3MiOiIyMDc4MDY5NzQ5MTQ5MTkyMTkyIiwiYXVkIjoiMjA3ODA2OTc0OTE0OTE5MjE5MyJ9.86oluoimnUJEUBwCfKog4hLNYgrzgdwcqAVphRCbgik",
"userName": "3js",
"id": "2004162624794681344",
"savePath": "/app/collect",
"favSavePath": "/app/favorite",
"upSavePath": "/app/uper",
"imgSavePath": "/app/images",
"status": 1
}

100
src/sync-douxiaoyun.js Normal file
View File

@ -0,0 +1,100 @@
// 同步 cookies 到 douxiaoyun 服务
import { readFileSync } from "fs";
import { fileURLToPath } from "url";
import { dirname, resolve } from "path";
const __dirname = dirname(fileURLToPath(import.meta.url));
const DOUXIAOYUN_BASE = "http://dsv6.honor3.com:10101";
const DOUXIAOYUN_USER = "douyin";
const DOUXIAOYUN_PASS = "douyin2025";
async function syncToDouxiaoyun(cookieString, secUserId) {
console.log("\n🔄 正在同步 cookies 到 douxiaoyun 服务...");
try {
// 1. 登录 douxiaoyun获取 JWT token
console.log(" 1/3 登录 douxiaoyun...");
const loginResp = await fetch(`${DOUXIAOYUN_BASE}/api/auth/login`, {
method: "POST",
headers: {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "no-cache",
"content-type": "application/json",
"pragma": "no-cache",
"Referer": `${DOUXIAOYUN_BASE}/`,
"Referrer-Policy": "no-referrer-when-downgrade",
},
body: JSON.stringify({ username: DOUXIAOYUN_USER, password: DOUXIAOYUN_PASS }),
});
if (!loginResp.ok) throw new Error(`登录失败: HTTP ${loginResp.status}`);
const loginData = await loginResp.json();
const token = loginData.token || loginData.accessToken || loginData.data?.token;
if (!token) {
console.log(" ❌ 未能获取 token, 响应:", JSON.stringify(loginData).substring(0, 200));
return;
}
console.log(" ✅ 登录成功");
// 2. 查询现有配置
console.log(" 2/3 查询现有配置...");
const configResp = await fetch(`${DOUXIAOYUN_BASE}/api/config/paged`, {
method: "POST",
headers: {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9",
"authorization": `Bearer ${token}`,
"cache-control": "no-cache",
"content-type": "application/json",
"pragma": "no-cache",
"Referer": `${DOUXIAOYUN_BASE}/`,
"Referrer-Policy": "no-referrer-when-downgrade",
},
body: JSON.stringify({ pageIndex: 1, pageSize: 10 }),
});
if (!configResp.ok) throw new Error(`查询配置失败: HTTP ${configResp.status}`);
const configData = await configResp.json();
const items = configData.data?.items || configData.items || configData.data || [];
const existingConfig = Array.isArray(items) ? items[0] : items;
if (!existingConfig || !existingConfig.id) {
console.log(" ⚠️ 未找到现有配置项");
return;
}
console.log(` ✅ 找到配置项: id=${existingConfig.id}, userName=${existingConfig.userName}`);
// 3. 更新配置
console.log(" 3/3 更新 cookies...");
const updateBody = {
...existingConfig,
cookies: cookieString,
secUserId: secUserId || existingConfig.secUserId || "",
};
const updateResp = await fetch(`${DOUXIAOYUN_BASE}/api/config/update`, {
method: "POST",
headers: {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9",
"authorization": `Bearer ${token}`,
"cache-control": "no-cache",
"content-type": "application/json",
"pragma": "no-cache",
"Referer": `${DOUXIAOYUN_BASE}/`,
"Referrer-Policy": "no-referrer-when-downgrade",
},
body: JSON.stringify(updateBody),
});
if (!updateResp.ok) throw new Error(`更新配置失败: HTTP ${updateResp.status}`);
const updateResult = await updateResp.json();
console.log(" ✅ douxiaoyun cookies 更新成功!");
console.log(` 响应: ${JSON.stringify(updateResult).substring(0, 200)}`);
} catch (err) {
console.error(` ❌ 同步 douxiaoyun 失败: ${err.message}`);
}
}
export { syncToDouxiaoyun };