@iflyrpa/actions 4.0.5 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4394,12 +4394,14 @@ var __webpack_exports__ = {};
4394
4394
  bjhConfigDataSchema: ()=>bjhConfigDataSchema,
4395
4395
  Action: ()=>Action,
4396
4396
  ProxyAgent: ()=>ProxyAgent,
4397
+ douyinConfigDataSchema: ()=>douyinConfigDataSchema,
4398
+ shipinhaoConfigDataSchema: ()=>shipinhaoConfigDataSchema,
4397
4399
  version: ()=>package_namespaceObject.i8
4398
4400
  });
4399
4401
  const package_json_namespaceObject = require("@iflyrpa/share/package.json");
4400
4402
  var package_json_default = /*#__PURE__*/ __webpack_require__.n(package_json_namespaceObject);
4401
4403
  var package_namespaceObject = {
4402
- i8: "4.0.5"
4404
+ i8: "4.0.6"
4403
4405
  };
4404
4406
  const share_namespaceObject = require("@iflyrpa/share");
4405
4407
  const external_node_fs_namespaceObject = require("node:fs");
@@ -4649,11 +4651,12 @@ var __webpack_exports__ = {};
4649
4651
  this.logger?.debug(`未处理的网络错误代码: ${error.code} ${error.message}`, {
4650
4652
  errorString: stringifyError(error)
4651
4653
  });
4652
- _message = `未知网络错误: ${error.message}`;
4654
+ _message = `网络错误: ${error.message}`;
4653
4655
  break;
4654
4656
  }
4655
4657
  }
4656
- errorResponse.message = errorResponse.message ? errorResponse.message : _message;
4658
+ if (error.code && !error.response?.data) errorResponse.message = _message || errorResponse.message;
4659
+ else errorResponse.message = errorResponse.message ? errorResponse.message : _message;
4657
4660
  if ("canceled" === errorResponse.message) {
4658
4661
  const message = errorResponse.extra?.isProxyRequest ? "代理连接建立超时,请更换区域或稍后重试!" : "网络请求超时,请稍后重试!";
4659
4662
  errorResponse.message = message;
@@ -13442,400 +13445,421 @@ var __webpack_exports__ = {};
13442
13445
  }
13443
13446
  return randomString;
13444
13447
  }
