Files
yaoyaoai/scripts/nodejs/publish_login.js
949036910@qq.com bbdee469fc 1
2026-06-03 21:21:42 +08:00

215 lines
5.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
const {
delay,
newLoginPage,
LOGIN_URLS,
closeLoginBrowser,
} = require("./publish_browser.js");
const DOUYIN_HOME_URL = "https://creator.douyin.com/creator-micro/home";
const LOGIN_SELECTORS = {
douyin: ["#header-avatar", ".creator-avatar", 'input[type="file"]'],
kuaishou: ['[class*="avatar"]', ".user-avatar", '[class*="upload"]'],
shipin: ['[class*="avatar"]', ".avatar"],
xiaohongshu: ['[class*="avatar"]', ".user-avatar", '[class*="upload"]'],
};
const URL_EXCLUDE = {
douyin: ["login", "passport"],
kuaishou: ["login", "passport"],
shipin: ["login", "auth", "qr"],
xiaohongshu: ["login", "passport", "account"],
};
async function checkLoggedIn(page, platform) {
const url = page.url();
const excludes = URL_EXCLUDE[platform] || URL_EXCLUDE.douyin;
if (excludes.some((k) => url.includes(k))) return false;
const sels = LOGIN_SELECTORS[platform] || LOGIN_SELECTORS.douyin;
for (const sel of sels) {
const el = await page.$(sel);
if (el) return true;
}
return false;
}
async function resolveUid(page) {
try {
const uidFromDom = await page.evaluate(() => {
const node = document.querySelector("[data-user-id], [data-uid]");
return node?.getAttribute("data-user-id") || node?.getAttribute("data-uid") || "";
});
if (uidFromDom) return String(uidFromDom);
} catch {
/* ignore */
}
try {
const local = await page.evaluate(() => {
const keys = Object.keys(localStorage || {});
for (const k of keys) {
if (/(uid|user.?id|sec_uid|openid)/i.test(k)) {
const v = localStorage.getItem(k);
if (v) return v;
}
}
return "";
});
if (local) return String(local).slice(0, 128);
} catch {
/* ignore */
}
return "";
}
async function resolveDouyinLabel(page) {
try {
await page.goto(DOUYIN_HOME_URL, {
waitUntil: "domcontentloaded",
timeout: 60000,
});
await delay(2000);
} catch {
/* ignore */
}
try {
const text = await page.$eval(
'[class^="unique_id-"], [class*=" unique_id-"]',
(el) => (el.textContent || "").trim(),
);
const m = String(text).match(/抖音号[:]\s*([a-zA-Z0-9._-]+)/);
if (m?.[1]) return m[1];
} catch {
/* ignore */
}
try {
const fallback = await page.evaluate(() => {
const all = Array.from(document.querySelectorAll("div,span,p"));
const node = all.find((el) =>
/抖音号[:]/.test((el.textContent || "").trim()),
);
return (node?.textContent || "").trim();
});
const m = String(fallback).match(/抖音号[:]\s*([a-zA-Z0-9._-]+)/);
if (m?.[1]) return m[1];
} catch {
/* ignore */
}
return "";
}
globalThis.__nodejsMain = async function main(params) {
const p = params || {};
const platform = String(p.platform || "").trim();
const accountId = p.accountId ?? null;
const loginUrl = LOGIN_URLS[platform];
if (!loginUrl) {
return { success: false, error: `不支持的平台: ${platform}` };
}
let page = null;
globalThis.__native?.emitProgress?.("正在启动浏览器,请扫码登录…");
try {
page = await newLoginPage(platform, accountId, []);
globalThis.__native?.emitProgress?.("正在打开登录页…");
try {
await page.goto(loginUrl, { waitUntil: "domcontentloaded", timeout: 60000 });
} catch (e) {
globalThis.__native?.log?.(
"warn",
`登录页加载超时,继续等待扫码: ${e.message}`,
null,
);
}
await delay(3000);
try {
await page.bringToFront();
} catch {
/* ignore */
}
globalThis.__native?.emitProgress?.(
"请在弹出的浏览器窗口中扫码登录(最长等待 5 分钟)",
);
const maxMs = 300000;
const start = Date.now();
let lastLog = 0;
while (Date.now() - start < maxMs) {
if (page.isClosed()) {
return { success: false, error: "浏览器窗口已关闭,登录已取消" };
}
if (await checkLoggedIn(page, platform)) {
const cookies = await page.cookies();
const resolvedUid = await resolveUid(page);
let douyinId = "";
let nickname = "";
try {
nickname = await page.$eval(
".username, .account-name, .user-name, .nickname",
(el) => (el.textContent || "").trim(),
);
} catch {
nickname = "已登录用户";
}
let avatar = "";
try {
avatar =
(await page.$eval(
"img.avatar, img[class*='avatar'], .avatar img",
(el) => el?.src || "",
)) || "";
} catch {
avatar = "";
}
if (platform === "douyin") {
douyinId = await resolveDouyinLabel(page);
}
return {
success: true,
message: "登录成功",
nickname: douyinId || nickname || "已登录用户",
uid: douyinId || resolvedUid || `user_${Date.now()}`,
label: douyinId || nickname || "已登录用户",
avatar,
cookies,
};
}
const elapsed = Date.now() - start;
if (elapsed - lastLog >= 15000) {
globalThis.__native?.emitProgress?.(
`等待扫码登录… ${Math.round(elapsed / 1000)}`,
);
lastLog = elapsed;
}
await delay(3000);
}
return {
success: false,
error: "登录超时5 分钟),请重试",
};
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
return { success: false, error: msg || "启动登录浏览器失败" };
} finally {
if (page) {
try {
await page.close();
} catch {
/* ignore */
}
}
await closeLoginBrowser(platform, accountId);
}
};