133 lines
3.6 KiB
JavaScript
133 lines
3.6 KiB
JavaScript
"use strict";
|
||
|
||
const {
|
||
delay,
|
||
newPublishPage,
|
||
LOGIN_URLS,
|
||
closePublishBrowser,
|
||
} = require("./publish_browser.js");
|
||
|
||
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 "";
|
||
}
|
||
|
||
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}` };
|
||
}
|
||
|
||
globalThis.__native?.emitProgress?.("正在打开登录页,请在浏览器中完成登录…");
|
||
const page = await newPublishPage(platform, accountId, []);
|
||
try {
|
||
await page.goto(loginUrl, { waitUntil: "domcontentloaded", timeout: 60000 });
|
||
await delay(3000);
|
||
|
||
const maxMs = 300000;
|
||
const start = Date.now();
|
||
while (Date.now() - start < maxMs) {
|
||
if (await checkLoggedIn(page, platform)) {
|
||
const cookies = await page.cookies();
|
||
const resolvedUid = await resolveUid(page);
|
||
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 = "";
|
||
}
|
||
return {
|
||
success: true,
|
||
message: "登录成功",
|
||
nickname: nickname || "已登录用户",
|
||
uid: resolvedUid || `user_${Date.now()}`,
|
||
avatar,
|
||
cookies,
|
||
};
|
||
}
|
||
await delay(2000);
|
||
globalThis.__native?.emitProgress?.("等待登录完成…");
|
||
}
|
||
return {
|
||
success: false,
|
||
error: "登录超时(5 分钟),请重试",
|
||
};
|
||
} finally {
|
||
try {
|
||
await page.close();
|
||
} catch {
|
||
/* ignore */
|
||
}
|
||
try {
|
||
await closePublishBrowser(platform, accountId);
|
||
} catch {
|
||
/* ignore */
|
||
}
|
||
}
|
||
};
|