13448
+ function safeSerialize(obj) {
13449
+ if (!obj || "object" != typeof obj) return obj;
13450
+ try {
13451
+ return JSON.parse(JSON.stringify(obj));
13452
+ } catch (error) {
13453
+ return {};
13454
+ }
13455
+ }
13445
13456
  const mock_mockAction = async (task, params)=>{
13446
13457
  const updateTaskState = task.taskStageStore?.update?.bind(task.taskStageStore, task.taskId || "");
13447
13458
  if (!params.extraParam || !params.extraParam["security-sdk/s_sdk_pri_key"] || !params.extraParam["security-sdk/s_sdk_pub_key"] || !params.extraParam["security-sdk/s_sdk_sign_data_key/web_protect"] || !params.extraParam["security-sdk/s_sdk_server_cert_key"] || !params.extraParam["security-sdk/s_sdk_crypt_sdk"]) return (0, share_namespaceObject.response)(414, "extraParam 参数缺失或不完整", "");
13448
- const userAgent = params.userAgent || "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.38";
13449
- const sessionidCookie = params.cookies.find((it)=>"msToken" === it.name)?.value;
13450
- if (!sessionidCookie) return {
13451
- code: 414,
13452
- message: "账号数据异常,请重新绑定账号后重试。",
13453
- data: ""
13454
- };
13455
- const headers = {
13456
- cookie: params.cookies.map((it)=>`${it.name}=${it.value}`).join(";"),
13457
- origin: "https://creator.douyin.com",
13458
- referer: "https://creator.douyin.com/creator-micro/content/post/image?default-tab=3&enter_from=publish_page&media_type=image&type=new",
13459
- Accept: "application/json, text/plain, */*",
13460
- "Accept-Encoding": "gzip, deflate, br, zstd",
13461
- "Content-Type": "application/json",
13462
- pragma: "no-cache",
13463
- "cache-control": "no-cache",
13464
- "sec-ch-ua-platform": params.extraParam?.browserInfo?.["sec-ch-ua-platform"] || "",
13465
- "sec-ch-ua": params.extraParam?.browserInfo?.["sec-ch-ua"] || "",
13466
- "bd-ticket-guard-web-version": "2",
13467
- "sec-ch-ua-mobile": "?0",
13468
- "user-agent": userAgent,
13469
- "sec-fetch-site": "same-origin",
13470
- "sec-fetch-mode": "cors",
13471
- "sec-fetch-dest": "empty",
13472
- "accept-language": "zh-CN,zh;q=0.9",
13473
- priority: "u=1, i"
13474
- };
13475
- const publishParams = {
13476
- read_aid: "2906",
13477
- aid: "1128",
13478
- cookie_enabled: "true",
13479
- screen_width: params.extraParam?.browserInfo.screen_width || "1920",
13480
- screen_height: params.extraParam?.browserInfo.screen_height || "1080",
13481
- browser_language: params.extraParam?.browserInfo.browser_language || "zh-CN",
13482
- browser_platform: params.extraParam?.browserInfo.browser_platform || "Win32",
13483
- browser_name: params.extraParam?.browserInfo.browser_name || "Mozilla",
13484
- browser_version: userAgent,
13485
- browser_online: "true",
13486
- timezone_name: "Asia/Shanghai",
13487
- support_h265: "1",
13488
- msToken: params.cookies.find((e)=>"msToken" === e.name)?.value || "",
13489
- a_bogus: ""
13490
- };
13491
- task.logger.info(`[douyinPublish] publishParams ${JSON.stringify(publishParams)}`);
13492
- const publishData = {
13493
- item: {
13494
- common: {
13495
- text: params.content,
13496
- text_extra: params.textExtra,
13497
- activity: "[]",
13498
- challenges: params.challengeIds || "[]",
13499
- hashtag_source: "",
13500
- mentions: "[]",
13501
- music_id: params.musicId || "",
13502
- music_end_time: 1000 * (params.musicDuration || 0),
13503
- hot_sentence: params.hotSentence || "",
13504
- visibility_type: Number(params.visibleRange) || 0,
13505
- download: params.allowSave ? 1 : 0,
13506
- timing: params.isImmediatelyPublish ? -1 : params.scheduledPublish,
13507
- media_type: Number(params.publishType) || 2,
13508
- images: [],
13509
- creation_id: ""
13510
- },
13511
- cover: {
13512
- poster: ""
13459
+ let currentStep = "初始化";
13460
+ try {
13461
+ currentStep = "验证账号信息";
13462
+ const userAgent = params.userAgent || "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.38";
13463
+ const sessionidCookie = params.cookies.find((it)=>"msToken" === it.name)?.value;
13464
+ if (!sessionidCookie) return {
13465
+ code: 414,
13466
+ message: "账号数据异常,请重新绑定账号后重试。",
13467
+ data: ""
13468
+ };
13469
+ currentStep = "准备请求参数";
13470
+ const headers = {
13471
+ cookie: params.cookies.map((it)=>`${it.name}=${it.value}`).join(";"),
13472
+ origin: "https://creator.douyin.com",
13473
+ referer: "https://creator.douyin.com/creator-micro/content/post/image?default-tab=3&enter_from=publish_page&media_type=image&type=new",
13474
+ Accept: "application/json, text/plain, */*",
13475
+ "Accept-Encoding": "gzip, deflate, br, zstd",
13476
+ "Content-Type": "application/json",
13477
+ pragma: "no-cache",
13478
+ "cache-control": "no-cache",
13479
+ "sec-ch-ua-platform": params.extraParam?.browserInfo?.["sec-ch-ua-platform"] || "",
13480
+ "sec-ch-ua": params.extraParam?.browserInfo?.["sec-ch-ua"] || "",
13481
+ "bd-ticket-guard-web-version": "2",
13482
+ "sec-ch-ua-mobile": "?0",
13483
+ "user-agent": userAgent,
13484
+ "sec-fetch-site": "same-origin",
13485
+ "sec-fetch-mode": "cors",
13486
+ "sec-fetch-dest": "empty",
13487
+ "accept-language": "zh-CN,zh;q=0.9",
13488
+ priority: "u=1, i"
13489
+ };
13490
+ const publishParams = {
13491
+ read_aid: "2906",
13492
+ aid: "1128",
13493
+ cookie_enabled: "true",
13494
+ screen_width: params.extraParam?.browserInfo.screen_width || "1920",
13495
+ screen_height: params.extraParam?.browserInfo.screen_height || "1080",
13496
+ browser_language: params.extraParam?.browserInfo.browser_language || "zh-CN",
13497
+ browser_platform: params.extraParam?.browserInfo.browser_platform || "Win32",
13498
+ browser_name: params.extraParam?.browserInfo.browser_name || "Mozilla",
13499
+ browser_version: userAgent,
13500
+ browser_online: "true",
13501
+ timezone_name: "Asia/Shanghai",
13502
+ support_h265: "1",
13503
+ msToken: params.cookies.find((e)=>"msToken" === e.name)?.value || "",
13504
+ a_bogus: ""
13505
+ };
13506
+ task.logger.info(`[douyinPublish] publishParams ${JSON.stringify(publishParams)}`);
13507
+ const publishData = {
13508
+ item: {
13509
+ common: {
13510
+ text: params.content,
13511
+ text_extra: params.textExtra,
13512
+ activity: "[]",
13513
+ challenges: params.challengeIds || "[]",
13514
+ hashtag_source: "",
13515
+ mentions: "[]",
13516
+ music_id: params.musicId || "",
13517
+ music_end_time: 1000 * (params.musicDuration || 0),
13518
+ hot_sentence: params.hotSentence || "",
13519
+ visibility_type: Number(params.visibleRange) || 0,
13520
+ download: params.allowSave ? 1 : 0,
13521
+ timing: params.isImmediatelyPublish ? -1 : params.scheduledPublish,
13522
+ media_type: Number(params.publishType) || 2,
13523
+ images: [],
13524
+ creation_id: ""
13525
+ },
13526
+ cover: {
13527
+ poster: ""
13528
+ },
13529
+ mix: params.mix ? {
13530
+ mix_id: params.mix.mix_id,
13531
+ mix_order: params.mix.mix_order || 0
13532
+ } : {},
13533
+ anchor: {},
13534
+ declare: {
13535
+ user_declare_info: "{}"
13536
+ }
13537
+ }
13538
+ };
13539
+ const args = [
13540
+ {
13541
+ headers
13513
13542
  },
13514
- mix: params.mix ? {
13515
- mix_id: params.mix.mix_id,
13516
- mix_order: params.mix.mix_order || 0
13517
- } : {},
13518
- anchor: {},
13519
- declare: {
13520
- user_declare_info: "{}"
13543
+ task.logger,
13544
+ "",
13545
+ "",
13546
+ params.accountId,
13547
+ "douyin"
13548
+ ];
13549
+ const http = new Http({
13550
+ headers
13551
+ });
13552
+ const proxyHttp = new Http(...args);
13553
+ const uploadedImgList = params.uploadedImgList ? JSON.parse(params.uploadedImgList) : [];
13554
+ if (uploadedImgList.length > 0) publishData.item.common.images = uploadedImgList;
13555
+ else {
13556
+ const tmpCachePath = task.getTmpPath();
13557
+ const uploader = new DouyinImageUploader(proxyHttp, headers, publishParams, tmpCachePath);
13558
+ if (params.coverImage) {
13559
+ const cover = await uploader.uploadCover(params.coverImage);
13560
+ if (cover) {
13561
+ publishData.item.common.images.push({
13562
+ uri: cover.uri,
13563
+ width: cover.width,
13564
+ height: cover.height
13565
+ });
13566
+ publishData.item.cover = {
13567
+ poster: cover.uri
13568
+ };
13569
+ }
13570
+ }
13571
+ if (params.banners && params.banners.length > 0) {
13572
+ const banners = params.banners.filter((i)=>i !== params.coverImage);
13573
+ const uploadResults = await uploader.uploadImages(banners);
13574
+ publishData.item.common.images = publishData.item.common.images.concat(uploadResults.map((result)=>({
13575
+ uri: result.uri,
13576
+ width: result.width,
13577
+ height: result.height
13578
+ })));
13521
13579
  }
13522
13580
  }
13523
- };
13524
- const args = [
13525
- {
13526
- headers
13527
- },
13528
- task.logger,
13529
- "",
13530
- "",
13531
- params.accountId,
13532
- "douyin"
13533
- ];
13534
- const http = new Http({
13535
- headers
13536
- });
13537
- const proxyHttp = new Http(...args);
13538
- const uploadedImgList = params.uploadedImgList ? JSON.parse(params.uploadedImgList) : [];
13539
- if (uploadedImgList.length > 0) publishData.item.common.images = uploadedImgList;
13540
- else {
13541
- const tmpCachePath = task.getTmpPath();
13542
- const uploader = new DouyinImageUploader(proxyHttp, headers, publishParams, tmpCachePath);
13543
- if (params.coverImage) {
13544
- const cover = await uploader.uploadCover(params.coverImage);
13545
- if (cover) {
13546
- publishData.item.common.images.push({
13547
- uri: cover.uri,
13548
- width: cover.width,
13549
- height: cover.height
13550
- });
13551
- publishData.item.cover = {
13552
- poster: cover.uri
13581
+ publishData.item.common.creation_id = generateRandomString(8) + Date.now();
13582
+ let decision = null;
13583
+ proxyHttp.addResponseInterceptor((response)=>{
13584
+ task.logger.info(`[douyinPublish] 拦截器收到响应response.headers: ${JSON.stringify(response.headers)} `);
13585
+ task.logger.info(`[douyinPublish] 拦截器收到响应response.data: ${JSON.stringify(response.data)} `);
13586
+ decision = parseVerifyPassportDecision(response.headers["x-tt-verify-passport-decision"]);
13587
+ if (needsVerification(decision)) {
13588
+ task.logger.info(`[douyinPublish] 检测到需要验证: ${JSON.stringify(decision)}`);
13589
+ return;
13590
+ }
13591
+ if (!response || !response.data) return;
13592
+ const responseData = response.data;
13593
+ if (response && responseData?.status_code && 0 !== responseData.status_code) {
13594
+ const errorCode = 4 === responseData.status_code ? 500 : responseData.status_code;
13595
+ if (4 === responseData.status_code) task.logger.warn(`[douyinPublish] 抖音服务器错误 status_code: 4,映射为 500 触发重试。原始响应: ${JSON.stringify(responseData)}`);
13596
+ return {
13597
+ code: errorCode,
13598
+ message: responseData.status_msg || "文章发布异常,请稍后重试。",
13599
+ data: responseData
13553
13600
  };
13554
13601
  }
13602
+ });
13603
+ task._timerRecord.PrePublish = Date.now();
13604
+ if (MockPublish) {
13605
+ const data = "123456789";
13606
+ const message = `图文模拟发布成功 ${http.proxyInfo}`;
13607
+ await updateTaskState?.({
13608
+ state: share_namespaceObject.TaskState.SUCCESS,
13609
+ result: {
13610
+ response: data
13611
+ }
13612
+ });
13613
+ return (0, share_namespaceObject.response)(0, message, data);
13555
13614
  }
13556
- if (params.banners && params.banners.length > 0) {
13557
- const banners = params.banners.filter((i)=>i !== params.coverImage);
13558
- const uploadResults = await uploader.uploadImages(banners);
13559
- publishData.item.common.images = publishData.item.common.images.concat(uploadResults.map((result)=>({
13560
- uri: result.uri,
13561
- width: result.width,
13562
- height: result.height
13563
- })));
13564
- }
13565
- }
13566
- publishData.item.common.creation_id = generateRandomString(8) + Date.now();
13567
- let decision = null;
13568
- proxyHttp.addResponseInterceptor((response)=>{
13569
- task.logger.info(`[douyinPublish] 拦截器收到响应response.headers: ${JSON.stringify(response.headers)} `);
13570
- task.logger.info(`[douyinPublish] 拦截器收到响应response.data: ${JSON.stringify(response.data)} `);
13571
- decision = parseVerifyPassportDecision(response.headers["x-tt-verify-passport-decision"]);
13572
- if (needsVerification(decision)) {
13573
- task.logger.info(`[douyinPublish] 检测到需要验证: ${JSON.stringify(decision)}`);
13574
- return;
13615
+ let webProtectData;
13616
+ try {
13617
+ webProtectData = JSON.parse(JSON.parse(params.extraParam["security-sdk/s_sdk_sign_data_key/web_protect"] || "{}").data || "{}");
13618
+ if (!webProtectData.ticket || !webProtectData.ts_sign || !webProtectData.client_cert) {
13619
+ task.logger.error(`webProtectData 关键字段缺失: ${JSON.stringify(webProtectData)}`);
13620
+ return (0, share_namespaceObject.response)(414, "安全参数 webProtectData 不完整,请重新获取后重试", "");
13621
+ }
13622
+ } catch (error) {
13623
+ task.logger.error(`解析 webProtectData 失败: ${error}`);
13624
+ return (0, share_namespaceObject.response)(414, "安全参数 webProtectData 解析失败,请重新获取后重试", "");
13625
+ }
13626
+ let ticket = webProtectData.ticket;
13627
+ let ts_sign = webProtectData.ts_sign;
13628
+ const serverDataCookie = params.cookies.find((it)=>"bd_ticket_guard_server_data" === it.name)?.value;
13629
+ if (serverDataCookie) try {
13630
+ const decoded = JSON.parse(Buffer.from(decodeURIComponent(serverDataCookie), "base64").toString("utf8"));
13631
+ if (decoded.ticket && decoded.ts_sign) {
13632
+ if (decoded.ticket !== ticket) task.logger.info("[douyinPublish] 使用 cookie 中的最新 ticket(web_protect 已过期)");
13633
+ ticket = decoded.ticket;
13634
+ ts_sign = decoded.ts_sign;
13635
+ }
13636
+ } catch (error) {
13637
+ task.logger.info(`[douyinPublish] 解析 bd_ticket_guard_server_data 失败,回退到 web_protect: ${error}`);
13575
13638
  }
13576
- if (!response || !response.data) return;
13577
- const responseData = response.data;
13578
- if (response && responseData?.status_code && 0 !== responseData.status_code) {
13579
- const errorCode = 4 === responseData.status_code ? 500 : responseData.status_code;
13580
- if (4 === responseData.status_code) task.logger.warn(`[douyinPublish] 抖音服务器错误 status_code: 4,映射为 500 触发重试。原始响应: ${JSON.stringify(responseData)}`);
13581
- return {
13582
- code: errorCode,
13583
- message: responseData.status_msg || "文章发布异常,请稍后重试。",
13584
- data: responseData
13585
- };
13639
+ let ec_privateKey;
13640
+ try {
13641
+ ec_privateKey = JSON.parse(JSON.parse(params.extraParam["security-sdk/s_sdk_crypt_sdk"] || "{}").data || "{}").ec_privateKey;
13642
+ if (!ec_privateKey) {
13643
+ task.logger.error("[douyinPublish] ec_privateKey 为空");
13644
+ return (0, share_namespaceObject.response)(414, "安全参数 ec_privateKey 缺失,请重新获取后重试", "");
13645
+ }
13646
+ } catch (error) {
13647
+ task.logger.error(`[douyinPublish] 解析 ec_privateKey 失败: ${error}`);
13648
+ return (0, share_namespaceObject.response)(414, "安全参数 ec_privateKey 解析失败,请重新获取后重试", "");
13586
13649
  }
13587
- });
13588
- task._timerRecord.PrePublish = Date.now();
13589
- if (MockPublish) {
13590
- const data = "123456789";
13591
- const message = `图文模拟发布成功 ${http.proxyInfo}`;
13592
- await updateTaskState?.({
13593
- state: share_namespaceObject.TaskState.SUCCESS,
13594
- result: {
13595
- response: data
13650
+ let certificate;
13651
+ try {
13652
+ certificate = JSON.parse(params.extraParam["security-sdk/s_sdk_server_cert_key"] || "{}").cert;
13653
+ if (!certificate) {
13654
+ task.logger.error("[douyinPublish] certificate 为空");
13655
+ return (0, share_namespaceObject.response)(414, "安全参数 certificate 缺失,请重新获取后重试", "");
13596
13656
  }
13597
- });
13598
- return (0, share_namespaceObject.response)(0, message, data);
13599
- }
13600
- let webProtectData;
13601
- try {
13602
- webProtectData = JSON.parse(JSON.parse(params.extraParam["security-sdk/s_sdk_sign_data_key/web_protect"] || "{}").data || "{}");
13603
- if (!webProtectData.ticket || !webProtectData.ts_sign || !webProtectData.client_cert) {
13604
- task.logger.error(`webProtectData 关键字段缺失: ${JSON.stringify(webProtectData)}`);
13605
- return (0, share_namespaceObject.response)(414, "安全参数 webProtectData 不完整,请重新获取后重试", "");
13657
+ } catch (error) {
13658
+ task.logger.error(`[douyinPublish] 解析 certificate 失败: ${error}`);
13659
+ return (0, share_namespaceObject.response)(414, "安全参数 certificate 解析失败,请重新获取后重试", "");
13606
13660
  }
13607
- } catch (error) {
13608
- task.logger.error(`解析 webProtectData 失败: ${error}`);
13609
- return (0, share_namespaceObject.response)(414, "安全参数 webProtectData 解析失败,请重新获取后重试", "");
13610
- }
13611
- let ticket = webProtectData.ticket;
13612
- let ts_sign = webProtectData.ts_sign;
13613
- const serverDataCookie = params.cookies.find((it)=>"bd_ticket_guard_server_data" === it.name)?.value;
13614
- if (serverDataCookie) try {
13615
- const decoded = JSON.parse(Buffer.from(decodeURIComponent(serverDataCookie), "base64").toString("utf8"));
13616
- if (decoded.ticket && decoded.ts_sign) {
13617
- if (decoded.ticket !== ticket) task.logger.info("[douyinPublish] 使用 cookie 中的最新 ticket(web_protect 已过期)");
13618
- ticket = decoded.ticket;
13619
- ts_sign = decoded.ts_sign;
13661
+ const ree_public_key = webProtectData.client_cert.replace("pub.", "");
13662
+ let bdTicketGuardClientData;
13663
+ try {
13664
+ bdTicketGuardClientData = getBdV2({
13665
+ ticket,
13666
+ ts_sign: ts_sign,
13667
+ ec_privateKey: ec_privateKey,
13668
+ certificate: certificate,
13669
+ bd_ticket_guard_ree_public_key: ree_public_key
13670
+ });
13671
+ if (!bdTicketGuardClientData || !bdTicketGuardClientData["headers_bd_ticket_guard_client_data"]) {
13672
+ task.logger.error(`[douyinPublish] bdTicketGuardClientData 生成失败或不完整: ${JSON.stringify(bdTicketGuardClientData)}`);
13673
+ return (0, share_namespaceObject.response)(414, "安全参数 bdTicketGuardClientData 生成失败,请重新获取后重试", "");
13674
+ }
13675
+ } catch (error) {
13676
+ task.logger.error(`[douyinPublish] 生成 bdTicketGuardClientData 失败: ${error}`);
13677
+ return (0, share_namespaceObject.response)(414, "安全参数 bdTicketGuardClientData 生成异常,请重新获取后重试", "");
13620
13678
  }
13621
- } catch (error) {
13622
- task.logger.info(`[douyinPublish] 解析 bd_ticket_guard_server_data 失败,回退到 web_protect: ${error}`);
13623
- }
13624
- let ec_privateKey;
13625
- try {
13626
- ec_privateKey = JSON.parse(JSON.parse(params.extraParam["security-sdk/s_sdk_crypt_sdk"] || "{}").data || "{}").ec_privateKey;
13627
- if (!ec_privateKey) {
13628
- task.logger.error("[douyinPublish] ec_privateKey 为空");
13629
- return (0, share_namespaceObject.response)(414, "安全参数 ec_privateKey 缺失,请重新获取后重试", "");
13679
+ task.logger.info("[douyinPublish] bdTicketGuardClientData 生成成功");
13680
+ const publishQuery = {
13681
+ ...publishParams,
13682
+ a_bogus: ""
13683
+ };
13684
+ const queryString = new URLSearchParams(publishQuery).toString();
13685
+ let aBogus;
13686
+ try {
13687
+ aBogus = mock_getABogus(`https://creator.douyin.com/web/api/media/aweme/create_v2/?${queryString}`, publishData, userAgent);
13688
+ if (!aBogus || aBogus.length < 10) {
13689
+ task.logger.error(`[douyinPublish] a_bogus 生成异常,长度过短: ${aBogus}`);
13690
+ return (0, share_namespaceObject.response)(414, "安全参数 a_bogus 生成失败,请重试", "");
13691
+ }
13692
+ } catch (error) {
13693
+ task.logger.error(`[douyinPublish] 生成 a_bogus 失败: ${error}`);
13694
+ return (0, share_namespaceObject.response)(414, "安全参数 a_bogus 生成异常,请重试", "");
13630
13695
  }
13631
- } catch (error) {
13632
- task.logger.error(`[douyinPublish] 解析 ec_privateKey 失败: ${error}`);
13633
- return (0, share_namespaceObject.response)(414, "安全参数 ec_privateKey 解析失败,请重新获取后重试", "");
13634
- }
13635
- let certificate;
13636
- try {
13637
- certificate = JSON.parse(params.extraParam["security-sdk/s_sdk_server_cert_key"] || "{}").cert;
13638
- if (!certificate) {
13639
- task.logger.error("[douyinPublish] certificate 为空");
13640
- return (0, share_namespaceObject.response)(414, "安全参数 certificate 缺失,请重新获取后重试", "");
13696
+ publishQuery.a_bogus = aBogus;
13697
+ const publishQueryParams = new URLSearchParams(publishQuery).toString();
13698
+ let csrfToken;
13699
+ try {
13700
+ csrfToken = mock_generateCsrfTokenAdvanced({
13701
+ cookies: params.cookies,
13702
+ url: "https://creator.douyin.com/web/api/media/aweme/create_v2/",
13703
+ method: "POST",
13704
+ userAgent
13705
+ });
13706
+ if (!csrfToken || csrfToken.length < 10) {
13707
+ task.logger.error(`[douyinPublish] csrfToken 生成异常,长度过短: ${csrfToken}`);
13708
+ return (0, share_namespaceObject.response)(414, "安全参数 csrfToken 生成失败,请重试", "");
13709
+ }
13710
+ task.logger.info(`[douyinPublish] csrfToken 生成成功: ${csrfToken.substring(0, 20)}...`);
13711
+ } catch (error) {
13712
+ task.logger.error(`[douyinPublish] 生成 csrfToken 失败: ${error}`);
13713
+ return (0, share_namespaceObject.response)(414, "安全参数 csrfToken 生成异常,请重试", "");
13641
13714
  }
13642
- } catch (error) {
13643
- task.logger.error(`[douyinPublish] 解析 certificate 失败: ${error}`);
13644
- return (0, share_namespaceObject.response)(414, "安全参数 certificate 解析失败,请重新获取后重试", "");
13645
- }
13646
- const ree_public_key = webProtectData.client_cert.replace("pub.", "");
13647
- let bdTicketGuardClientData;
13648
- try {
13649
- bdTicketGuardClientData = getBdV2({
13650
- ticket,
13651
- ts_sign: ts_sign,
13652
- ec_privateKey: ec_privateKey,
13653
- certificate: certificate,
13654
- bd_ticket_guard_ree_public_key: ree_public_key
13655
- });
13656
- if (!bdTicketGuardClientData || !bdTicketGuardClientData["headers_bd_ticket_guard_client_data"]) {
13657
- task.logger.error(`[douyinPublish] bdTicketGuardClientData 生成失败或不完整: ${JSON.stringify(bdTicketGuardClientData)}`);
13658
- return (0, share_namespaceObject.response)(414, "安全参数 bdTicketGuardClientData 生成失败,请重新获取后重试", "");
13715
+ let sessionDtrait;
13716
+ try {
13717
+ sessionDtrait = mock_generateDtrait("/web/api/media/aweme/create_v2/");
13718
+ task.logger.info(`[douyinPublish] sessionDtrait 生成成功: ${sessionDtrait || "(空)"}`);
13719
+ } catch (error) {
13720
+ task.logger.error(`[douyinPublish] 生成 sessionDtrait 失败: ${error}`);
13721
+ return (0, share_namespaceObject.response)(414, "安全参数 sessionDtrait 生成异常,请重试", "");
13659
13722
  }
13660
- } catch (error) {
13661
- task.logger.error(`[douyinPublish] 生成 bdTicketGuardClientData 失败: ${error}`);
13662
- return (0, share_namespaceObject.response)(414, "安全参数 bdTicketGuardClientData 生成异常,请重新获取后重试", "");
13663
- }
13664
- task.logger.info("[douyinPublish] bdTicketGuardClientData 生成成功");
13665
- const publishQuery = {
13666
- ...publishParams,
13667
- a_bogus: ""
13668
- };
13669
- const queryString = new URLSearchParams(publishQuery).toString();
13670
- let aBogus;
13671
- try {
13672
- aBogus = mock_getABogus(`https://creator.douyin.com/web/api/media/aweme/create_v2/?${queryString}`, publishData, userAgent);
13673
- if (!aBogus || aBogus.length < 10) {
13674
- task.logger.error(`[douyinPublish] a_bogus 生成异常,长度过短: ${aBogus}`);
13675
- return (0, share_namespaceObject.response)(414, "安全参数 a_bogus 生成失败,请重试", "");
13723
+ task.logger.info(`[douyinPublish] headers: ${JSON.stringify({
13724
+ ...headers,
13725
+ Referer: "https://creator.douyin.com/creator-micro/content/post/image?default-tab=3&enter_from=publish_page&media_type=image&type=new",
13726
+ "Content-Type": "application/json",
13727
+ Accept: "application/json, text/plain, */*",
13728
+ "bd-ticket-guard-client-data": bdTicketGuardClientData["headers_bd_ticket_guard_client_data"],
13729
+ "bd-ticket-guard-ree-public-key": bdTicketGuardClientData["headers_bd_ticket_guard_ree_public_key"],
13730
+ "bd-ticket-guard-version": "2",
13731
+ "bd-ticket-guard-web-sign-type": "1",
13732
+ "bd-ticket-guard-web-version": "2",
13733
+ "x-secsdk-csrf-token": csrfToken,
13734
+ "x-tt-session-dtrait": sessionDtrait || ""
13735
+ })}`);
13736
+ task.logger.info(`[douyinPublish] url: https://creator.douyin.com/web/api/media/aweme/create_v2/?${publishQueryParams}`);
13737
+ let publishResult;
13738
+ try {
13739
+ publishResult = await proxyHttp.api({
13740
+ method: "post",
13741
+ url: `https://creator.douyin.com/web/api/media/aweme/create_v2/?${publishQueryParams}`,
13742
+ data: publishData,
13743
+ defaultErrorMsg: "发布异常,请稍后重试。",
13744
+ headers: {
13745
+ ...headers,
13746
+ Referer: "https://creator.douyin.com/creator-micro/content/post/image?default-tab=3&enter_from=publish_page&media_type=image&type=new",
13747
+ "Content-Type": "application/json",
13748
+ Accept: "application/json, text/plain, */*",
13749
+ "bd-ticket-guard-client-data": bdTicketGuardClientData["headers_bd_ticket_guard_client_data"],
13750
+ "bd-ticket-guard-ree-public-key": bdTicketGuardClientData["headers_bd_ticket_guard_ree_public_key"],
13751
+ "bd-ticket-guard-version": "2",
13752
+ "bd-ticket-guard-web-sign-type": "1",
13753
+ "bd-ticket-guard-web-version": "2",
13754
+ "x-secsdk-csrf-token": csrfToken,
13755
+ "x-tt-session-dtrait": sessionDtrait || ""
13756
+ }
13757
+ }, {
13758
+ timeout: 60000,
13759
+ retries: 3,
13760
+ retryDelay: 2000
13761
+ });
13762
+ } catch (error) {
13763
+ const handledError = Http.handleApiError(error);
13764
+ const isProxyOrNetworkError = [
13765
+ 599,
13766
+ 500,
13767
+ 502,
13768
+ 503,
13769
+ 504
13770
+ ].includes(handledError.code);
13771
+ if (isProxyOrNetworkError) {
13772
+ const isProxyRequest = handledError.extra?.isProxyRequest === true;
13773
+ const errorType = 599 === handledError.code || isProxyRequest ? "代理错误" : "网络错误";
13774
+ const message = `图文发布失败,${errorType}:${handledError.message}${task.debug ? ` ${http.proxyInfo}` : ""}`;
13775
+ task.logger.error(`[douyinPublish] ${errorType},直接返回: ${message}`, stringifyError(handledError));
13776
+ await updateTaskState?.({
13777
+ state: share_namespaceObject.TaskState.FAILED,
13778
+ error: message
13779
+ });
13780
+ return {
13781
+ code: 414,
13782
+ data: "",
13783
+ message
13784
+ };
13785
+ }
13786
+ throw error;
13676
13787
  }
13677
- } catch (error) {
13678
- task.logger.error(`[douyinPublish] 生成 a_bogus 失败: ${error}`);
13679
- return (0, share_namespaceObject.response)(414, "安全参数 a_bogus 生成异常,请重试", "");
13680
- }
13681
- publishQuery.a_bogus = aBogus;
13682
- const publishQueryParams = new URLSearchParams(publishQuery).toString();
13683
- let csrfToken;
13684
- try {
13685
- csrfToken = mock_generateCsrfTokenAdvanced({
13686
- cookies: params.cookies,
13687
- url: "https://creator.douyin.com/web/api/media/aweme/create_v2/",
13688
- method: "POST",
13689
- userAgent
13690
- });
13691
- if (!csrfToken || csrfToken.length < 10) {
13692
- task.logger.error(`[douyinPublish] csrfToken 生成异常,长度过短: ${csrfToken}`);
13693
- return (0, share_namespaceObject.response)(414, "安全参数 csrfToken 生成失败,请重试", "");
13788
+ task.logger.info(`[douyinPublish] decision值: ${JSON.stringify(decision)}, needsVerification(decision): ${needsVerification(decision)}`);
13789
+ if (needsVerification(decision)) {
13790
+ const details = [
13791
+ publishResult.status_msg,
13792
+ decision?.verify_title,
13793
+ decision?.verify_desc
13794
+ ].filter(Boolean).join(" ");
13795
+ const message = `图文发布失败,原因:${details}${task.debug ? ` ${http.proxyInfo}` : ""}`;
13796
+ const safeDecision = safeSerialize(decision) ?? {};
13797
+ const mockData = {
13798
+ state: share_namespaceObject.TaskState.FAILED,
13799
+ error: message,
13800
+ result: {
13801
+ ...safeDecision,
13802
+ data: decision,
13803
+ uploadedImgList: JSON.stringify(publishData.item.common.images)
13804
+ }
13805
+ };
13806
+ await updateTaskState?.(mockData);
13807
+ return {
13808
+ code: 0,
13809
+ data: mockData,
13810
+ message: "操作成功"
13811
+ };
13694
13812
  }
13695
- task.logger.info(`[douyinPublish] csrfToken 生成成功: ${csrfToken.substring(0, 20)}...`);
13696
- } catch (error) {
13697
- task.logger.error(`[douyinPublish] 生成 csrfToken 失败: ${error}`);
13698
- return (0, share_namespaceObject.response)(414, "安全参数 csrfToken 生成异常,请重试", "");
13699
- }
13700
- let sessionDtrait;
13701
- try {
13702
- sessionDtrait = mock_generateDtrait("/web/api/media/aweme/create_v2/");
13703
- task.logger.info(`[douyinPublish] sessionDtrait 生成成功: ${sessionDtrait || "(空)"}`);
13704
- } catch (error) {
13705
- task.logger.error(`[douyinPublish] 生成 sessionDtrait 失败: ${error}`);
13706
- return (0, share_namespaceObject.response)(414, "安全参数 sessionDtrait 生成异常,请重试", "");
13707
- }
13708
- task.logger.info(`[douyinPublish] headers: ${JSON.stringify({
13709
- ...headers,
13710
- Referer: "https://creator.douyin.com/creator-micro/content/post/image?default-tab=3&enter_from=publish_page&media_type=image&type=new",
13711
- "Content-Type": "application/json",
13712
- Accept: "application/json, text/plain, */*",
13713
- "bd-ticket-guard-client-data": bdTicketGuardClientData["headers_bd_ticket_guard_client_data"],
13714
- "bd-ticket-guard-ree-public-key": bdTicketGuardClientData["headers_bd_ticket_guard_ree_public_key"],
13715
- "bd-ticket-guard-version": "2",
13716
- "bd-ticket-guard-web-sign-type": "1",
13717
- "bd-ticket-guard-web-version": "2",
13718
- "x-secsdk-csrf-token": csrfToken,
13719
- "x-tt-session-dtrait": sessionDtrait || ""
13720
- })}`);
13721
- task.logger.info(`[douyinPublish] url: https://creator.douyin.com/web/api/media/aweme/create_v2/?${publishQueryParams}`);
13722
- let publishResult;
13723
- try {
13724
- publishResult = await proxyHttp.api({
13725
- method: "post",
13726
- url: `https://creator.douyin.com/web/api/media/aweme/create_v2/?${publishQueryParams}`,
13727
- data: publishData,
13728
- defaultErrorMsg: "发布异常,请稍后重试。",
13729
- headers: {
13730
- ...headers,
13731
- Referer: "https://creator.douyin.com/creator-micro/content/post/image?default-tab=3&enter_from=publish_page&media_type=image&type=new",
13732
- "Content-Type": "application/json",
13733
- Accept: "application/json, text/plain, */*",
13734
- "bd-ticket-guard-client-data": bdTicketGuardClientData["headers_bd_ticket_guard_client_data"],
13735
- "bd-ticket-guard-ree-public-key": bdTicketGuardClientData["headers_bd_ticket_guard_ree_public_key"],
13736
- "bd-ticket-guard-version": "2",
13737
- "bd-ticket-guard-web-sign-type": "1",
13738
- "bd-ticket-guard-web-version": "2",
13739
- "x-secsdk-csrf-token": csrfToken,
13740
- "x-tt-session-dtrait": sessionDtrait || ""
13741
- }
13742
- }, {
13743
- timeout: 60000,
13744
- retries: 3,
13745
- retryDelay: 2000
13813
+ reportLogger({
13814
+ token: params.huiwenToken || "",
13815
+ enverionment: task.enverionment || "development",
13816
+ postId: params.articleId,
13817
+ eip: proxyHttp.proxyInfo,
13818
+ proxyIp: params.localIP,
13819
+ accountId: params.accountId,
13820
+ uid: params.uid,
13821
+ platform: "douyin",
13822
+ publishParams: publishData
13746
13823
  });
13747
- } catch (error) {
13748
- const handledError = Http.handleApiError(error);
13749
- const isProxyOrNetworkError = [
13750
- 599,
13751
- 500,
13752
- 502,
13753
- 503,
13754
- 504
13755
- ].includes(handledError.code);
13756
- if (isProxyOrNetworkError) {
13757
- const isProxyRequest = handledError.extra?.isProxyRequest === true;
13758
- const errorType = 599 === handledError.code || isProxyRequest ? "代理错误" : "网络错误";
13759
- const message = `图文发布失败,${errorType}:${handledError.message}${task.debug ? ` ${http.proxyInfo}` : ""}`;
13760
- task.logger.error(`[douyinPublish] ${errorType},直接返回: ${message}`, stringifyError(handledError));
13824
+ task.logger.info(`[douyinPublish] 发布结果 ${JSON.stringify(publishResult)}`);
13825
+ const isSuccess = 0 === publishResult.status_code;
13826
+ const message = `图文发布${isSuccess ? "成功" : `失败,原因:${publishResult.status_msg} ${decision?.verify_title} ${decision?.verify_desc}`}${task.debug ? ` ${http.proxyInfo}` : ""}`;
13827
+ const data = isSuccess ? publishResult.item_id || "" : "";
13828
+ if (!isSuccess) {
13829
+ const safeDecision = safeSerialize(decision) ?? {};
13761
13830
  await updateTaskState?.({
13762
13831
  state: share_namespaceObject.TaskState.FAILED,
13763
- error: message
13832
+ error: message,
13833
+ result: {
13834
+ ...safeDecision,
13835
+ data: safeDecision,
13836
+ uploadedImgList: JSON.stringify(publishData.item.common.images)
13837
+ }
13764
13838
  });
13765
13839
  return {
13766
- code: 414,
13767
- data: "",
13768
- message
13769
- };
13770
- }
13771
- throw error;
13772
- }
13773
- task.logger.info(`[douyinPublish] decision值: ${JSON.stringify(decision)}, needsVerification(decision): ${needsVerification(decision)}`);
13774
- if (needsVerification(decision)) {
13775
- const details = [
13776
- publishResult.status_msg,
13777
- decision?.verify_title,
13778
- decision?.verify_desc
13779
- ].filter(Boolean).join(" ");
13780
- const message = `图文发布失败,原因:${details}${task.debug ? ` ${http.proxyInfo}` : ""}`;
13781
- let decisionObj = {};
13782
- if (decision) decisionObj = decision;
13783
- const mockData = {
13784
- state: share_namespaceObject.TaskState.FAILED,
13785
- error: message,
13840
+ code: 414,
13841
+ data: safeDecision,
13842
+ message
13843
+ };
13844
+ }
13845
+ await updateTaskState?.({
13846
+ state: share_namespaceObject.TaskState.SUCCESS,
13786
13847
  result: {
13787
- ...decisionObj,
13788
- data: decision,
13789
- uploadedImgList: JSON.stringify(publishData.item.common.images)
13848
+ response: data
13790
13849
  }
13791
- };
13792
- await updateTaskState?.(mockData);
13793
- return {
13794
- code: 0,
13795
- data: mockData,
13796
- message: "操作成功"
13797
- };
13798
- }
13799
- reportLogger({
13800
- token: params.huiwenToken || "",
13801
- enverionment: task.enverionment || "development",
13802
- postId: params.articleId,
13803
- eip: proxyHttp.proxyInfo,
13804
- proxyIp: params.localIP,
13805
- accountId: params.accountId,
13806
- uid: params.uid,
13807
- platform: "douyin",
13808
- publishParams: publishData
13809
- });
13810
- task.logger.info(`[douyinPublish] 发布结果 ${JSON.stringify(publishResult)}`);
13811
- const isSuccess = 0 === publishResult.status_code;
13812
- const message = `图文发布${isSuccess ? "成功" : `失败,原因:${publishResult.status_msg} ${decision?.verify_title} ${decision?.verify_desc}`}${task.debug ? ` ${http.proxyInfo}` : ""}`;
13813
- const data = isSuccess ? publishResult.item_id || "" : "";
13814
- if (!isSuccess) {
13815
- let decisionObj = {};
13816
- if (decision) decisionObj = decision;
13850
+ });
13851
+ return (0, share_namespaceObject.response)(isSuccess ? 0 : 414, message, data);
13852
+ } catch (error) {
13853
+ const handledError = Http.handleApiError(error);
13854
+ const errorMsg = handledError.message || "发布失败";
13855
+ const errorCode = handledError.code || 500;
13856
+ task.logger.error(`[douyinPublish] 发布流程异常 (步骤: ${currentStep}): ${errorMsg}`, stringifyError(error), handledError.extra);
13817
13857
  await updateTaskState?.({
13818
13858
  state: share_namespaceObject.TaskState.FAILED,
13819
- error: message,
13820
- result: {
13821
- ...decisionObj,
13822
- data: decision,
13823
- uploadedImgList: JSON.stringify(publishData.item.common.images)
13824
- }
13859
+ error: `${currentStep}失败: ${errorMsg}`
13825
13860
  });
13826
- return {
13827
- code: 414,
13828
- data,
13829
- message
13830
- };
13861
+ return (0, share_namespaceObject.response)(errorCode, errorMsg, "");
13831
13862
  }
13832
- await updateTaskState?.({
13833
- state: share_namespaceObject.TaskState.SUCCESS,
13834
- result: {
13835
- response: data
13836
- }
13837
- });
13838
- return (0, share_namespaceObject.response)(isSuccess ? 0 : 414, message, data);
13839
13863
  };
13840
13864
  const douyinPublish_rpa_rpaAction = async (task, params)=>{
13841
13865
  const commonCookies = {
@@ -15361,6 +15385,241 @@ var __webpack_exports__ = {};
15361
15385
  };
15362
15386
  return (0, share_namespaceObject.success)(bjhData, "百家号平台数据获取成功!");
15363
15387
  }
15388
+ async function getDouyinData(_task, params) {
15389
+ try {
15390
+ const sessionidCookie = params.cookies.find((it)=>"sessionid" === it.name)?.value;
15391
+ if (!sessionidCookie) return types_errorResponse("抖音账号数据异常,请重新绑定账号后重试。", 414);
15392
+ const csrfToken = params.cookies.find((it)=>"passport_csrf_token" === it.name)?.value || "";
15393
+ const headers = {
15394
+ cookie: params.cookies.map((it)=>`${it.name}=${it.value}`).join(";"),
15395
+ referer: "https://creator.douyin.com/creator-micro/home",
15396
+ origin: "https://creator.douyin.com",
15397
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
15398
+ ...csrfToken ? {
15399
+ "x-secsdk-csrf-token": csrfToken
15400
+ } : {}
15401
+ };
15402
+ const args = [
15403
+ {
15404
+ headers
15405
+ },
15406
+ _task.logger,
15407
+ params.proxyLoc,
15408
+ params.localIP,
15409
+ params.accountId
15410
+ ];
15411
+ const http = new Http(...args);
15412
+ const toNum = (val)=>{
15413
+ if (null == val) return 0;
15414
+ const n = Number.parseInt(String(val).replace(/[+,]/g, ""), 10);
15415
+ return Number.isNaN(n) ? 0 : n;
15416
+ };
15417
+ const userProfileP = http.api({
15418
+ method: "get",
15419
+ url: "https://www.douyin.com/aweme/v1/web/user/profile/self/",
15420
+ params: {
15421
+ device_platform: "webapp",
15422
+ aid: "6383",
15423
+ channel: "channel_pc_web",
15424
+ pc_client_type: "1",
15425
+ version_code: "170400",
15426
+ version_name: "17.4.0",
15427
+ cookie_enabled: "true",
15428
+ platform: "PC"
15429
+ }
15430
+ }, {
15431
+ retries: 3,
15432
+ retryDelay: 100,
15433
+ timeout: 10000
15434
+ }).catch((e)=>{
15435
+ _task.logger.warn(`抖音用户信息获取失败: ${e instanceof Error ? e.message : String(e)}`);
15436
+ return null;
15437
+ });
15438
+ const overviewP = http.api({
15439
+ method: "get",
15440
+ url: "https://creator.douyin.com/aweme/janus/creator/data/overview/all/",
15441
+ params: {
15442
+ last_days_type: 1,
15443
+ aid: 2906,
15444
+ app_name: "aweme_creator_platform",
15445
+ device_platform: "web"
15446
+ }
15447
+ }, {
15448
+ retries: 3,
15449
+ retryDelay: 100,
15450
+ timeout: 5000
15451
+ }).catch((e)=>{
15452
+ _task.logger.warn(`抖音近7日数据获取失败(可能未开通数据中心或被风控): ${e instanceof Error ? e.message : String(e)}`);
15453
+ return null;
15454
+ });
15455
+ const [userProfile, overview] = await Promise.all([
15456
+ userProfileP,
15457
+ overviewP
15458
+ ]);
15459
+ let fansNum = 0;
15460
+ let favedNum = 0;
15461
+ let followingNum = 0;
15462
+ if (userProfile?.status_code === 0 && userProfile.user) {
15463
+ const user = userProfile.user;
15464
+ fansNum = toNum(user.follower_count);
15465
+ followingNum = toNum(user.following_count);
15466
+ favedNum = toNum(user.total_favorited);
15467
+ } else _task.logger.warn(`用户信息接口返回异常: status_code=${userProfile?.status_code}, msg=${userProfile?.status_msg}`);
15468
+ const ov = overview?.data;
15469
+ const douyinData = {
15470
+ fansNum,
15471
+ favedNum,
15472
+ fansNumLastWeek: toNum(ov?.new_fans?.last_period_incr),
15473
+ watchNumLastWeek: toNum(ov?.play?.last_period_incr),
15474
+ likeNumLastWeek: toNum(ov?.digg?.last_period_incr),
15475
+ commentNumLastWeek: toNum(ov?.comment?.last_period_incr),
15476
+ shareNumLastWeek: toNum(ov?.share?.last_period_incr),
15477
+ visitNumLastWeek: toNum(ov?.profile?.last_period_incr)
15478
+ };
15479
+ return (0, share_namespaceObject.success)(douyinData, "抖音平台数据获取成功!");
15480
+ } catch (error) {
15481
+ if (error && "object" == typeof error && "code" in error && "message" in error) {
15482
+ const err = error;
15483
+ _task.logger.error(`抖音账号数据获取失败: ${err.message} (${err.code})`);
15484
+ return types_errorResponse(err.message, err.code);
15485
+ }
15486
+ const errMsg = error instanceof Error ? error.message : String(error);
15487
+ _task.logger.error(`抖音账号数据获取失败: ${errMsg}`);
15488
+ return types_errorResponse(errMsg || "抖音账号数据获取失败");
15489
+ }
15490
+ }
15491
+ async function getShipinhaoData(_task, params) {
15492
+ try {
15493
+ const sessionidCookie = params.cookies.find((it)=>"sessionid" === it.name)?.value;
15494
+ if (!sessionidCookie) return types_errorResponse("视频号账号数据异常,请重新绑定账号后重试。", 414);
15495
+ const uinCookie = params.cookies.find((it)=>"uin" === it.name || "wxuin" === it.name)?.value || "0000000000";
15496
+ const deviceIdCookie = params.cookies.find((it)=>"device_id" === it.name || "finger_print_device_id" === it.name)?.value;
15497
+ const aid = params.cookies.find((it)=>"_aid" === it.name)?.value || "9d3e0e9f-b842-498d-a273-4285d58df264";
15498
+ const finderId = params.cookies.find((it)=>"_log_finder_id" === it.name || "finder_id" === it.name)?.value || "";
15499
+ const headers = {
15500
+ cookie: params.cookies.map((it)=>`${it.name}=${it.value}`).join(";"),
15501
+ referer: "https://channels.weixin.qq.com/platform",
15502
+ origin: "https://channels.weixin.qq.com",
15503
+ "content-type": "application/json",
15504
+ "X-WECHAT-UIN": uinCookie,
15505
+ ...deviceIdCookie ? {
15506
+ "finger-print-device-id": deviceIdCookie
15507
+ } : {}
15508
+ };
15509
+ const args = [
15510
+ {
15511
+ headers
15512
+ },
15513
+ _task.logger,
15514
+ params.proxyLoc,
15515
+ params.localIP,
15516
+ params.accountId
15517
+ ];
15518
+ const http = new Http(...args);
15519
+ const authData = await http.api({
15520
+ method: "post",
15521
+ url: "https://channels.weixin.qq.com/cgi-bin/mmfinderassistant-bin/auth/auth_data",
15522
+ params: {
15523
+ _aid: aid,
15524
+ _rid: `${Date.now().toString(16)}-${Math.random().toString(36).substring(2, 9)}`,
15525
+ _pageUrl: encodeURIComponent("https://channels.weixin.qq.com/platform")
15526
+ },
15527
+ data: {
15528
+ timestamp: Date.now().toString(),
15529
+ _log_finder_uin: "",
15530
+ _log_finder_id: finderId,
15531
+ rawKeyBuff: "",
15532
+ pluginSessionId: null,
15533
+ scene: 7,
15534
+ reqScene: 7
15535
+ }
15536
+ }, {
15537
+ retries: 3,
15538
+ retryDelay: 100,
15539
+ timeout: 5000
15540
+ });
15541
+ const AUTH_ERROR_CODES = [
15542
+ 300333,
15543
+ 300334,
15544
+ 300330,
15545
+ 300331,
15546
+ 300332
15547
+ ];
15548
+ if (authData.errCode && AUTH_ERROR_CODES.includes(authData.errCode)) {
15549
+ _task.logger.warn(`视频号登录已失效:${authData.errMsg} (${authData.errCode})`);
15550
+ return types_errorResponse("视频号账号信息获取失败,请检查账号状态", 414);
15551
+ }
15552
+ if (authData.errCode) {
15553
+ _task.logger.warn(`视频号账号API错误:${authData.errMsg} (${authData.errCode})`);
15554
+ return types_errorResponse(`视频号账号信息获取失败:${authData.errMsg || "未知错误"}`, 414);
15555
+ }
15556
+ const finderUser = authData.data?.finderUser;
15557
+ const now = new Date();
15558
+ const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 2);
15559
+ const startTs = Math.floor(yesterday.getTime() / 1000);
15560
+ const endTs = startTs + 86400;
15561
+ _task.logger.info(`视频号昨日数据范围 start: ${startTs} ~ end: ${endTs}`);
15562
+ let fansNumYesterday = 0;
15563
+ let playNumYesterday = 0;
15564
+ let likeNumYesterday = 0;
15565
+ let commentNumYesterday = 0;
15566
+ try {
15567
+ const statsData = await http.api({
15568
+ method: "post",
15569
+ url: "https://channels.weixin.qq.com/cgi-bin/mmfinderassistant-bin/statistic/new_post_total_data",
15570
+ params: {
15571
+ _aid: aid,
15572
+ _rid: `${Date.now().toString(16)}-${Math.random().toString(36).substring(2, 9)}`,
15573
+ _pageUrl: encodeURIComponent("https://channels.weixin.qq.com/platform")
15574
+ },
15575
+ data: {
15576
+ startTs: startTs.toString(),
15577
+ endTs: endTs.toString(),
15578
+ interval: 3,
15579
+ timestamp: Date.now().toString(),
15580
+ _log_finder_uin: "",
15581
+ _log_finder_id: finderId,
15582
+ rawKeyBuff: "",
15583
+ pluginSessionId: null,
15584
+ scene: 7,
15585
+ reqScene: 7
15586
+ }
15587
+ }, {
15588
+ retries: 3,
15589
+ retryDelay: 100,
15590
+ timeout: 5000
15591
+ });
15592
+ if (!statsData.errCode && statsData.data?.totalData) {
15593
+ const data = statsData.data.totalData;
15594
+ fansNumYesterday = Number.parseInt(data.follow?.[1] || "0", 10) || 0;
15595
+ playNumYesterday = Number.parseInt(data.browse?.[1] || "0", 10) || 0;
15596
+ likeNumYesterday = Number.parseInt(data.like?.[1] || "0", 10) || 0;
15597
+ commentNumYesterday = Number.parseInt(data.comment?.[1] || "0", 10) || 0;
15598
+ }
15599
+ } catch (error) {
15600
+ const errMsg = error instanceof Error ? error.message : String(error);
15601
+ _task.logger.warn(`视频号昨日数据获取失败(降级为null): ${errMsg}`);
15602
+ }
15603
+ const shipinhaoData = {
15604
+ fansNum: finderUser?.fansCount || 0,
15605
+ feedsCount: finderUser?.feedsCount || 0,
15606
+ fansNumYesterday,
15607
+ playNumYesterday,
15608
+ likeNumYesterday,
15609
+ commentNumYesterday
15610
+ };
15611
+ return (0, share_namespaceObject.success)(shipinhaoData, "视频号平台数据获取成功!");
15612
+ } catch (error) {
15613
+ if (error && "object" == typeof error && "code" in error && "message" in error) {
15614
+ const err = error;
15615
+ _task.logger.error(`视频号账号数据获取失败: ${err.message} (${err.code})`);
15616
+ return types_errorResponse(err.message, err.code);
15617
+ }
15618
+ const errMsg = error instanceof Error ? error.message : String(error);
15619
+ _task.logger.error(`视频号账号数据获取失败: ${errMsg}`);
15620
+ return types_errorResponse(errMsg || "视频号账号数据获取失败");
15621
+ }
15622
+ }
15364
15623
  async function getToutiaoData(_task, params) {
15365
15624
  const http = new Http({
15366
15625
  headers: {
@@ -15459,7 +15718,7 @@ var __webpack_exports__ = {};
15459
15718
  userInfoHtmlPromise,
15460
15719
  userSummaryHtmlPromise
15461
15720
  ]);
15462
- if (userInfoHtml.includes("请重新<a id='jumpUrl' href='/'>登录</a>")) return types_errorResponse("Token已失效,请重新获取", 414);
15721
+ if (userInfoHtml.includes("请重新<a id='jumpUrl' href='/'>登录</a>")) return types_errorResponse("微信公众号数据获取失败,请检查账号状态", 414);
15463
15722
  const userInfoJson = exportWxCgiData(userInfoHtml);
15464
15723
  const userSummaryJson = exportWxCgiData(userSummaryHtml);
15465
15724
  const wxData = {
@@ -15536,7 +15795,9 @@ var __webpack_exports__ = {};
15536
15795
  "toutiao",
15537
15796
  "xiaohongshu",
15538
15797
  "weixin",
15539
- "baijiahao"
15798
+ "baijiahao",
15799
+ "douyin",
15800
+ "shipinhao"
15540
15801
  ])
15541
15802
  });
15542
15803
  const SearchAccountInfo = async (_task, params)=>{
@@ -15550,6 +15811,10 @@ var __webpack_exports__ = {};
15550
15811
  return getWeixinData(_task, params);
15551
15812
  case "baijiahao":
15552
15813
  return getBaijiahaoData(_task, params);
15814
+ case "douyin":
15815
+ return getDouyinData(_task, params);
15816
+ case "shipinhao":
15817
+ return getShipinhaoData(_task, params);
15553
15818
  default:
15554
15819
  return (0, share_namespaceObject.success)(null, "暂不支持该平台");
15555
15820
  }
@@ -15644,18 +15909,45 @@ var __webpack_exports__ = {};
15644
15909
  collectNum: schemas_number(),
15645
15910
  shareNum: schemas_number()
15646
15911
  });
15912
+ const DouyinArticleSchema = BaseArticleSchema.extend({
15913
+ playNum: schemas_number(),
15914
+ likeNum: schemas_number(),
15915
+ commentNum: schemas_number(),
15916
+ shareNum: schemas_number(),
15917
+ collectNum: schemas_number(),
15918
+ awemeId: schemas_string(),
15919
+ awemeType: schemas_number(),
15920
+ duration: schemas_number().optional(),
15921
+ status: schemas_string(),
15922
+ publicUrl: schemas_string()
15923
+ });
15924
+ const ShipinhaoArticleSchema = BaseArticleSchema.extend({
15925
+ readNum: schemas_number(),
15926
+ likeNum: schemas_number(),
15927
+ commentNum: schemas_number(),
15928
+ forwardNum: schemas_number(),
15929
+ favNum: schemas_number(),
15930
+ objectId: schemas_string(),
15931
+ postType: schemas_string(),
15932
+ postStatus: schemas_number(),
15933
+ effectiveTime: schemas_number().optional()
15934
+ });
15647
15935
  const FetchArticlesDataSchema = schemas_object({
15648
15936
  articleCell: schemas_array(union([
15649
15937
  ToutiaoArticleSchema,
15650
15938
  WeixinArticleSchema,
15651
15939
  BaijiahaoArticleSchema,
15652
- XiaohongshuArticleSchema
15940
+ XiaohongshuArticleSchema,
15941
+ DouyinArticleSchema,
15942
+ ShipinhaoArticleSchema
15653
15943
  ])).optional(),
15654
15944
  timerPublish: schemas_array(union([
15655
15945
  ToutiaoArticleSchema,
15656
15946
  WeixinArticleSchema,
15657
15947
  BaijiahaoArticleSchema,
15658
- XiaohongshuArticleSchema
15948
+ XiaohongshuArticleSchema,
15949
+ DouyinArticleSchema,
15950
+ ShipinhaoArticleSchema
15659
15951
  ])).optional(),
15660
15952
  pagination: schemas_object({
15661
15953
  total: schemas_number().optional(),
@@ -15770,6 +16062,269 @@ var __webpack_exports__ = {};
15770
16062
  return searchPublishInfo_types_errorResponse(error instanceof Error ? error.message : "百家号文章数据获取失败");
15771
16063
  }
15772
16064
  }
16065
+ async function handleDouyinData(_task, params) {
16066
+ try {
16067
+ const { cookies, pageSize = 12, status = 0, showOriginalData = false, onlySuccess = false } = params;
16068
+ const pageNum = params.pageNum || 1;
16069
+ const headers = {
16070
+ cookie: cookies.map((it)=>`${it.name}=${it.value}`).join(";"),
16071
+ referer: "https://creator.douyin.com"
16072
+ };
16073
+ const args = [
16074
+ {
16075
+ headers
16076
+ },
16077
+ _task.logger,
16078
+ params.proxyLoc,
16079
+ params.localIP,
16080
+ params.accountId
16081
+ ];
16082
+ const http = new Http(...args);
16083
+ async function fetchWorks(cursor) {
16084
+ return await http.api({
16085
+ method: "get",
16086
+ url: "https://creator.douyin.com/janus/douyin/creator/pc/work_list",
16087
+ params: {
16088
+ scene: "star_atlas",
16089
+ device_platform: "android",
16090
+ aid: 1128,
16091
+ status,
16092
+ count: pageSize,
16093
+ max_cursor: cursor
16094
+ }
16095
+ }, {
16096
+ retries: 3,
16097
+ retryDelay: 100,
16098
+ timeout: 5000
16099
+ });
16100
+ }
16101
+ const isHasMore = (v)=>true === v || 1 === v;
16102
+ const skipCount = (pageNum - 1) * pageSize;
16103
+ const needCount = skipCount + pageSize;
16104
+ const workListResponse = await fetchWorks(0);
16105
+ if (!workListResponse || !Array.isArray(workListResponse.aweme_list)) return searchPublishInfo_types_errorResponse("抖音数据获取失败,请检查账号状态", 414);
16106
+ const allWorks = [
16107
+ ...workListResponse.aweme_list
16108
+ ];
16109
+ let hasMore = isHasMore(workListResponse.has_more);
16110
+ let currentCursor = workListResponse.cursor ?? workListResponse.max_cursor ?? 0;
16111
+ let guard = 0;
16112
+ while(allWorks.length < needCount && hasMore && guard < 20){
16113
+ const nextPageResponse = await fetchWorks(currentCursor);
16114
+ if (!Array.isArray(nextPageResponse.aweme_list) || 0 === nextPageResponse.aweme_list.length) break;
16115
+ allWorks.push(...nextPageResponse.aweme_list);
16116
+ hasMore = isHasMore(nextPageResponse.has_more);
16117
+ currentCursor = nextPageResponse.cursor ?? nextPageResponse.max_cursor ?? currentCursor;
16118
+ guard++;
16119
+ }
16120
+ const finalWorks = allWorks.slice(skipCount, needCount);
16121
+ const articleCell = finalWorks.map((item)=>{
16122
+ const workDetailUrl = `https://creator.douyin.com/creator-micro/work-management/work-detail/${item.aweme_id}`;
16123
+ const workPublicUrl = item.share_url || `https://www.douyin.com/video/${item.aweme_id}`;
16124
+ let statusText;
16125
+ statusText = item.status?.is_delete ? "deleted" : item.status?.is_private ? "private" : item.status?.in_reviewing ? "reviewing" : "public";
16126
+ return {
16127
+ title: item.desc || "无作品描述",
16128
+ imageUrl: item.Cover?.url_list?.[0] || "",
16129
+ createTime: item.create_time,
16130
+ redirectUrl: workDetailUrl,
16131
+ playNum: item.statistics?.play_count || 0,
16132
+ likeNum: item.statistics?.digg_count || 0,
16133
+ commentNum: item.statistics?.comment_count || 0,
16134
+ shareNum: item.statistics?.share_count || 0,
16135
+ collectNum: item.statistics?.collect_count || 0,
16136
+ awemeId: item.aweme_id,
16137
+ awemeType: item.aweme_type ?? 0,
16138
+ duration: item.duration,
16139
+ status: statusText,
16140
+ publicUrl: workPublicUrl,
16141
+ ...showOriginalData ? {
16142
+ originalData: item
16143
+ } : {}
16144
+ };
16145
+ });
16146
+ return (0, share_namespaceObject.success)({
16147
+ articleCell,
16148
+ ...onlySuccess ? {
16149
+ pagination: {
16150
+ total: workListResponse.total || allWorks.length,
16151
+ nextPage: hasMore,
16152
+ pageNum,
16153
+ pageSize
16154
+ }
16155
+ } : null
16156
+ }, "抖音数据获取成功");
16157
+ } catch (error) {
16158
+ return searchPublishInfo_types_errorResponse(error instanceof Error ? error.message : "抖音数据获取失败");
16159
+ }
16160
+ }
16161
+ async function handleShipinhaoData(_task, params) {
16162
+ try {
16163
+ const { cookies, postType = "all", pageSize = 10, showOriginalData = false } = params;
16164
+ const pageNum = params.pageNum || 1;
16165
+ const aidCookie = cookies.find((it)=>"_aid" === it.name)?.value;
16166
+ const aid = aidCookie || "9d3e0e9f-b842-498d-a273-4285d58df264";
16167
+ const uinCookie = cookies.find((it)=>"uin" === it.name || "wxuin" === it.name)?.value || "0000000000";
16168
+ const deviceIdCookie = cookies.find((it)=>"device_id" === it.name || "finger_print_device_id" === it.name)?.value;
16169
+ const headers = {
16170
+ cookie: cookies.map((it)=>`${it.name}=${it.value}`).join(";"),
16171
+ referer: "https://channels.weixin.qq.com",
16172
+ origin: "https://channels.weixin.qq.com",
16173
+ "content-type": "application/json",
16174
+ "X-WECHAT-UIN": uinCookie,
16175
+ ...deviceIdCookie ? {
16176
+ "finger-print-device-id": deviceIdCookie
16177
+ } : {}
16178
+ };
16179
+ const args = [
16180
+ {
16181
+ headers
16182
+ },
16183
+ _task.logger,
16184
+ params.proxyLoc,
16185
+ params.localIP,
16186
+ params.accountId
16187
+ ];
16188
+ const http = new Http(...args);
16189
+ const finderIdCookie = cookies.find((it)=>"_log_finder_id" === it.name || "finder_id" === it.name)?.value || "";
16190
+ async function fetchPosts(currentPage, userpageType, pageUrl, rawKeyBuff = "") {
16191
+ return await http.api({
16192
+ method: "post",
16193
+ url: "https://channels.weixin.qq.com/micro/content/cgi-bin/mmfinderassistant-bin/post/post_list",
16194
+ params: {
16195
+ _aid: aid,
16196
+ _rid: `${Date.now().toString(16)}-${Math.random().toString(36).substring(2, 9)}`,
16197
+ _pageUrl: encodeURIComponent(pageUrl)
16198
+ },
16199
+ data: {
16200
+ pageSize,
16201
+ currentPage,
16202
+ userpageType,
16203
+ stickyOrder: true,
16204
+ timestamp: Date.now().toString(),
16205
+ _log_finder_uin: "",
16206
+ _log_finder_id: finderIdCookie,
16207
+ rawKeyBuff,
16208
+ pluginSessionId: null,
16209
+ scene: 7,
16210
+ reqScene: 7
16211
+ }
16212
+ }, {
16213
+ retries: 3,
16214
+ retryDelay: 100,
16215
+ timeout: 5000
16216
+ });
16217
+ }
16218
+ async function fetchAllPosts(userpageType, pageUrl) {
16219
+ const allPosts = [];
16220
+ let currentPage = 1;
16221
+ let rawKeyBuff = "";
16222
+ let continueFlag = true;
16223
+ let totalCount = 0;
16224
+ while(continueFlag){
16225
+ const response = await fetchPosts(currentPage, userpageType, pageUrl, rawKeyBuff);
16226
+ if (response.errCode && AUTH_ERROR_CODES.includes(response.errCode)) throw new Error(`AUTH_ERROR:${response.errMsg || "登录已失效"}`);
16227
+ if (response.errCode) {
16228
+ _task.logger.warn(`视频号API错误:${response.errMsg} (${response.errCode})`);
16229
+ throw new Error(`视频号API错误:${response.errMsg} (${response.errCode})`);
16230
+ }
16231
+ if (1 === currentPage) totalCount = response.data?.totalCount ?? 0;
16232
+ const posts = response.data?.list || response.posts || response.post_list || [];
16233
+ allPosts.push(...posts);
16234
+ continueFlag = response.data?.continueFlag ?? false;
16235
+ rawKeyBuff = response.data?.lastBuff || "";
16236
+ currentPage++;
16237
+ if (currentPage > 100) {
16238
+ _task.logger.warn("分页超过100页,停止请求");
16239
+ break;
16240
+ }
16241
+ }
16242
+ if (totalCount > 0 && allPosts.length !== totalCount) _task.logger.warn(`视频号分页可能不完整:期望${totalCount}条,实际${allPosts.length}条`);
16243
+ return {
16244
+ posts: allPosts,
16245
+ totalCount
16246
+ };
16247
+ }
16248
+ const mapPost = (item, forcePostType)=>{
16249
+ let imageUrl = "";
16250
+ if (item.desc?.media?.[0]?.thumbUrl) imageUrl = item.desc.media[0].thumbUrl;
16251
+ else if (item.desc?.media?.[0]?.coverUrl) imageUrl = item.desc.media[0].coverUrl;
16252
+ else if (item.cover?.url) imageUrl = item.cover.url;
16253
+ else if (item.media_url) imageUrl = item.media_url;
16254
+ const title = item.desc?.description || item.object_desc || "无标题";
16255
+ return {
16256
+ title,
16257
+ imageUrl,
16258
+ createTime: item.createTime || item.create_time,
16259
+ redirectUrl: "https://channels.weixin.qq.com/platform",
16260
+ readNum: item.readCount || item.read_count || 0,
16261
+ likeNum: item.likeCount || item.like_count || 0,
16262
+ commentNum: item.commentCount || item.comment_count || 0,
16263
+ forwardNum: item.forwardCount || item.forward_count || 0,
16264
+ favNum: item.favCount || item.fav_count || 0,
16265
+ objectId: item.exportId || item.objectId || "",
16266
+ postType: forcePostType,
16267
+ postStatus: item.status || item.post_status || 0,
16268
+ ...item.effectiveTime ? {
16269
+ effectiveTime: item.effectiveTime
16270
+ } : {},
16271
+ ...showOriginalData ? {
16272
+ originalData: item
16273
+ } : {}
16274
+ };
16275
+ };
16276
+ const allArticles = [];
16277
+ const needVideo = "all" === postType || "video" === postType;
16278
+ const needArticle = "all" === postType || "article" === postType;
16279
+ const AUTH_ERROR_CODES = [
16280
+ 300333,
16281
+ 300334,
16282
+ 300330,
16283
+ 300331,
16284
+ 300332
16285
+ ];
16286
+ let combinedTotal = 0;
16287
+ if (needVideo) try {
16288
+ const videoPageUrl = "https://channels.weixin.qq.com/micro/content/post/list";
16289
+ const { posts, totalCount } = await fetchAllPosts(11, videoPageUrl);
16290
+ const videoArticles = posts.filter((item)=>item.createTime || item.create_time).map((item)=>mapPost(item, "video"));
16291
+ allArticles.push(...videoArticles);
16292
+ combinedTotal += totalCount || videoArticles.length;
16293
+ } catch (error) {
16294
+ const errMsg = error instanceof Error ? error.message : String(error);
16295
+ if (errMsg.startsWith("AUTH_ERROR:")) throw error;
16296
+ _task.logger.warn(`获取视频号视频失败:${errMsg}`);
16297
+ }
16298
+ if (needArticle) try {
16299
+ const articlePageUrl = "https://channels.weixin.qq.com/micro/content/post/finderNewLifePostList";
16300
+ const { posts, totalCount } = await fetchAllPosts(10, articlePageUrl);
16301
+ const articleArticles = posts.filter((item)=>item.createTime || item.create_time).map((item)=>mapPost(item, "article"));
16302
+ allArticles.push(...articleArticles);
16303
+ combinedTotal += totalCount || articleArticles.length;
16304
+ } catch (error) {
16305
+ const errMsg = error instanceof Error ? error.message : String(error);
16306
+ if (errMsg.startsWith("AUTH_ERROR:")) throw error;
16307
+ _task.logger.warn(`获取视频号图文失败:${errMsg}`);
16308
+ }
16309
+ allArticles.sort((a, b)=>b.createTime - a.createTime);
16310
+ const total = allArticles.length;
16311
+ const start = (pageNum - 1) * pageSize;
16312
+ const pageItems = allArticles.slice(start, start + pageSize);
16313
+ return (0, share_namespaceObject.success)({
16314
+ articleCell: pageItems,
16315
+ pagination: {
16316
+ total,
16317
+ nextPage: start + pageSize < total,
16318
+ pageNum,
16319
+ pageSize
16320
+ }
16321
+ }, "视频号数据获取成功");
16322
+ } catch (error) {
16323
+ const errMsg = error instanceof Error ? error.message : String(error);
16324
+ if (errMsg.startsWith("AUTH_ERROR:")) return searchPublishInfo_types_errorResponse("视频号数据获取失败,请检查账号状态", 414);
16325
+ return searchPublishInfo_types_errorResponse(errMsg || "视频号数据获取失败");
16326
+ }
16327
+ }
15773
16328
  async function handleToutiaoData(_task, params) {
15774
16329
  try {
15775
16330
  const { cookies, pageNum = 1, pageSize = 10, showOriginalData = false, onlySuccess = false, containsArticle = false } = params;
@@ -15802,7 +16357,7 @@ var __webpack_exports__ = {};
15802
16357
  app_id: 1231
15803
16358
  }
15804
16359
  });
15805
- if (0 !== visitedUid.code) return searchPublishInfo_types_errorResponse("头条号账号信息获取失败,请检查账号状态", 414);
16360
+ if (0 !== visitedUid.code) return searchPublishInfo_types_errorResponse("头条号数据获取失败,请检查账号状态", 414);
15806
16361
  const articleInfo = await http.api({
15807
16362
  method: "get",
15808
16363
  url: "https://mp.toutiao.com/api/feed/mp_provider/v1/",
@@ -15911,7 +16466,7 @@ var __webpack_exports__ = {};
15911
16466
  const size = onlySuccess ? 10 : pageSize > 20 ? 20 : pageSize;
15912
16467
  let begin = (lastPage ?? pageNum) - 1;
15913
16468
  const rawArticlesInfo = await fetchArticles(begin * size, size, token);
15914
- if (rawArticlesInfo.includes("请重新<a id='jumpUrl' href='/'>登录</a>")) return searchPublishInfo_types_errorResponse("登陆已失效,请重新登陆!", 414);
16469
+ if (rawArticlesInfo.includes("请重新<a id='jumpUrl' href='/'>登录</a>")) return searchPublishInfo_types_errorResponse("微信公众号数据获取失败,请检查账号状态", 414);
15915
16470
  const articlesInfo = ParsePublishPage(rawArticlesInfo);
15916
16471
  let articleCell = [];
15917
16472
  if (!onlySuccess && pageSize > 20) {
@@ -16073,7 +16628,7 @@ var __webpack_exports__ = {};
16073
16628
  const a1Cookie = cookies.find((it)=>"a1" === it.name)?.value;
16074
16629
  if (!a1Cookie) return {
16075
16630
  code: 414,
16076
- message: "账号数据异常",
16631
+ message: "小红书数据获取失败,请检查账号状态",
16077
16632
  data: {}
16078
16633
  };
16079
16634
  if (onlySuccess && 10 !== pageSize) return {
@@ -16192,7 +16747,7 @@ var __webpack_exports__ = {};
16192
16747
  }, "小红书文章数据获取成功");
16193
16748
  }
16194
16749
  const FetchArticlesParamsSchema = ActionCommonParamsSchema.extend({
16195
- platform: schemas_string().describe("社交平台:weixin, toutiao, baijiahao, xiaohongshu"),
16750
+ platform: schemas_string().describe("社交平台:weixin, toutiao, baijiahao, xiaohongshu, douyin, shipinhao"),
16196
16751
  token: union([
16197
16752
  schemas_string(),
16198
16753
  schemas_number()
@@ -16204,7 +16759,14 @@ var __webpack_exports__ = {};
16204
16759
  showOriginalData: schemas_boolean().optional().describe("是否展示原始数据,默认false"),
16205
16760
  cursor: schemas_number().optional().describe("仅用于微信分页游标,默认为空"),
16206
16761
  lastPage: schemas_number().optional(),
16207
- containsArticle: schemas_boolean().optional().describe("是否包含文章内容,默认false")
16762
+ containsArticle: schemas_boolean().optional().describe("是否包含文章内容,默认false"),
16763
+ status: schemas_number().optional().describe("抖音作品状态:0=全部"),
16764
+ includeAccount: schemas_boolean().optional().describe("是否包含账号数据,默认true"),
16765
+ postType: schemas_enum([
16766
+ "video",
16767
+ "article",
16768
+ "all"
16769
+ ]).optional().describe("视频号作品类型:video=视频, article=图文, all=全部")
16208
16770
  });
16209
16771
  const FetchArticles = async (_task, params)=>{
16210
16772
  const { platform } = params;
@@ -16217,6 +16779,10 @@ var __webpack_exports__ = {};
16217
16779
  return handleBaijiahaoData(_task, params);
16218
16780
  case "xiaohongshu":
16219
16781
  return handleXiaohongshuData(_task, params);
16782
+ case "douyin":
16783
+ return handleDouyinData(_task, params);
16784
+ case "shipinhao":
16785
+ return handleShipinhaoData(_task, params);
16220
16786
  default:
16221
16787
  return (0, share_namespaceObject.success)({}, "暂不支持该平台");
16222
16788
  }
@@ -17620,6 +18186,11 @@ var __webpack_exports__ = {};
17620
18186
  this.concurrentLimit = config.concurrentLimit || 4;
17621
18187
  this.singleFileSize = config.singleFileSize || 10485760;
17622
18188
  this.http = config.http || new Http();
18189
+ this.reqOptions = {
18190
+ timeout: config.timeout ?? 60000,
18191
+ retries: config.retries ?? 3,
18192
+ retryDelay: config.retryDelay ?? 2000
18193
+ };
17623
18194
  }
17624
18195
  calculateMd5(buffer) {
17625
18196
  const MAX_SIZE = 5242880;
@@ -17676,7 +18247,7 @@ var __webpack_exports__ = {};
17676
18247
  url: filePath,
17677
18248
  method: "get",
17678
18249
  responseType: "arraybuffer"
17679
- });
18250
+ }, this.reqOptions);
17680
18251
  return Buffer.from(resp);
17681
18252
  }
17682
18253
  return external_node_fs_default().promises.readFile(filePath);
@@ -17706,7 +18277,7 @@ var __webpack_exports__ = {};
17706
18277
  headers,
17707
18278
  data: requestBody,
17708
18279
  defaultErrorMsg: "获取UploadID失败"
17709
- });
18280
+ }, this.reqOptions);
17710
18281
  if (!resp?.UploadID) throw new Error(`获取 UploadID 失败: ${resp?.errMsg || "未知错误"}`);
17711
18282
  return resp.UploadID;
17712
18283
  }
@@ -17727,7 +18298,7 @@ var __webpack_exports__ = {};
17727
18298
  headers,
17728
18299
  data: chunk,
17729
18300
  defaultErrorMsg: `分片 ${partNumber} 上传失败`
17730
- });
18301
+ }, this.reqOptions);
17731
18302
  if (resp?.errCode !== void 0 && 0 !== resp.errCode) throw new Error(`分片 ${partNumber} 上传失败: ${resp.errMsg}`);
17732
18303
  if (onProgress) onProgress(chunk.length);
17733
18304
  return resp.ETag || "";
@@ -17751,7 +18322,7 @@ var __webpack_exports__ = {};
17751
18322
  headers,
17752
18323
  data: requestBody,
17753
18324
  defaultErrorMsg: "确认分片上传失败"
17754
- });
18325
+ }, this.reqOptions);
17755
18326
  if (resp?.ListPartsResult?.Part) return resp.ListPartsResult.Part.map((p)=>({
17756
18327
  PartNumber: parseInt(p.PartNumber),
17757
18328
  ETag: p.ETag
@@ -17777,7 +18348,7 @@ var __webpack_exports__ = {};
17777
18348
  headers,
17778
18349
  data: requestBody,
17779
18350
  defaultErrorMsg: "完成上传失败"
17780
- });
18351
+ }, this.reqOptions);
17781
18352
  if (!resp?.DownloadURL) throw new Error(`完成上传失败: ${resp?.errMsg || "未知错误"}`);
