import type { StoredPlatformState } from "../platforms"; import { connectedPlatform, disconnectedPlatform, fetchImageBlob, fetchJson, getCookieString, manageUrlResult, normalizeArticleHtml, sleep, uploadHtmlImages, } from "./common"; import type { AdapterContext, PlatformAdapter, PlatformPublishResult } from "./types"; const QIEHAO_APP_ID = "LA6zXi1lWzAioIzdiAD6iM10aHarlHF6"; type QiehaoBasicInfoResponse = { data?: { cpInfo?: { mediaId?: string | number; mediaName?: string; header?: string; }; }; }; type QiehaoPublishResponse = { response?: { code?: number; msg?: string; }; data?: { articleId?: string | number; }; msg?: string; }; type QiehaoArticleListResponse = { data?: { articles?: Array<{ article_id?: string | number; url?: string; }>; }; }; type QiehaoUploadStepOneResponse = { data?: { url?: { size?: Record; }; }; }; type QiehaoUploadStepTwoResponse = { data?: { url?: string; }; }; async function fetchBasicInfo() { const cookie = await getCookieString("om.qq.com"); return fetchJson("https://om.qq.com/maccountsetting/basicinfo?relogin=1", { headers: { accept: "application/json, text/plain, */*", ...(cookie ? { cookie } : {}), }, }).catch(() => null); } async function detectQiehao(platform: StoredPlatformState): Promise { try { const cpInfo = (await fetchBasicInfo())?.data?.cpInfo; const uid = cpInfo?.mediaId != null ? String(cpInfo.mediaId) : ""; if (!uid || !cpInfo?.mediaName) { return disconnectedPlatform(platform, "未检测到企鹅号登录态"); } return connectedPlatform(platform, uid, cpInfo.mediaName, cpInfo.header ?? null); } catch (error) { return disconnectedPlatform(platform, error instanceof Error ? error.message : "企鹅号登录检测失败"); } } async function uploadImage(sourceUrl: string, includeCoverMeta: boolean): Promise { const blob = await fetchImageBlob(sourceUrl); if (!blob) { return null; } const form = new FormData(); form.append("file", blob, "image.png"); form.append("appid", QIEHAO_APP_ID); form.append("isUpOrg", "1"); form.append("endpoint", "1"); form.append("isRetImgAttr", "1"); form.append("opCode", "151"); const first = await fetchJson("https://image.om.qq.com/cpom_pimage/ArchacaleUploadViaFile", { method: "POST", body: form, }).catch(() => null); const imageUrl = first?.data?.url?.size?.["641"]?.imageUrl ?? null; if (!imageUrl) { return null; } if (!includeCoverMeta) { return imageUrl; } const second = await fetchJson("https://image.om.qq.com/cpom_pimage/ListImageUploadViaUrl", { method: "POST", headers: { "content-type": "application/json", }, body: JSON.stringify({ auth: { appid: QIEHAO_APP_ID, endpoint: 1, }, reqData: { appid: QIEHAO_APP_ID, isUpOrg: 1, endpoint: 1, isRetImgAttr: 1, opCode: 151, imageUrl, }, relogin: 1, }), }).catch(() => null); return second?.data?.url ?? imageUrl; } async function publishQiehao(context: AdapterContext): Promise { const cpInfo = (await fetchBasicInfo())?.data?.cpInfo; const mediaId = cpInfo?.mediaId != null ? String(cpInfo.mediaId) : ""; if (!mediaId) { throw new Error("qiehao_not_logged_in"); } const cookie = await getCookieString("om.qq.com"); if (!cookie) { throw new Error("qiehao_cookie_missing"); } const content = normalizeArticleHtml(context.article); const processed = await uploadHtmlImages(content, async (sourceUrl) => uploadImage(sourceUrl, false)); const coverImages = context.article.cover_asset_url?.trim() ? [await uploadImage(context.article.cover_asset_url.trim(), true)].filter(Boolean) : []; const uploadedImageList = Array.from(processed.uploaded.values()); const resourceMarkInfo = uploadedImageList.reduce>>((result, imageUrl) => { result[imageUrl] = { image_url: imageUrl, id: imageUrl, resource_type: "image", can_modify: 1, aigc_user_statement: 2, }; return result; }, {}); const endpoint = context.article.publish_type === "publish" ? "https://om.qq.com/marticlepublish/omPublish" : "https://om.qq.com/marticlepublish/omSave"; const response = await fetchJson(endpoint, { method: "POST", headers: { "content-type": "application/json", cookie, }, body: JSON.stringify({ title: context.article.title, content: processed.html, imgurl_ext: JSON.stringify(coverImages), cover_type: "1", imgurlsrc: "custom", orignal: 0, user_original: 0, mediaId, needpub: 1, type: 0, relogin: 1, self_declare: '{"id":7,"desc":"作者声明:该文章由AI辅助创作"}', resource_aigc_mark_info: JSON.stringify(resourceMarkInfo), }), }); const articleId = response.data?.articleId != null ? String(response.data.articleId) : ""; if (response.response?.code !== 0 || !articleId) { throw new Error(response.msg || response.response?.msg || "qiehao_publish_failed"); } await sleep(1500); const list = await fetchJson( "https://om.qq.com/marticle/article/list?category=&search=&source=&startDate=&endDate=&num=20&ftype=&readChannel=qb&dstChannel=&isPartDst=0&refreshField=&relogin=1", { headers: { accept: "application/json, text/plain, */*", cookie, }, }, ).catch(() => null); const article = list?.data?.articles?.find((item) => String(item.article_id) === articleId); const articleUrl = article?.url?.trim() || null; const externalArticleId = articleUrl ? articleUrl.split("/").filter(Boolean).pop() || articleId : articleId; if (context.article.publish_type === "draft") { return manageUrlResult( true, "pending_review", externalArticleId, "https://om.qq.com/article/manage", "企鹅号草稿保存成功。", articleUrl, ); } return manageUrlResult( true, "success", externalArticleId, "https://om.qq.com/article/manage", "企鹅号发布成功。", articleUrl, ); } export const qiehaoAdapter: PlatformAdapter = { platformId: "qiehao", detect: detectQiehao, publish: publishQiehao, };