feat(desktop-client/wangyihao): persist session cookies and recover bound partitions

Snapshot 163.com/126.net cookies on bind/refresh to a userData vault and
restore them when reattaching a session, recover orphan partitions by
matching the detected mediaInfo, verify the bind window via the console
state instead of a generic profile probe, and route token/draft fetches
through the https API origin while opening console pages over http to
match the live editor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-30 19:18:03 +08:00
parent c87842347e
commit b89892be6e
2 changed files with 530 additions and 40 deletions
+501 -24
View File
@@ -1,9 +1,9 @@
import { createHash } from "node:crypto";
import { readdirSync, statSync } from "node:fs";
import { join } from "node:path";
import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { BrowserWindow, app, nativeTheme, session as electronSession } from "electron/main";
import type { Session, WebContents } from "electron/main";
import type { Cookie, Session, WebContents } from "electron/main";
import { aiPlatformCatalog } from "@geo/shared-types";
import type { DesktopAccountInfo } from "@geo/shared-types";
@@ -160,14 +160,31 @@ type ZhihuMeResponse = {
};
type WangyiInfoResponse = {
code?: number | string;
message?: string;
msg?: string;
data?: {
mediaInfo?: {
userId?: string | number;
wemediaId?: string | number;
tname?: string;
icon?: string;
};
};
};
type WangyiInfoFetchOptions = {
allowCookieWrite?: boolean;
};
type StoredWangyihaoCookie = Pick<
Cookie,
"expirationDate" | "hostOnly" | "httpOnly" | "name" | "path" | "sameSite" | "secure" | "session" | "value"
> & {
domain: string;
};
type WangyihaoCookieVault = Record<string, {
updatedAt: number;
cookies: StoredWangyihaoCookie[];
}>;
type JianshuUser = {
id?: string | number;
@@ -259,6 +276,23 @@ const ZOL_LOGIN_REDIRECT_URLS = [
"https://passport.zol.com.cn/",
"https://service.zol.com.cn/user/login",
];
const WANGYI_API_ORIGIN = "https://mp.163.com";
const WANGYI_CONSOLE_ORIGIN = "http://mp.163.com";
const WANGYI_API_REFERER = `${WANGYI_API_ORIGIN}/subscribe_v4/index.html`;
const WANGYI_INFO_URL = `${WANGYI_API_ORIGIN}/wemedia/info.do`;
const WANGYI_CONSOLE_URL = `${WANGYI_CONSOLE_ORIGIN}/subscribe_v4/index.html`;
const WANGYI_LOGIN_REDIRECT_URLS = [
`${WANGYI_API_ORIGIN}/login.html`,
`${WANGYI_CONSOLE_ORIGIN}/login.html`,
"https://reg.163.com/",
"https://dl.reg.163.com/",
];
const WANGYI_COOKIE_URLS = [
WANGYI_API_ORIGIN,
WANGYI_CONSOLE_ORIGIN,
"https://reg.163.com/",
"https://dl.reg.163.com/",
];
const BILIBILI_WBI_MIXIN_KEY_ENC_TAB = [
46, 47, 18, 2, 53, 8, 23, 32,
15, 50, 10, 31, 58, 3, 45, 35,
@@ -1586,6 +1620,281 @@ async function hasToutiaoAuthCookies(session: Session): Promise<boolean> {
return false;
}
function extractWangyihaoAccount(response: WangyiInfoResponse | null | undefined): DetectedAccount | null {
const media = response?.data?.mediaInfo;
const uid = stringId(media?.userId) || stringId(media?.wemediaId);
const displayName = normalizeText(media?.tname);
if (!uid || !displayName) {
return null;
}
return {
platformUid: uid,
displayName,
avatarUrl: normalizeRemoteUrl(media?.icon),
};
}
async function fetchWangyihaoInfo(
session: Session,
options: WangyiInfoFetchOptions = {},
): Promise<WangyiInfoResponse | null> {
const headers = {
accept: "application/json, text/plain, */*",
referer: WANGYI_API_REFERER,
origin: WANGYI_API_ORIGIN,
};
if (options.allowCookieWrite) {
return await sessionFetchJson<WangyiInfoResponse>(
session,
WANGYI_INFO_URL,
{
credentials: "include",
headers,
},
).catch(() => null);
}
return await sessionCookieFetchJson<WangyiInfoResponse>(
session,
WANGYI_INFO_URL,
{ headers },
).catch(() => null);
}
async function detectWangyihaoFromSession(session: Session): Promise<DetectedAccount | null> {
return extractWangyihaoAccount(await fetchWangyihaoInfo(session));
}
function wangyihaoCookieVaultPath(): string {
return join(app.getPath("userData"), "desktop-wangyihao-cookies.json");
}
function readWangyihaoCookieVault(): WangyihaoCookieVault {
try {
return JSON.parse(readFileSync(wangyihaoCookieVaultPath(), "utf8")) as WangyihaoCookieVault;
} catch {
return {};
}
}
function writeWangyihaoCookieVault(vault: WangyihaoCookieVault): void {
const target = wangyihaoCookieVaultPath();
mkdirSync(dirname(target), { recursive: true });
writeFileSync(target, JSON.stringify(vault, null, 2), "utf8");
}
function isWangyihaoCookie(cookie: Cookie): boolean {
const domain = cookie.domain?.toLowerCase() ?? "";
return domain.endsWith("163.com") || domain.endsWith("126.net");
}
function dedupeWangyihaoCookies(cookies: Cookie[]): StoredWangyihaoCookie[] {
const seen = new Set<string>();
const result: StoredWangyihaoCookie[] = [];
for (const cookie of cookies) {
const domain = cookie.domain;
if (!domain || !isWangyihaoCookie(cookie) || !cookie.value) {
continue;
}
const key = [
domain,
cookie.path,
cookie.name,
cookie.secure ? "secure" : "plain",
].join("\n");
if (seen.has(key)) {
continue;
}
seen.add(key);
result.push({
domain,
expirationDate: cookie.expirationDate,
hostOnly: cookie.hostOnly,
httpOnly: cookie.httpOnly,
name: cookie.name,
path: cookie.path,
sameSite: cookie.sameSite,
secure: cookie.secure,
session: cookie.session,
value: cookie.value,
});
}
return result;
}
function urlForStoredWangyihaoCookie(cookie: StoredWangyihaoCookie): string {
const domain = cookie.domain.replace(/^\./, "");
const protocol = cookie.secure ? "https" : "http";
return `${protocol}://${domain}${cookie.path || "/"}`;
}
async function saveWangyihaoSessionCookies(accountId: string, session: Session): Promise<void> {
const collected: Cookie[] = [];
for (const url of WANGYI_COOKIE_URLS) {
collected.push(...await session.cookies.get({ url }).catch(() => []));
}
const cookies = dedupeWangyihaoCookies(collected);
if (!cookies.length) {
return;
}
const vault = readWangyihaoCookieVault();
vault[accountId] = {
updatedAt: Date.now(),
cookies,
};
writeWangyihaoCookieVault(vault);
}
async function restoreWangyihaoSessionCookies(accountId: string, session: Session): Promise<void> {
const snapshot = readWangyihaoCookieVault()[accountId];
if (!snapshot?.cookies?.length) {
return;
}
for (const cookie of snapshot.cookies) {
await session.cookies.set({
url: urlForStoredWangyihaoCookie(cookie),
name: cookie.name,
value: cookie.value,
domain: cookie.domain,
path: cookie.path || "/",
secure: cookie.secure,
httpOnly: cookie.httpOnly,
sameSite: cookie.sameSite,
...(!cookie.session && cookie.expirationDate ? { expirationDate: cookie.expirationDate } : {}),
}).catch((error) => {
console.warn("[desktop-session] restore wangyihao cookie failed", {
accountId,
domain: cookie.domain,
name: cookie.name,
message: error instanceof Error ? error.message : String(error),
});
});
}
}
async function probeWangyihaoSession(
account: PublishAccountIdentity,
session: Session,
options: WangyiInfoFetchOptions = {},
): Promise<AuthProbeResult> {
const response = await fetchWangyihaoInfo(session, options).catch(() => null);
const detected = extractWangyihaoAccount(response);
if (detected) {
if (!detectedAccountMatchesIdentity(detected, account)) {
return {
verdict: "expired",
reason: "login_redirect",
profile: null,
sessionFingerprint: sanitizeDetectedAccount(detected).platformUid,
evidence: {
detectedPlatformUid: detected.platformUid,
expectedPlatformUid: account.platformUid,
},
};
}
return {
verdict: "active",
reason: "probe_success",
profile: toAccountHealthProfile(toPublishAccountProfile(detected)),
sessionFingerprint: sanitizeDetectedAccount(detected).platformUid,
};
}
if (!response) {
return {
verdict: "network_error",
reason: "network_error",
profile: null,
sessionFingerprint: null,
};
}
return {
verdict: "expired",
reason: "login_redirect",
profile: null,
sessionFingerprint: null,
evidence: {
code: response.code ?? null,
message: response.message ?? response.msg ?? null,
},
};
}
async function hasWangyihaoAuthCookies(session: Session): Promise<boolean> {
const authCookieNames = new Set([
"P_INFO",
"S_INFO",
"NTES_SESS",
"l_yd_sign",
]);
const isAuthCookie = (name: string) => authCookieNames.has(name) || name.startsWith("l_s_subscribe");
const urls = [
WANGYI_API_ORIGIN,
WANGYI_CONSOLE_ORIGIN,
"https://reg.163.com/",
"https://dl.reg.163.com/",
];
for (const url of urls) {
const cookies = await session.cookies.get({ url }).catch(() => []);
if (cookies.some((cookie) => isAuthCookie(cookie.name) && normalizeText(cookie.value))) {
return true;
}
}
return false;
}
async function recoverWangyihaoSessionHandle(account: PublishAccountIdentity): Promise<SessionHandle | null> {
const pendingPartitions = listPendingPartitions("wangyihao");
if (!pendingPartitions.length) {
return null;
}
const expectedUid = normalizeText(account.platformUid) ?? "";
const expectedName = normalizeComparableText(account.displayName);
for (const partition of pendingPartitions) {
const candidateSession = electronSession.fromPartition(partition);
if (!(await hasWangyihaoAuthCookies(candidateSession))) {
continue;
}
const detected = await detectWangyihaoFromSession(candidateSession).catch(() => null);
if (!detected) {
continue;
}
if (expectedUid && sameAccountPlatformUid(detected.platformUid, expectedUid)) {
console.info("[desktop-session] recovered wangyihao partition by uid", {
accountId: account.id,
partition,
platformUid: detected.platformUid,
});
return createSessionHandleForPartition(account.id, partition);
}
if (expectedName && normalizeComparableText(detected.displayName) === expectedName) {
console.info("[desktop-session] recovered wangyihao partition by name", {
accountId: account.id,
partition,
displayName: detected.displayName,
});
return createSessionHandleForPartition(account.id, partition);
}
}
return null;
}
async function recoverToutiaoSessionHandle(account: PublishAccountIdentity): Promise<SessionHandle | null> {
const pendingPartitions = listPendingPartitions("toutiaohao");
if (!pendingPartitions.length) {
@@ -1651,12 +1960,19 @@ async function findLocalPublishAccountSessionHandle(
): Promise<SessionHandle | null> {
const existing = getSessionHandle(account.id);
if (existing) {
if (account.platform === "wangyihao") {
await restoreWangyihaoSessionCookies(account.id, existing.session);
}
return existing;
}
const persisted = getPersistedPartition(account.id);
if (persisted) {
return createSessionHandle(account.id);
const handle = createSessionHandle(account.id);
if (account.platform === "wangyihao") {
await restoreWangyihaoSessionCookies(account.id, handle.session);
}
return handle;
}
if (account.platform === "toutiaohao") {
@@ -1666,6 +1982,13 @@ async function findLocalPublishAccountSessionHandle(
}
}
if (account.platform === "wangyihao") {
const recovered = await recoverWangyihaoSessionHandle(account);
if (recovered) {
return recovered;
}
}
return null;
}
@@ -1783,6 +2106,10 @@ export async function probePublishAccountSession(
};
}
if (account.platform === "wangyihao") {
return await probeWangyihaoSession(account, handle.session);
}
const window = createBoundWindow(
`${definition.label} 静默探针`,
await resolvePublishAccountConsoleURL(definition, handle.session),
@@ -1849,7 +2176,9 @@ export async function probePublishAccountSession(
};
}
if (definitionLooksLikeLoginRedirect(currentURL, definition)) {
const isLoginRedirect = definitionLooksLikeLoginRedirect(currentURL, definition);
if (isLoginRedirect) {
return {
verdict: "expired",
reason: "login_redirect",
@@ -2136,6 +2465,15 @@ export async function silentRefreshPublishAccountSession(
return false;
}
if (account.platform === "wangyihao") {
const result = await probeWangyihaoSession(account, handle.session, { allowCookieWrite: true })
.catch(() => null);
if (result?.verdict === "active") {
await saveWangyihaoSessionCookies(account.id, handle.session);
}
return result?.verdict === "active";
}
const window = createBoundWindow(
`${definition.label} 静默续期`,
await resolvePublishAccountConsoleURL(definition, handle.session),
@@ -2199,6 +2537,13 @@ export async function inspectPublishAccountLocalSession(
const profile = await resolvePublishAccountProfileFromHandle(account, handle);
if (!profile) {
if (account.platform === "wangyihao") {
return {
availability: "expired",
profile: null,
};
}
const consoleReady = await verifyPublishAccountConsoleAccess(account, handle).catch(() => false);
if (consoleReady) {
return {
@@ -2344,6 +2689,121 @@ async function verifyToutiaoConsoleAccess(window: BrowserWindow, session: Sessio
return extractToutiaoAccount(sessionResponse) !== null;
}
function isWangyihaoLoggedOutText(text: string): boolean {
return /(登录超时|登录态失效|登录状态失效|登录已过期|会话已过期|请重新登录|请先登录|未登录|网易邮箱账号登录|网易邮箱帐号登录|手机号登录|扫码登录)/i
.test(text);
}
async function readWangyihaoConsoleState(
webContents: WebContents | null | undefined,
): Promise<{ loggedOut: boolean; title: string; textSnippet: string } | null> {
if (!webContents || webContents.isDestroyed()) {
return null;
}
const state = await webContents.executeJavaScript(
`(() => {
try {
const text = String(document.body?.innerText || "");
const title = String(document.title || "");
const source = title + "\\n" + text.slice(0, 1200);
return {
title,
textSnippet: text.slice(0, 500),
loggedOut: /(登录超时|登录态失效|登录状态失效|登录已过期|会话已过期|请重新登录|请先登录|未登录|网易邮箱账号登录|网易邮箱帐号登录|手机号登录|扫码登录)/i.test(source),
};
} catch {
return null;
}
})();`,
true,
).catch(() => null);
if (!state || typeof state !== "object") {
return null;
}
const typed = state as { loggedOut?: unknown; title?: unknown; textSnippet?: unknown };
const title = typeof typed.title === "string" ? typed.title : "";
const textSnippet = typeof typed.textSnippet === "string" ? typed.textSnippet : "";
return {
loggedOut: typed.loggedOut === true || isWangyihaoLoggedOutText(`${title}\n${textSnippet}`),
title,
textSnippet,
};
}
async function verifyWangyihaoConsoleAccess(
window: BrowserWindow,
session: Session,
account: PublishAccountIdentity,
): Promise<boolean> {
if (window.isDestroyed()) {
return false;
}
const currentURL = window.webContents.getURL();
if (!currentURL || currentURL.startsWith("data:text/html")) {
return false;
}
const definition = platformBindingDefinitions.wangyihao;
if (definition && definitionLooksLikeLoginRedirect(currentURL, definition)) {
return false;
}
const pageState = await readWangyihaoConsoleState(window.webContents);
if (pageState?.loggedOut) {
return false;
}
const detected = await detectWangyihaoFromSession(session).catch(() => null);
if (detected) {
return detectedAccountMatchesIdentity(detected, account);
}
return false;
}
function detectedAccountsLikelyMatch(left: DetectedAccount, right: DetectedAccount): boolean {
const leftUid = normalizeAccountPlatformUid(left.platformUid) || left.platformUid;
const rightUid = normalizeAccountPlatformUid(right.platformUid) || right.platformUid;
if (leftUid && rightUid) {
return sameAccountPlatformUid(leftUid, rightUid);
}
const leftName = normalizeComparableText(left.displayName);
const rightName = normalizeComparableText(right.displayName);
return Boolean(leftName && rightName && leftName === rightName);
}
async function verifyWangyihaoBindWindowReady(
window: BrowserWindow,
session: Session,
expected: DetectedAccount,
): Promise<boolean> {
if (window.isDestroyed()) {
return false;
}
const currentURL = window.webContents.getURL();
const definition = platformBindingDefinitions.wangyihao;
if (!currentURL || currentURL.startsWith("data:text/html")) {
return false;
}
if (definition && definitionLooksLikeLoginRedirect(currentURL, definition)) {
return false;
}
const pageState = await readWangyihaoConsoleState(window.webContents);
if (pageState?.loggedOut) {
return false;
}
const detected = await detectWangyihaoFromSession(session).catch(() => null);
return detected ? detectedAccountsLikelyMatch(detected, expected) : false;
}
function detectedAccountMatchesIdentity(
detected: DetectedAccount,
account: PublishAccountIdentity,
@@ -2360,7 +2820,7 @@ function platformRequiresDetectedAccountForConsoleAccess(platformId: string): bo
}
function platformRequiresDetectedAccountIdentityMatch(platformId: string): boolean {
return platformId === "qiehao" || platformId === "zol";
return platformId === "qiehao" || platformId === "wangyihao" || platformId === "zol";
}
async function verifyZolConsoleAccess(
@@ -2381,7 +2841,7 @@ async function verifyZolConsoleAccess(
const LOGIN_REDIRECT_TOKEN_RE =
/(^|[/?#=&._-])(login|signin|sign-in|sign_in|signup|sign-up|register|auth|oauth|passport|scan|qrcode|qrlogin|wxlogin|sso)(?=$|[/?#=&._-])/i;
const LOGIN_REDIRECT_HOST_RE = /(^|[.-])(login|passport|auth|sso)(?=$|[.-])/i;
const LOGIN_REDIRECT_HOST_RE = /(^|[.-])(login|passport|auth|sso|reg)(?=$|[.-])/i;
function looksLikeLoginRedirect(currentURL: string, loginURL: string): boolean {
if (!currentURL || !loginURL) {
@@ -2468,6 +2928,10 @@ async function verifyPublishAccountConsoleAccess(
return detected ? detectedAccountMatchesIdentity(detected, account) : false;
}
if (account.platform === "wangyihao") {
return await verifyWangyihaoConsoleAccess(window, handle.session, account);
}
if (account.platform === "zol") {
return await verifyZolConsoleAccess(window, handle.session, account);
}
@@ -2582,22 +3046,7 @@ async function detectZhihu({ session }: DetectContext): Promise<DetectedAccount
}
async function detectWangyihao({ session }: DetectContext): Promise<DetectedAccount | null> {
const response = await sessionFetchJson<WangyiInfoResponse>(
session,
"https://mp.163.com/wemedia/info.do",
).catch(() => null);
const media = response?.data?.mediaInfo;
const uid = stringId(media?.userId);
if (!uid || !media?.tname) {
return null;
}
return {
platformUid: uid,
displayName: media.tname,
avatarUrl: normalizeRemoteUrl(media.icon),
};
return await detectWangyihaoFromSession(session);
}
async function detectJianshu({ session }: DetectContext): Promise<DetectedAccount | null> {
@@ -3094,7 +3543,8 @@ const publishBindingDefinitions: Record<string, PublishPlatformBindingDefinition
id: "wangyihao",
label: "网易号",
loginUrl: "https://mp.163.com/login.html",
consoleUrl: "https://mp.163.com/index.html#/article/create",
consoleUrl: WANGYI_CONSOLE_URL,
loginRedirectUrls: WANGYI_LOGIN_REDIRECT_URLS,
detect: detectWangyihao,
},
jianshu: {
@@ -3414,6 +3864,29 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
}
}
if (definition.id === "wangyihao") {
const consoleReady = await verifyWangyihaoBindWindowReady(
window,
handle.session,
normalizedDetected,
);
console.info("[desktop-bind] wangyihao console verification", {
platform: definition.id,
ready: consoleReady,
url: window.isDestroyed() ? "" : window.webContents.getURL(),
});
if (!consoleReady) {
return;
}
const detectedFromWorkbench = await definition
.detect({ session: handle.session, webContents: window.webContents })
.catch(() => null);
if (detectedFromWorkbench) {
normalizedDetected = sanitizeDetectedAccount(detectedFromWorkbench);
}
}
normalizedDetected = await finalizeDetectedAccountForBind(
definition,
{ session: handle.session, webContents: window.webContents },
@@ -3434,6 +3907,10 @@ export async function bindPublishAccount(platformId: string): Promise<DesktopAcc
tags: [],
});
if (definition.id === "wangyihao") {
await saveWangyihaoSessionCookies(account.id, handle.session);
}
settleSuccess(account);
} catch (error) {
console.error("[desktop-bind] upsert failed", {
@@ -69,9 +69,11 @@ type WangyiPublishDetail = {
newProminentFlag: string;
};
const WANGYI_ORIGIN = "https://mp.163.com";
const WANGYI_HOME_URL = `${WANGYI_ORIGIN}/subscribe_v4/index.html`;
const WANGYI_MANAGE_URL = `${WANGYI_ORIGIN}/subscribe_v4/index.html#/article-manage`;
const WANGYI_API_ORIGIN = "https://mp.163.com";
const WANGYI_CONSOLE_ORIGIN = "http://mp.163.com";
const WANGYI_API_REFERER = `${WANGYI_API_ORIGIN}/subscribe_v4/index.html`;
const WANGYI_HOME_URL = `${WANGYI_CONSOLE_ORIGIN}/subscribe_v4/index.html`;
const WANGYI_MANAGE_URL = `${WANGYI_CONSOLE_ORIGIN}/subscribe_v4/index.html#/article-manage`;
const WANGYI_CREATIVE_STATEMENT = "个人原创,仅供参考";
const WANGYI_PUBLISH_DELAY_MS = 2_000;
const WANGYI_TOKEN_WAIT_MS = 12_000;
@@ -155,8 +157,8 @@ async function wangyiHeaders(
(await sessionCookieHeader(context.session, "163.com").catch(() => ""));
return {
accept: "application/json, text/plain, */*",
origin: WANGYI_ORIGIN,
referer: WANGYI_HOME_URL,
origin: WANGYI_API_ORIGIN,
referer: WANGYI_API_REFERER,
...(cookie ? { cookie } : {}),
...extra,
};
@@ -165,7 +167,7 @@ async function wangyiHeaders(
async function fetchAccount(context: PublishAdapterContext): Promise<WangyiAccount | null> {
const response = await sessionFetchJson<WangyiInfoResponse>(
context.session,
`${WANGYI_ORIGIN}/wemedia/info.do`,
`${WANGYI_API_ORIGIN}/wemedia/info.do`,
{
credentials: "include",
headers: await wangyiHeaders(context),
@@ -191,7 +193,7 @@ async function fetchPublishDetail(
newProminentFlag: "",
};
const url = new URL(`${WANGYI_ORIGIN}/wemedia/article/postpage.do`);
const url = new URL(`${WANGYI_API_ORIGIN}/wemedia/article/postpage.do`);
url.searchParams.set("_", String(Date.now()));
url.searchParams.set("wemediaId", account.wemediaId);
url.searchParams.set("mediaId", account.wemediaId);
@@ -224,13 +226,24 @@ async function getPublishToken(context: PublishAdapterContext): Promise<string>
throw new Error("wangyihao_playwright_missing");
}
await page.goto(WANGYI_HOME_URL, {
waitUntil: "domcontentloaded",
});
for (let attempt = 0; attempt < 2; attempt += 1) {
await page.goto(WANGYI_HOME_URL, {
waitUntil: attempt === 0 ? "domcontentloaded" : "load",
timeout: 20_000,
}).catch(() => null);
await page.waitForLoadState("networkidle", { timeout: 3_000 }).catch(() => null);
if (attempt > 0) {
await sleep(800, context.signal);
}
// 网易号的 neg 有时是顶层绑定,不一定挂在 window 上;这里保持和旧版插件一致的读取方式。
const token = await readPublishTokenFromPage(page);
return token.trim();
// 网易号的 neg 有时是顶层绑定,不一定挂在 window 上;这里保持和旧版插件一致的读取方式。
const token = (await readPublishTokenFromPage(page)).trim();
if (token) {
return token;
}
}
return "";
}
async function readPublishTokenFromPage(page: Page): Promise<string> {
@@ -415,7 +428,7 @@ async function uploadImage(
form.append("from", "neteasecode_mp");
form.append("logotext", account.name);
const url = new URL(`${WANGYI_ORIGIN}/api/v3/upload/picupload`);
const url = new URL(`${WANGYI_API_ORIGIN}/api/v3/upload/picupload`);
url.searchParams.set("_", String(Date.now()));
url.searchParams.set("wemediaId", account.wemediaId);
url.searchParams.set("realUserId", account.realUserId);
@@ -444,7 +457,7 @@ async function saveDraft(
html: string,
token: string,
): Promise<string> {
const url = new URL(`${WANGYI_ORIGIN}/wemedia/article/status/api/publishV2.do`);
const url = new URL(`${WANGYI_API_ORIGIN}/wemedia/article/status/api/publishV2.do`);
url.searchParams.set("_", String(Date.now()));
const body = buildDraftBody(context, account, detail, html, token);
@@ -772,7 +785,7 @@ async function publishDraft(context: PublishAdapterContext, draftId: string): Pr
throw new Error("wangyihao_playwright_missing");
}
const draftUrl = `https://mp.163.com/subscribe_v4/index.html#/article-publish/${encodeURIComponent(draftId)}?option=editDraft`;
const draftUrl = `${WANGYI_CONSOLE_ORIGIN}/subscribe_v4/index.html#/article-publish/${encodeURIComponent(draftId)}?option=editDraft`;
await page.goto(draftUrl, {
waitUntil: "domcontentloaded",
});