17782
18353
  return resp.DownloadURL;
17783
18354
  }
@@ -18128,7 +18699,9 @@ var __webpack_exports__ = {};
18128
18699
  task.logger.info("[shipinhaoPublish] 开始执行视频号发布 - Mock API 方式");
18129
18700
  const updateTaskState = task.taskStageStore?.update?.bind(task.taskStageStore, task.taskId || "");
18130
18701
  if (!params.extraParam.fingerPrintDeviceId || !params.extraParam.aId) return (0, share_namespaceObject.response)(400, "fingerPrintDeviceId和aId 不能为空", "");
18702
+ let currentStep = "初始化";
18131
18703
  try {
18704
+ currentStep = "解析认证信息";
18132
18705
  const cookieString = params.cookies.map((c)=>`${c.name}=${c.value}`).join("; ");
18133
18706
  const fingerPrintDeviceId = params.extraParam.fingerPrintDeviceId;
18134
18707
  const aId = params.extraParam.aId;
@@ -18149,8 +18722,10 @@ var __webpack_exports__ = {};
18149
18722
  headers
18150
18723
  });
18151
18724
  const proxyHttp = new Http(...args);
18725
+ currentStep = "验证发布参数";
18152
18726
  if (!params.banners || 0 === params.banners.length) return (0, share_namespaceObject.response)(400, "至少需要一张图片", "");
18153
18727
  const images = params.banners.slice(0, 18).filter((img)=>"string" == typeof img);
18728
+ currentStep = "获取用户信息";
18154
18729
  task.logger.info("[shipinhaoPublish] 获取用户信息...");
18155
18730
  console.log("cookieString", cookieString);
18156
18731
  const userInfo = await mock_getUserInfo(cookieString, http);
@@ -18161,6 +18736,7 @@ var __webpack_exports__ = {};
18161
18736
  }
18162
18737
  const finderUsername = userInfo.data.finderUser.finderUsername;
18163
18738
  console.log(finderUsername);
18739
+ currentStep = "获取上传认证密钥";
18164
18740
  task.logger.info("[shipinhaoPublish] 获取上传认证密钥...");
18165
18741
  const authKeyResponse = await getUploadAuthKey(cookieString, finderUsername, http);
18166
18742
  if (0 !== authKeyResponse.errCode || !authKeyResponse.data?.authKey) return (0, share_namespaceObject.response)(authKeyResponse.errCode || 500, `获取上传认证参数失败: ${authKeyResponse.errMsg}`, "");
@@ -18168,10 +18744,12 @@ var __webpack_exports__ = {};
18168
18744
  const uin = authKeyResponse.data.uin;
18169
18745
  if (!uin) return (0, share_namespaceObject.response)(500, "获取用户 uin 失败", "");
18170
18746
  const taskId = String(generateUUID());
18747
+ currentStep = "上传图片";
18171
18748
  task.logger.info(`[shipinhaoPublish] 开始上传 ${images.length} 张图片...`);
18172
18749
  const uploadedImages = [];
18173
18750
  for(let i = 0; i < images.length; i++){
18174
- task.logger.info(`[shipinhaoPublish] 上传图片 ${i + 1}/${images.length}...`);
18751
+ currentStep = `上传图片 ${i + 1}/${images.length}`;
18752
+ task.logger.info(`[shipinhaoPublish] ${currentStep}...`);
18175
18753
  const uploadResult = await uploadImageComplete(images[i], taskId, finderUsername, uin, authKey, http);
18176
18754
  console.log(JSON.stringify(uploadResult));
18177
18755
  if (!uploadResult.DownloadURL) return (0, share_namespaceObject.response)(500, `图片上传失败: ${uploadResult.errMsg}`, "");
@@ -18188,6 +18766,7 @@ var __webpack_exports__ = {};
18188
18766
  urlCdnTaskId: ""
18189
18767
  });
18190
18768
  }
18769
+ currentStep = "发布图文内容";
18191
18770
  task.logger.info("[shipinhaoPublish] 正在发布...");
18192
18771
  const topicNames = params.topic || void 0;
18193
18772
  const addressInfo = params.address ? {
@@ -18274,9 +18853,15 @@ var __webpack_exports__ = {};
18274
18853
  });
18275
18854
  return (0, share_namespaceObject.response)(resultCode || 500, errorMessage, "");
18276
18855
  } catch (error) {
18277
- const errorMsg = error instanceof Error ? error.message : "发布失败";
18278
- task.logger.error(`[shipinhaoPublish] 发布异常: ${errorMsg}`);
18279
- return (0, share_namespaceObject.response)(500, errorMsg, "");
18856
+ const handledError = Http.handleApiError(error);
18857
+ const errorMsg = handledError.message || "发布失败,请稍后重试";
18858
+ const errorCode = handledError.code || 500;
18859
+ task.logger.error(`[shipinhaoPublish] 发布流程异常: ${errorMsg}`, stringifyError(error), handledError.extra);
18860
+ await updateTaskState?.({
18861
+ state: share_namespaceObject.TaskState.FAILED,
18862
+ error: errorMsg
18863
+ });
18864
+ return (0, share_namespaceObject.response)(errorCode, errorMsg, "");
18280
18865
  }
18281
18866
  };
18282
18867
  const shipinhaoPublish_rpa_rpaAction = async (task, params)=>{
@@ -24782,6 +25367,24 @@ var __webpack_exports__ = {};
24782
25367
  likeNumYesterday: schemas_number().nullable(),
24783
25368
  commentNumYesterday: schemas_number().nullable()
24784
25369
  });
25370
+ const douyinConfigDataSchema = schemas_object({
25371
+ fansNum: schemas_number(),
25372
+ favedNum: schemas_number(),
25373
+ fansNumLastWeek: schemas_number(),
25374
+ watchNumLastWeek: schemas_number(),
25375
+ likeNumLastWeek: schemas_number(),
25376
+ commentNumLastWeek: schemas_number(),
25377
+ shareNumLastWeek: schemas_number(),
25378
+ visitNumLastWeek: schemas_number()
25379
+ });
25380
+ const shipinhaoConfigDataSchema = schemas_object({
25381
+ fansNum: schemas_number(),
25382
+ feedsCount: schemas_number(),
25383
+ fansNumYesterday: schemas_number().nullable(),
25384
+ playNumYesterday: schemas_number().nullable(),
25385
+ likeNumYesterday: schemas_number().nullable(),
25386
+ commentNumYesterday: schemas_number().nullable()
25387
+ });
24785
25388
  const BetaFlag = "HuiwenCanary";
24786
25389
  class Action {
24787
25390
  constructor(task){