@iflyrpa/actions 1.0.0 → 1.0.2

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.cjs CHANGED
@@ -21753,7 +21753,7 @@ const replaceImgSrc = (html, callback) => {
21753
21753
  return lastedHtml;
21754
21754
  };
21755
21755
 
21756
- const errnoMap = {
21756
+ const errnoMap$1 = {
21757
21757
  20040706: "\u6B63\u6587\u548C\u5C01\u9762\u56FE\u7247\u63A8\u8350\u4F7F\u752820M\u4EE5\u5185\u7684jpg\u548Cpng\u56FE\u7247",
21758
21758
  20040084: "\u6B63\u6587\u548C\u5C01\u9762\u56FE\u7247\u63A8\u8350\u4F7F\u752820M\u4EE5\u5185\u7684jpg\u548Cpng\u56FE\u7247",
21759
21759
  20050004: "\u53D1\u5E03\u6B21\u6570\u7528\u5C3D\uFF0C\u8BF7\u660E\u5929\u518D\u8BD5",
@@ -21766,6 +21766,7 @@ const errnoMap = {
21766
21766
  401100032: "\u4E0D\u652F\u6301\u8BE5\u5A92\u8D44\u7C7B\u578B\uFF0C\u8BF7\u68C0\u67E5\u56FE\u7247\uFF08\u4F8B\u5982\uFF1A\u7248\u6743\uFF09"
21767
21767
  };
21768
21768
  const mockAction$5 = async (task, params) => {
21769
+ const { baijiahaoSingleCover, baijiahaoMultCover, baijiahaoCoverType } = params.settingInfo;
21769
21770
  const tmpCachePath = task.getTmpPath();
21770
21771
  const api = axios$1.create({
21771
21772
  headers: {
@@ -21776,7 +21777,7 @@ const mockAction$5 = async (task, params) => {
21776
21777
  api.interceptors.response.use(
21777
21778
  (response) => {
21778
21779
  if (response.data.errno !== 0) {
21779
- const errmsg = errnoMap[response.data.errno] || response.config.defaultErrorMsg || response.data.errmsg || "Unknown error";
21780
+ const errmsg = errnoMap$1[response.data.errno] || response.config.defaultErrorMsg || response.data.errmsg || "Unknown error";
21780
21781
  task.logger.error(errmsg);
21781
21782
  return Promise.reject(new Error(errmsg));
21782
21783
  }
@@ -21841,7 +21842,7 @@ const mockAction$5 = async (task, params) => {
21841
21842
  if (vertical_cover) {
21842
21843
  vertical_cover = (await uploadImages([vertical_cover]))[0].bos_url;
21843
21844
  }
21844
- const horizontalCoverUrl = params.settingInfo.baijiahaoCoverType === "single" ? [params.settingInfo.baijiahaoSingleCover] : params.settingInfo.baijiahaoMultCover;
21845
+ const horizontalCoverUrl = baijiahaoCoverType === "single" ? [baijiahaoSingleCover] : baijiahaoMultCover;
21845
21846
  const horizontalCoverRes = await uploadImages(horizontalCoverUrl);
21846
21847
  const cover_images = horizontalCoverRes.map((item) => ({
21847
21848
  src: item.bos_url,
@@ -21854,7 +21855,7 @@ const mockAction$5 = async (task, params) => {
21854
21855
  }));
21855
21856
  const isAi = params.settingInfo.baijiahaoIsAi.includes("isAi");
21856
21857
  const activityList = params.settingInfo.baijiahaoSelectActivityCache;
21857
- const cover_layout = params.settingInfo.baijiahaoCoverType === "single" ? "one" : "three";
21858
+ const cover_layout = baijiahaoCoverType === "single" ? "one" : "three";
21858
21859
  const activity_list = [
21859
21860
  ...activityList.length > 0 ? [{ id: `task_${activityList[0]}`, is_checked: 1 }] : [],
21860
21861
  ...isAi ? [{ id: "aigc_bjh_status", is_checked: 1 }] : []
@@ -21920,19 +21921,245 @@ const getBaijiahaoActivity = async (task, params) => {
21920
21921
  return res.data.data.list;
21921
21922
  };
21922
21923
 
21924
+ const getToutiaoConfig = async (task, params) => {
21925
+ task.logger.info("\u83B7\u53D6\u5934\u6761\u53D1\u5E03\u914D\u7F6E\u7684\u8BDD\u9898\u4FE1\u606F\u3001\u4F4D\u7F6E\u4FE1\u606F\u548C\u539F\u521B\u9996\u53D1\u4FE1\u606F");
21926
+ const api = axios$1.create({
21927
+ headers: {
21928
+ cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
21929
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish"
21930
+ }
21931
+ });
21932
+ const getSuggestWords = async () => {
21933
+ try {
21934
+ const res = await api({
21935
+ method: "get",
21936
+ url: "https://mp.toutiao.com/mp/agw/creator_helper/suggest_words",
21937
+ params: { type: 2, words: "" }
21938
+ });
21939
+ return res.data.code === 0 ? res.data.hots : [];
21940
+ } catch (error) {
21941
+ return [];
21942
+ }
21943
+ };
21944
+ const getCityDistrict = async () => {
21945
+ try {
21946
+ const res = await api.get(
21947
+ "https://mp.toutiao.com/toutiao/normandy/mp/city_district/"
21948
+ );
21949
+ return res.data.status === 0 ? res.data.data : null;
21950
+ } catch (error) {
21951
+ return null;
21952
+ }
21953
+ };
21954
+ const getUserRights = async () => {
21955
+ try {
21956
+ const res = await api.get("https://mp.toutiao.com/mp/agw/creator_project/get_benefit_page_info");
21957
+ return res.data.code === 0 ? res.data.data.benefit_level_info_list : [];
21958
+ } catch (error) {
21959
+ return [];
21960
+ }
21961
+ };
21962
+ const [suggestWords, cityDistrict, userRights] = await Promise.all([
21963
+ getSuggestWords(),
21964
+ getCityDistrict(),
21965
+ getUserRights()
21966
+ ]);
21967
+ return { suggestWords, cityDistrict, userRights };
21968
+ };
21969
+
21970
+ const searchToutiaoTopicList = async (task, params) => {
21971
+ task.logger.info("\u641C\u7D22\u5934\u6761\u8BDD\u9898");
21972
+ const api = axios$1.create({
21973
+ headers: {
21974
+ cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
21975
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish"
21976
+ }
21977
+ });
21978
+ try {
21979
+ const res = await api({
21980
+ method: "get",
21981
+ url: "https://mp.toutiao.com/mp/agw/creator_helper/suggest_words",
21982
+ params: { type: 2, words: params.searchValue }
21983
+ });
21984
+ if (res.data.code === 0) {
21985
+ return params.searchValue ? res.data.recents : res.data.hots;
21986
+ }
21987
+ return [];
21988
+ } catch (error) {
21989
+ return [];
21990
+ }
21991
+ };
21992
+
21993
+ const COVER_TYPE = {
21994
+ no: 1,
21995
+ single: 2,
21996
+ multiple: 3
21997
+ };
21998
+ const errnoMap = {
21999
+ 20004020: "\u56FE\u7247\u4E0A\u4F20\u51FA\u73B0\u95EE\u9898\uFF0C\u8BF7\u91CD\u65B0\u7ED1\u5B9A\u8D26\u53F7\u540E\u518D\u5C1D\u8BD5",
22000
+ 7115: "\u6B63\u6587\u548C\u5C01\u9762\u56FE\u7247\u63A8\u8350\u4F7F\u752820M\u4EE5\u5185\u7684jpg\u548Cpng\u56FE\u7247",
22001
+ 100006: "\u6587\u7AE0\u53D1\u5E03\u51FA\u73B0\u95EE\u9898\uFF0C\u8BF7\u91CD\u65B0\u7ED1\u5B9A\u8D26\u53F7\u540E\u518D\u5C1D\u8BD5",
22002
+ 3101: "\u7F51\u7EDC\u73AF\u5883\u6709\u95EE\u9898\uFF0C\u9700\u8981\u53BB\u5E73\u53F0\u5B8C\u6210\u9A8C\u8BC1",
22003
+ 2007: "\u6587\u7AE0\u53D1\u5E03\u51FA\u73B0\u95EE\u9898\uFF0C\u58F0\u660E\u539F\u521B\u65F6\uFF0C\u6B63\u6587\u5B57\u6570\u9700\u5927\u4E8E300\u5B57",
22004
+ 1053: "\u6B63\u6587\u548C\u5C01\u9762\u56FE\u7247\u63A8\u8350\u4F7F\u752820M\u4EE5\u5185\u7684jpg\u548Cpng\u56FE\u7247",
22005
+ 2005: "\u65E0\u58F0\u660E\u539F\u521B\u6743\u9650\uFF0C\u8BF7\u53D6\u6D88\u539F\u521B\u58F0\u660E\u6216\u7533\u8BF7\u539F\u521B\u6743\u9650\u540E\u518D\u5C1D\u8BD5"
22006
+ };
21923
22007
  const mockAction$4 = async (task, params) => {
21924
- task.getTmpPath();
22008
+ const { toutiaoSingleCover, toutiaoMultCover, toutiaoCoverType, toutiaoOriginal } = params.settingInfo;
22009
+ const tmpCachePath = task.getTmpPath();
21925
22010
  const api = axios$1.create({
21926
22011
  headers: {
21927
- cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";")
22012
+ cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
22013
+ origin: "https://mp.toutiao.com",
22014
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish"
21928
22015
  }
21929
22016
  });
21930
- const userInfoRes = await api.get(
21931
- "https://mp.toutiao.com/mp/agw/creator_center/user_info"
22017
+ api.interceptors.response.use(
22018
+ (response) => {
22019
+ if (response.data.code !== 0) {
22020
+ const errmsg = errnoMap[response.data.code] || response.config.defaultErrorMsg || response.data.message || "Unknown error";
22021
+ task.logger.error(errmsg);
22022
+ return Promise.reject(new Error(errmsg));
22023
+ }
22024
+ return response;
22025
+ },
22026
+ (error) => {
22027
+ return Promise.reject(error);
22028
+ }
21932
22029
  );
21933
- if (userInfoRes.data.code !== 0) {
21934
- throw new Error("\u767B\u5F55\u5931\u6548");
21935
- }
22030
+ await api({
22031
+ method: "get",
22032
+ url: "https://mp.toutiao.com/mp/agw/creator_center/user_info",
22033
+ defaultErrorMsg: "\u767B\u5F55\u5931\u6548"
22034
+ });
22035
+ const uploadImages = async (images) => {
22036
+ const localImages = await Promise.all(
22037
+ images.map((url) => {
22038
+ const fileName = getFilenameFromUrl(url);
22039
+ return downloadImage(url, path__default.join(tmpCachePath, fileName));
22040
+ })
22041
+ );
22042
+ return await Promise.all(
22043
+ localImages.map(async (image) => {
22044
+ const formData = new FormData$2();
22045
+ formData.append("image", fs__default.createReadStream(image));
22046
+ const response = await api({
22047
+ method: "post",
22048
+ url: "https://mp.toutiao.com/spice/image?upload_source=20020003&aid=1231&device_platform=web",
22049
+ data: formData,
22050
+ defaultErrorMsg: "\u4E0A\u4F20\u5934\u6761\u53F7\u56FE\u7247\u5931\u8D25"
22051
+ });
22052
+ return response.data.data;
22053
+ })
22054
+ );
22055
+ };
22056
+ const originContentImages = extractImgTag(params.content);
22057
+ const targetContentImages = await uploadImages(originContentImages);
22058
+ const content = replaceImgSrc(params.content, (dom) => {
22059
+ if (dom.attribs.src) {
22060
+ const idx = originContentImages.findIndex((it) => it === dom.attribs.src);
22061
+ dom.attribs.src = targetContentImages[idx].image_url;
22062
+ dom.attribs.web_uri = targetContentImages[idx].image_uri;
22063
+ dom.attribs.img_width = targetContentImages[idx].image_width.toString();
22064
+ dom.attribs.image_height = targetContentImages[idx].image_height.toString();
22065
+ dom.attribs.image_type = targetContentImages[idx].image_type.toString();
22066
+ dom.attribs.mime_type = targetContentImages[idx].image_mime_type;
22067
+ }
22068
+ return dom;
22069
+ });
22070
+ const coverUrl = toutiaoCoverType === "single" ? [toutiaoSingleCover] : toutiaoCoverType === "multiple" ? toutiaoMultCover : [];
22071
+ const coverRes = await uploadImages(coverUrl);
22072
+ const isSingleTitle = params.settingInfo.toutiaoTitleType === "single";
22073
+ const location = params.settingInfo.toutiaoLocation;
22074
+ const topics = params.settingInfo.toutiaoTopic || [];
22075
+ const multiTitleData = params.settingInfo.subTitles.map((title) => ({
22076
+ id: "0",
22077
+ visibility_level: 0,
22078
+ source: "author",
22079
+ old_source: "author",
22080
+ text: title,
22081
+ version: "author",
22082
+ ai_title: ""
22083
+ }));
22084
+ const topicContent = topics.map(
22085
+ (topic) => `<p><a class="tteditor-forum" data-name="${topic.word}" data-id="${topic.id}" data-concern-id="${topic.id}">#${topic.word}#</a ></p >`
22086
+ ).join("");
22087
+ const extraData = {
22088
+ content_word_cnt: params.settingInfo.cntWord,
22089
+ is_multi_title: isSingleTitle ? 0 : 1,
22090
+ sub_titles: isSingleTitle ? [] : multiTitleData,
22091
+ gd_ext: {
22092
+ entrance: "",
22093
+ from_page: "publisher_mp",
22094
+ enter_from: "PC",
22095
+ device_platform: "mp",
22096
+ is_message: 0
22097
+ },
22098
+ tuwen_wtt_trans_flag: "0",
22099
+ info_source: {
22100
+ source_type: 5,
22101
+ source_link: "",
22102
+ time_format: "",
22103
+ position: {}
22104
+ },
22105
+ ...location ? { city: location.label, city_code: location.value } : null
22106
+ };
22107
+ const publishData = {
22108
+ article_type: 0,
22109
+ source: 0,
22110
+ search_creation_info: '{"searchTopOne": 0, "abstract": "", "clue_id": ""}',
22111
+ title_id: "",
22112
+ educluecard: "",
22113
+ origin_debut_check_pgc_normal: 1,
22114
+ is_fans_article: 0,
22115
+ govern_forward: 0,
22116
+ praise: 0,
22117
+ disable_praise: 0,
22118
+ tree_plan_article: 0,
22119
+ star_order_id: "",
22120
+ star_order_name: "",
22121
+ customer_nick_name: "",
22122
+ activity_tag: 0,
22123
+ trends_writing_tag: 0,
22124
+ is_refute_rumor: 0,
22125
+ save: params.saveType === "publish" ? 1 : 0,
22126
+ timer_status: 0,
22127
+ timer_time: "",
22128
+ title: params.title,
22129
+ content: content + topicContent,
22130
+ extra: JSON.stringify(extraData),
22131
+ mp_editor_stat: toutiaoCoverType === "no" ? "{}" : '{"image": %d}',
22132
+ draft_form_data: JSON.stringify({
22133
+ coverType: COVER_TYPE[toutiaoCoverType]
22134
+ }),
22135
+ pgc_feed_covers: JSON.stringify(
22136
+ coverRes.map((item) => ({
22137
+ id: "",
22138
+ url: item.image_url,
22139
+ uri: item.image_uri,
22140
+ ic_uri: "",
22141
+ thumb_widt: item.image_width,
22142
+ thumb_heigh: item.image_height,
22143
+ extra: {
22144
+ from_content_uri: "",
22145
+ from_content: "0"
22146
+ }
22147
+ }))
22148
+ ),
22149
+ article_ad_type: params.settingInfo.toutiaoAd === "yes" ? 3 : 2,
22150
+ claim_origin: toutiaoOriginal.includes("original") ? 1 : 0,
22151
+ claim_exclusive: toutiaoOriginal.includes("exclusive") ? 1 : 0
22152
+ };
22153
+ const publishResult = await api({
22154
+ method: "post",
22155
+ url: "https://mp.toutiao.com/mp/agw/article/publish?source=mp&type=article&aid=1",
22156
+ data: publishData,
22157
+ headers: {
22158
+ "content-type": "application/x-www-form-urlencoded"
22159
+ },
22160
+ defaultErrorMsg: "\u6587\u7AE0\u53D1\u5E03\u51FA\u73B0\u95EE\u9898\uFF0C\u8BF7\u8054\u7CFB\u5BA2\u670D"
22161
+ });
22162
+ return publishResult.data.data.pgc_id;
21936
22163
  };
21937
22164
 
21938
22165
  const toutiaoPublish = async (task, params) => {
@@ -21949,9 +22176,7 @@ const mockAction$3 = async (task, params) => {
21949
22176
  referer: "https://mp.toutiao.com/profile_v4/graphic/publish"
21950
22177
  }
21951
22178
  });
21952
- const userInfoRes = await api.get(
21953
- "https://mp.toutiao.com/mp/agw/creator_center/user_info"
21954
- );
22179
+ const userInfoRes = await api.get("https://mp.toutiao.com/mp/agw/creator_center/user_info");
21955
22180
  if (userInfoRes.data.code !== 0) {
21956
22181
  throw new Error("\u767B\u5F55\u5931\u6548");
21957
22182
  }
@@ -22508,6 +22733,14 @@ class Action {
22508
22733
  constructor(task) {
22509
22734
  this.task = task;
22510
22735
  }
22736
+ // 搜索头条话题列表
22737
+ searchToutiaoTopicList(params) {
22738
+ return searchToutiaoTopicList(this.task, params);
22739
+ }
22740
+ // 获取头条配置
22741
+ getToutiaoConfig(params) {
22742
+ return getToutiaoConfig(this.task, params);
22743
+ }
22511
22744
  // 百家号发布
22512
22745
  baijiahaoPublish(params) {
22513
22746
  return baijiahaoPublish(this.task, params);
package/dist/index.mjs CHANGED
@@ -21734,7 +21734,7 @@ const replaceImgSrc = (html, callback) => {
21734
21734
  return lastedHtml;
21735
21735
  };
21736
21736
 
21737
- const errnoMap = {
21737
+ const errnoMap$1 = {
21738
21738
  20040706: "\u6B63\u6587\u548C\u5C01\u9762\u56FE\u7247\u63A8\u8350\u4F7F\u752820M\u4EE5\u5185\u7684jpg\u548Cpng\u56FE\u7247",
21739
21739
  20040084: "\u6B63\u6587\u548C\u5C01\u9762\u56FE\u7247\u63A8\u8350\u4F7F\u752820M\u4EE5\u5185\u7684jpg\u548Cpng\u56FE\u7247",
21740
21740
  20050004: "\u53D1\u5E03\u6B21\u6570\u7528\u5C3D\uFF0C\u8BF7\u660E\u5929\u518D\u8BD5",
@@ -21747,6 +21747,7 @@ const errnoMap = {
21747
21747
  401100032: "\u4E0D\u652F\u6301\u8BE5\u5A92\u8D44\u7C7B\u578B\uFF0C\u8BF7\u68C0\u67E5\u56FE\u7247\uFF08\u4F8B\u5982\uFF1A\u7248\u6743\uFF09"
21748
21748
  };
21749
21749
  const mockAction$5 = async (task, params) => {
21750
+ const { baijiahaoSingleCover, baijiahaoMultCover, baijiahaoCoverType } = params.settingInfo;
21750
21751
  const tmpCachePath = task.getTmpPath();
21751
21752
  const api = axios$1.create({
21752
21753
  headers: {
@@ -21757,7 +21758,7 @@ const mockAction$5 = async (task, params) => {
21757
21758
  api.interceptors.response.use(
21758
21759
  (response) => {
21759
21760
  if (response.data.errno !== 0) {
21760
- const errmsg = errnoMap[response.data.errno] || response.config.defaultErrorMsg || response.data.errmsg || "Unknown error";
21761
+ const errmsg = errnoMap$1[response.data.errno] || response.config.defaultErrorMsg || response.data.errmsg || "Unknown error";
21761
21762
  task.logger.error(errmsg);
21762
21763
  return Promise.reject(new Error(errmsg));
21763
21764
  }
@@ -21822,7 +21823,7 @@ const mockAction$5 = async (task, params) => {
21822
21823
  if (vertical_cover) {
21823
21824
  vertical_cover = (await uploadImages([vertical_cover]))[0].bos_url;
21824
21825
  }
21825
- const horizontalCoverUrl = params.settingInfo.baijiahaoCoverType === "single" ? [params.settingInfo.baijiahaoSingleCover] : params.settingInfo.baijiahaoMultCover;
21826
+ const horizontalCoverUrl = baijiahaoCoverType === "single" ? [baijiahaoSingleCover] : baijiahaoMultCover;
21826
21827
  const horizontalCoverRes = await uploadImages(horizontalCoverUrl);
21827
21828
  const cover_images = horizontalCoverRes.map((item) => ({
21828
21829
  src: item.bos_url,
@@ -21835,7 +21836,7 @@ const mockAction$5 = async (task, params) => {
21835
21836
  }));
21836
21837
  const isAi = params.settingInfo.baijiahaoIsAi.includes("isAi");
21837
21838
  const activityList = params.settingInfo.baijiahaoSelectActivityCache;
21838
- const cover_layout = params.settingInfo.baijiahaoCoverType === "single" ? "one" : "three";
21839
+ const cover_layout = baijiahaoCoverType === "single" ? "one" : "three";
21839
21840
  const activity_list = [
21840
21841
  ...activityList.length > 0 ? [{ id: `task_${activityList[0]}`, is_checked: 1 }] : [],
21841
21842
  ...isAi ? [{ id: "aigc_bjh_status", is_checked: 1 }] : []
@@ -21901,19 +21902,245 @@ const getBaijiahaoActivity = async (task, params) => {
21901
21902
  return res.data.data.list;
21902
21903
  };
21903
21904
 
21905
+ const getToutiaoConfig = async (task, params) => {
21906
+ task.logger.info("\u83B7\u53D6\u5934\u6761\u53D1\u5E03\u914D\u7F6E\u7684\u8BDD\u9898\u4FE1\u606F\u3001\u4F4D\u7F6E\u4FE1\u606F\u548C\u539F\u521B\u9996\u53D1\u4FE1\u606F");
21907
+ const api = axios$1.create({
21908
+ headers: {
21909
+ cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
21910
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish"
21911
+ }
21912
+ });
21913
+ const getSuggestWords = async () => {
21914
+ try {
21915
+ const res = await api({
21916
+ method: "get",
21917
+ url: "https://mp.toutiao.com/mp/agw/creator_helper/suggest_words",
21918
+ params: { type: 2, words: "" }
21919
+ });
21920
+ return res.data.code === 0 ? res.data.hots : [];
21921
+ } catch (error) {
21922
+ return [];
21923
+ }
21924
+ };
21925
+ const getCityDistrict = async () => {
21926
+ try {
21927
+ const res = await api.get(
21928
+ "https://mp.toutiao.com/toutiao/normandy/mp/city_district/"
21929
+ );
21930
+ return res.data.status === 0 ? res.data.data : null;
21931
+ } catch (error) {
21932
+ return null;
21933
+ }
21934
+ };
21935
+ const getUserRights = async () => {
21936
+ try {
21937
+ const res = await api.get("https://mp.toutiao.com/mp/agw/creator_project/get_benefit_page_info");
21938
+ return res.data.code === 0 ? res.data.data.benefit_level_info_list : [];
21939
+ } catch (error) {
21940
+ return [];
21941
+ }
21942
+ };
21943
+ const [suggestWords, cityDistrict, userRights] = await Promise.all([
21944
+ getSuggestWords(),
21945
+ getCityDistrict(),
21946
+ getUserRights()
21947
+ ]);
21948
+ return { suggestWords, cityDistrict, userRights };
21949
+ };
21950
+
21951
+ const searchToutiaoTopicList = async (task, params) => {
21952
+ task.logger.info("\u641C\u7D22\u5934\u6761\u8BDD\u9898");
21953
+ const api = axios$1.create({
21954
+ headers: {
21955
+ cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
21956
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish"
21957
+ }
21958
+ });
21959
+ try {
21960
+ const res = await api({
21961
+ method: "get",
21962
+ url: "https://mp.toutiao.com/mp/agw/creator_helper/suggest_words",
21963
+ params: { type: 2, words: params.searchValue }
21964
+ });
21965
+ if (res.data.code === 0) {
21966
+ return params.searchValue ? res.data.recents : res.data.hots;
21967
+ }
21968
+ return [];
21969
+ } catch (error) {
21970
+ return [];
21971
+ }
21972
+ };
21973
+
21974
+ const COVER_TYPE = {
21975
+ no: 1,
21976
+ single: 2,
21977
+ multiple: 3
21978
+ };
21979
+ const errnoMap = {
21980
+ 20004020: "\u56FE\u7247\u4E0A\u4F20\u51FA\u73B0\u95EE\u9898\uFF0C\u8BF7\u91CD\u65B0\u7ED1\u5B9A\u8D26\u53F7\u540E\u518D\u5C1D\u8BD5",
21981
+ 7115: "\u6B63\u6587\u548C\u5C01\u9762\u56FE\u7247\u63A8\u8350\u4F7F\u752820M\u4EE5\u5185\u7684jpg\u548Cpng\u56FE\u7247",
21982
+ 100006: "\u6587\u7AE0\u53D1\u5E03\u51FA\u73B0\u95EE\u9898\uFF0C\u8BF7\u91CD\u65B0\u7ED1\u5B9A\u8D26\u53F7\u540E\u518D\u5C1D\u8BD5",
21983
+ 3101: "\u7F51\u7EDC\u73AF\u5883\u6709\u95EE\u9898\uFF0C\u9700\u8981\u53BB\u5E73\u53F0\u5B8C\u6210\u9A8C\u8BC1",
21984
+ 2007: "\u6587\u7AE0\u53D1\u5E03\u51FA\u73B0\u95EE\u9898\uFF0C\u58F0\u660E\u539F\u521B\u65F6\uFF0C\u6B63\u6587\u5B57\u6570\u9700\u5927\u4E8E300\u5B57",
21985
+ 1053: "\u6B63\u6587\u548C\u5C01\u9762\u56FE\u7247\u63A8\u8350\u4F7F\u752820M\u4EE5\u5185\u7684jpg\u548Cpng\u56FE\u7247",
21986
+ 2005: "\u65E0\u58F0\u660E\u539F\u521B\u6743\u9650\uFF0C\u8BF7\u53D6\u6D88\u539F\u521B\u58F0\u660E\u6216\u7533\u8BF7\u539F\u521B\u6743\u9650\u540E\u518D\u5C1D\u8BD5"
21987
+ };
21904
21988
  const mockAction$4 = async (task, params) => {
21905
- task.getTmpPath();
21989
+ const { toutiaoSingleCover, toutiaoMultCover, toutiaoCoverType, toutiaoOriginal } = params.settingInfo;
21990
+ const tmpCachePath = task.getTmpPath();
21906
21991
  const api = axios$1.create({
21907
21992
  headers: {
21908
- cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";")
21993
+ cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
21994
+ origin: "https://mp.toutiao.com",
21995
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish"
21909
21996
  }
21910
21997
  });
21911
- const userInfoRes = await api.get(
21912
- "https://mp.toutiao.com/mp/agw/creator_center/user_info"
21998
+ api.interceptors.response.use(
21999
+ (response) => {
22000
+ if (response.data.code !== 0) {
22001
+ const errmsg = errnoMap[response.data.code] || response.config.defaultErrorMsg || response.data.message || "Unknown error";
22002
+ task.logger.error(errmsg);
22003
+ return Promise.reject(new Error(errmsg));
22004
+ }
22005
+ return response;
22006
+ },
22007
+ (error) => {
22008
+ return Promise.reject(error);
22009
+ }
21913
22010
  );
21914
- if (userInfoRes.data.code !== 0) {
21915
- throw new Error("\u767B\u5F55\u5931\u6548");
21916
- }
22011
+ await api({
22012
+ method: "get",
22013
+ url: "https://mp.toutiao.com/mp/agw/creator_center/user_info",
22014
+ defaultErrorMsg: "\u767B\u5F55\u5931\u6548"
22015
+ });
22016
+ const uploadImages = async (images) => {
22017
+ const localImages = await Promise.all(
22018
+ images.map((url) => {
22019
+ const fileName = getFilenameFromUrl(url);
22020
+ return downloadImage(url, path$1.join(tmpCachePath, fileName));
22021
+ })
22022
+ );
22023
+ return await Promise.all(
22024
+ localImages.map(async (image) => {
22025
+ const formData = new FormData$2();
22026
+ formData.append("image", fs$1.createReadStream(image));
22027
+ const response = await api({
22028
+ method: "post",
22029
+ url: "https://mp.toutiao.com/spice/image?upload_source=20020003&aid=1231&device_platform=web",
22030
+ data: formData,
22031
+ defaultErrorMsg: "\u4E0A\u4F20\u5934\u6761\u53F7\u56FE\u7247\u5931\u8D25"
22032
+ });
22033
+ return response.data.data;
22034
+ })
22035
+ );
22036
+ };
22037
+ const originContentImages = extractImgTag(params.content);
22038
+ const targetContentImages = await uploadImages(originContentImages);
22039
+ const content = replaceImgSrc(params.content, (dom) => {
22040
+ if (dom.attribs.src) {
22041
+ const idx = originContentImages.findIndex((it) => it === dom.attribs.src);
22042
+ dom.attribs.src = targetContentImages[idx].image_url;
22043
+ dom.attribs.web_uri = targetContentImages[idx].image_uri;
22044
+ dom.attribs.img_width = targetContentImages[idx].image_width.toString();
22045
+ dom.attribs.image_height = targetContentImages[idx].image_height.toString();
22046
+ dom.attribs.image_type = targetContentImages[idx].image_type.toString();
22047
+ dom.attribs.mime_type = targetContentImages[idx].image_mime_type;
22048
+ }
22049
+ return dom;
22050
+ });
22051
+ const coverUrl = toutiaoCoverType === "single" ? [toutiaoSingleCover] : toutiaoCoverType === "multiple" ? toutiaoMultCover : [];
22052
+ const coverRes = await uploadImages(coverUrl);
22053
+ const isSingleTitle = params.settingInfo.toutiaoTitleType === "single";
22054
+ const location = params.settingInfo.toutiaoLocation;
22055
+ const topics = params.settingInfo.toutiaoTopic || [];
22056
+ const multiTitleData = params.settingInfo.subTitles.map((title) => ({
22057
+ id: "0",
22058
+ visibility_level: 0,
22059
+ source: "author",
22060
+ old_source: "author",
22061
+ text: title,
22062
+ version: "author",
22063
+ ai_title: ""
22064
+ }));
22065
+ const topicContent = topics.map(
22066
+ (topic) => `<p><a class="tteditor-forum" data-name="${topic.word}" data-id="${topic.id}" data-concern-id="${topic.id}">#${topic.word}#</a ></p >`
22067
+ ).join("");
22068
+ const extraData = {
22069
+ content_word_cnt: params.settingInfo.cntWord,
22070
+ is_multi_title: isSingleTitle ? 0 : 1,
22071
+ sub_titles: isSingleTitle ? [] : multiTitleData,
22072
+ gd_ext: {
22073
+ entrance: "",
22074
+ from_page: "publisher_mp",
22075
+ enter_from: "PC",
22076
+ device_platform: "mp",
22077
+ is_message: 0
22078
+ },
22079
+ tuwen_wtt_trans_flag: "0",
22080
+ info_source: {
22081
+ source_type: 5,
22082
+ source_link: "",
22083
+ time_format: "",
22084
+ position: {}
22085
+ },
22086
+ ...location ? { city: location.label, city_code: location.value } : null
22087
+ };
22088
+ const publishData = {
22089
+ article_type: 0,
22090
+ source: 0,
22091
+ search_creation_info: '{"searchTopOne": 0, "abstract": "", "clue_id": ""}',
22092
+ title_id: "",
22093
+ educluecard: "",
22094
+ origin_debut_check_pgc_normal: 1,
22095
+ is_fans_article: 0,
22096
+ govern_forward: 0,
22097
+ praise: 0,
22098
+ disable_praise: 0,
22099
+ tree_plan_article: 0,
22100
+ star_order_id: "",
22101
+ star_order_name: "",
22102
+ customer_nick_name: "",
22103
+ activity_tag: 0,
22104
+ trends_writing_tag: 0,
22105
+ is_refute_rumor: 0,
22106
+ save: params.saveType === "publish" ? 1 : 0,
22107
+ timer_status: 0,
22108
+ timer_time: "",
22109
+ title: params.title,
22110
+ content: content + topicContent,
22111
+ extra: JSON.stringify(extraData),
22112
+ mp_editor_stat: toutiaoCoverType === "no" ? "{}" : '{"image": %d}',
22113
+ draft_form_data: JSON.stringify({
22114
+ coverType: COVER_TYPE[toutiaoCoverType]
22115
+ }),
22116
+ pgc_feed_covers: JSON.stringify(
22117
+ coverRes.map((item) => ({
22118
+ id: "",
22119
+ url: item.image_url,
22120
+ uri: item.image_uri,
22121
+ ic_uri: "",
22122
+ thumb_widt: item.image_width,
22123
+ thumb_heigh: item.image_height,
22124
+ extra: {
22125
+ from_content_uri: "",
22126
+ from_content: "0"
22127
+ }
22128
+ }))
22129
+ ),
22130
+ article_ad_type: params.settingInfo.toutiaoAd === "yes" ? 3 : 2,
22131
+ claim_origin: toutiaoOriginal.includes("original") ? 1 : 0,
22132
+ claim_exclusive: toutiaoOriginal.includes("exclusive") ? 1 : 0
22133
+ };
22134
+ const publishResult = await api({
22135
+ method: "post",
22136
+ url: "https://mp.toutiao.com/mp/agw/article/publish?source=mp&type=article&aid=1",
22137
+ data: publishData,
22138
+ headers: {
22139
+ "content-type": "application/x-www-form-urlencoded"
22140
+ },
22141
+ defaultErrorMsg: "\u6587\u7AE0\u53D1\u5E03\u51FA\u73B0\u95EE\u9898\uFF0C\u8BF7\u8054\u7CFB\u5BA2\u670D"
22142
+ });
22143
+ return publishResult.data.data.pgc_id;
21917
22144
  };
21918
22145
 
21919
22146
  const toutiaoPublish = async (task, params) => {
@@ -21930,9 +22157,7 @@ const mockAction$3 = async (task, params) => {
21930
22157
  referer: "https://mp.toutiao.com/profile_v4/graphic/publish"
21931
22158
  }
21932
22159
  });
21933
- const userInfoRes = await api.get(
21934
- "https://mp.toutiao.com/mp/agw/creator_center/user_info"
21935
- );
22160
+ const userInfoRes = await api.get("https://mp.toutiao.com/mp/agw/creator_center/user_info");
21936
22161
  if (userInfoRes.data.code !== 0) {
21937
22162
  throw new Error("\u767B\u5F55\u5931\u6548");
21938
22163
  }
@@ -22489,6 +22714,14 @@ class Action {
22489
22714
  constructor(task) {
22490
22715
  this.task = task;
22491
22716
  }
22717
+ // 搜索头条话题列表
22718
+ searchToutiaoTopicList(params) {
22719
+ return searchToutiaoTopicList(this.task, params);
22720
+ }
22721
+ // 获取头条配置
22722
+ getToutiaoConfig(params) {
22723
+ return getToutiaoConfig(this.task, params);
22724
+ }
22492
22725
  // 百家号发布
22493
22726
  baijiahaoPublish(params) {
22494
22727
  return baijiahaoPublish(this.task, params);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iflyrpa/actions",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -34,6 +34,7 @@ const errnoMap: Record<number, string> = {
34
34
  };
35
35
 
36
36
  export const mockAction: PublishAction = async (task, params) => {
37
+ const { baijiahaoSingleCover, baijiahaoMultCover, baijiahaoCoverType } = params.settingInfo;
37
38
  const tmpCachePath = task.getTmpPath();
38
39
 
39
40
  const api = axios.create({
@@ -137,10 +138,7 @@ export const mockAction: PublishAction = async (task, params) => {
137
138
  }
138
139
 
139
140
  // 4. 上传横版封面
140
- const horizontalCoverUrl =
141
- params.settingInfo.baijiahaoCoverType === "single"
142
- ? [params.settingInfo.baijiahaoSingleCover]
143
- : params.settingInfo.baijiahaoMultCover;
141
+ const horizontalCoverUrl = baijiahaoCoverType === "single" ? [baijiahaoSingleCover] : baijiahaoMultCover;
144
142
  const horizontalCoverRes = await uploadImages(horizontalCoverUrl);
145
143
  const cover_images = horizontalCoverRes.map((item) => ({
146
144
  src: item.bos_url,
@@ -155,7 +153,7 @@ export const mockAction: PublishAction = async (task, params) => {
155
153
  // 5. 构造发布数据
156
154
  const isAi = params.settingInfo.baijiahaoIsAi.includes("isAi");
157
155
  const activityList = params.settingInfo.baijiahaoSelectActivityCache;
158
- const cover_layout = params.settingInfo.baijiahaoCoverType === "single" ? "one" : "three";
156
+ const cover_layout = baijiahaoCoverType === "single" ? "one" : "three";
159
157
 
160
158
  const activity_list = [
161
159
  ...(activityList.length > 0 ? [{ id: `task_${activityList[0]}`, is_checked: 1 }] : []),
@@ -0,0 +1,72 @@
1
+ import axios from "axios";
2
+
3
+ import type { CommonAction, CookiesSetDetails } from "@iflyrpa/share";
4
+ import type { ActiomCommonParams, Toutiao } from "../../types";
5
+
6
+ export interface GetToutiaoConfigParams extends Omit<ActiomCommonParams, "cookies"> {
7
+ cookies: Partial<CookiesSetDetails>[];
8
+ }
9
+
10
+ export interface GetToutiaoConfigResult {
11
+ suggestWords: Toutiao.Topic[];
12
+ cityDistrict: Toutiao.CityDistrict | null;
13
+ userRights: Toutiao.UserRight[];
14
+ }
15
+
16
+ export type PublishAction = CommonAction<GetToutiaoConfigParams, GetToutiaoConfigResult>;
17
+
18
+ export const getToutiaoConfig: PublishAction = async (task, params) => {
19
+ task.logger.info("获取头条发布配置的话题信息、位置信息和原创首发信息");
20
+
21
+ const api = axios.create({
22
+ headers: {
23
+ cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
24
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish",
25
+ },
26
+ });
27
+
28
+ const getSuggestWords = async () => {
29
+ try {
30
+ const res = await api<{ code: number; hots: Toutiao.Topic[] }>({
31
+ method: "get",
32
+ url: "https://mp.toutiao.com/mp/agw/creator_helper/suggest_words",
33
+ params: { type: 2, words: "" },
34
+ });
35
+
36
+ return res.data.code === 0 ? res.data.hots : [];
37
+ } catch (error) {
38
+ return [];
39
+ }
40
+ };
41
+
42
+ const getCityDistrict = async () => {
43
+ try {
44
+ const res = await api.get<{ status: number; data: Toutiao.CityDistrict }>(
45
+ "https://mp.toutiao.com/toutiao/normandy/mp/city_district/",
46
+ );
47
+ return res.data.status === 0 ? res.data.data : null;
48
+ } catch (error) {
49
+ return null;
50
+ }
51
+ };
52
+
53
+ const getUserRights = async () => {
54
+ try {
55
+ const res = await api.get<{
56
+ code: number;
57
+ data: { benefit_level_info_list: Toutiao.UserRight[] };
58
+ }>("https://mp.toutiao.com/mp/agw/creator_project/get_benefit_page_info");
59
+ return res.data.code === 0 ? res.data.data.benefit_level_info_list : [];
60
+ } catch (error) {
61
+ return [];
62
+ }
63
+ };
64
+
65
+ const [suggestWords, cityDistrict, userRights] = await Promise.all([
66
+ getSuggestWords(),
67
+ getCityDistrict(),
68
+ getUserRights(),
69
+ ]);
70
+
71
+ return { suggestWords, cityDistrict, userRights };
72
+ };
@@ -0,0 +1,38 @@
1
+ import axios from "axios";
2
+
3
+ import type { CommonAction, CookiesSetDetails } from "@iflyrpa/share";
4
+ import type { ActiomCommonParams, Toutiao } from "../../types";
5
+
6
+ export interface SearchToutiaoTopicListParams extends Omit<ActiomCommonParams, "cookies"> {
7
+ cookies: Partial<CookiesSetDetails>[];
8
+ searchValue: string;
9
+ }
10
+
11
+ export type PublishAction = CommonAction<SearchToutiaoTopicListParams, Toutiao.Topic[]>;
12
+
13
+ export const searchToutiaoTopicList: PublishAction = async (task, params) => {
14
+ task.logger.info("搜索头条话题");
15
+
16
+ const api = axios.create({
17
+ headers: {
18
+ cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
19
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish",
20
+ },
21
+ });
22
+
23
+ try {
24
+ const res = await api<{ code: number; recents: Toutiao.Topic[]; hots: Toutiao.Topic[] }>({
25
+ method: "get",
26
+ url: "https://mp.toutiao.com/mp/agw/creator_helper/suggest_words",
27
+ params: { type: 2, words: params.searchValue },
28
+ });
29
+
30
+ if (res.data.code === 0) {
31
+ return params.searchValue ? res.data.recents : res.data.hots;
32
+ }
33
+
34
+ return [];
35
+ } catch (error) {
36
+ return [];
37
+ }
38
+ };
@@ -2,12 +2,26 @@ import type { CommonAction, CookiesSetDetails } from "@iflyrpa/share";
2
2
  import type { ActiomCommonParams } from "../../types";
3
3
  import { mockAction } from "./mock";
4
4
 
5
- export interface ToutiaoPublishParams
6
- extends Omit<ActiomCommonParams, "cookies"> {
5
+ export interface ToutiaoPublishParams extends Omit<ActiomCommonParams, "cookies"> {
6
+ saveType: "draft" | "publish"; // 保存成草稿 / 发布
7
7
  cookies: Partial<CookiesSetDetails>[];
8
+ title: string;
9
+ content: string;
10
+ settingInfo: {
11
+ toutiaoCoverType: "single" | "multiple" | "no";
12
+ toutiaoTitleType: "single" | "multiple";
13
+ toutiaoSingleCover: string;
14
+ toutiaoMultCover: string[];
15
+ toutiaoAd: string; // 广告配置 - 投放广告/不投放广告
16
+ toutiaoOriginal: string; // 作品声明
17
+ toutiaoLocation?: { label: string; value: string }; // 位置
18
+ toutiaoTopic: { id: string; word: string }[]; // 话题
19
+ cntWord: number;
20
+ subTitles: string[]; // 多标题
21
+ };
8
22
  }
9
23
 
10
- export type PublishAction = CommonAction<ToutiaoPublishParams>;
24
+ export type PublishAction = CommonAction<ToutiaoPublishParams, string>;
11
25
 
12
26
  export const toutiaoPublish: PublishAction = async (task, params) => {
13
27
  task.logger.info("开始头条发布");
@@ -1,24 +1,222 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { downloadImage, getFilenameFromUrl } from "@iflyrpa/share";
4
- import axios from "axios";
4
+ import axios, { type AxiosResponse } from "axios";
5
5
  import FormData from "form-data";
6
- import type { PublishAction } from ".";
6
+
7
+ import type { PublishAction, ToutiaoPublishParams } from ".";
8
+ import type { Toutiao } from "../../types";
9
+ import { extractImgTag, replaceImgSrc } from "../../utils";
10
+
11
+ interface CommonResponse<T = unknown> {
12
+ data: T;
13
+ code: number;
14
+ message: string;
15
+ }
16
+
17
+ const COVER_TYPE: Record<ToutiaoPublishParams["settingInfo"]["toutiaoCoverType"], number> = {
18
+ no: 1,
19
+ single: 2,
20
+ multiple: 3,
21
+ };
22
+
23
+ const errnoMap: Record<number, string> = {
24
+ 20004020: "图片上传出现问题,请重新绑定账号后再尝试",
25
+ 7115: "正文和封面图片推荐使用20M以内的jpg和png图片",
26
+ 100006: "文章发布出现问题,请重新绑定账号后再尝试",
27
+ 3101: "网络环境有问题,需要去平台完成验证",
28
+ 2007: "文章发布出现问题,声明原创时,正文字数需大于300字",
29
+ 1053: "正文和封面图片推荐使用20M以内的jpg和png图片",
30
+ 2005: "无声明原创权限,请取消原创声明或申请原创权限后再尝试",
31
+ };
7
32
 
8
33
  export const mockAction: PublishAction = async (task, params) => {
34
+ const { toutiaoSingleCover, toutiaoMultCover, toutiaoCoverType, toutiaoOriginal } = params.settingInfo;
9
35
  const tmpCachePath = task.getTmpPath();
10
36
 
11
37
  const api = axios.create({
12
38
  headers: {
13
39
  cookie: params.cookies.map((it) => `${it.name}=${it.value}`).join(";"),
40
+ origin: "https://mp.toutiao.com",
41
+ referer: "https://mp.toutiao.com/profile_v4/graphic/publish",
14
42
  },
15
43
  });
16
44
 
17
- // 0. 校验登录
18
- const userInfoRes = await api.get<{ code: number }>(
19
- "https://mp.toutiao.com/mp/agw/creator_center/user_info",
45
+ // 添加响应拦截器
46
+ api.interceptors.response.use(
47
+ (response: AxiosResponse<CommonResponse>) => {
48
+ // 检查响应中的 errno 字段
49
+ if (response.data.code !== 0) {
50
+ const errmsg =
51
+ errnoMap[response.data.code] || response.config.defaultErrorMsg || response.data.message || "Unknown error";
52
+
53
+ task.logger.error(errmsg);
54
+
55
+ return Promise.reject(new Error(errmsg));
56
+ }
57
+ // 如果 errno 为 0,返回响应数据
58
+ return response;
59
+ },
60
+ (error) => {
61
+ // 处理响应错误
62
+ return Promise.reject(error);
63
+ },
20
64
  );
21
- if (userInfoRes.data.code !== 0) {
22
- throw new Error("登录失效");
23
- }
65
+
66
+ // 0. 校验登录
67
+ await api<{ code: number }>({
68
+ method: "get",
69
+ url: "https://mp.toutiao.com/mp/agw/creator_center/user_info",
70
+ defaultErrorMsg: "登录失效",
71
+ });
72
+
73
+ const uploadImages = async (images: string[]) => {
74
+ // 下载图片到本地
75
+ const localImages = await Promise.all(
76
+ images.map((url) => {
77
+ const fileName = getFilenameFromUrl(url);
78
+ return downloadImage(url, path.join(tmpCachePath, fileName));
79
+ }),
80
+ );
81
+
82
+ return await Promise.all(
83
+ localImages.map(async (image) => {
84
+ const formData = new FormData();
85
+ formData.append("image", fs.createReadStream(image));
86
+
87
+ const response = await api<{ data: Toutiao.ImageData }>({
88
+ method: "post",
89
+ url: "https://mp.toutiao.com/spice/image?upload_source=20020003&aid=1231&device_platform=web",
90
+ data: formData,
91
+ defaultErrorMsg: "上传头条号图片失败",
92
+ });
93
+
94
+ return response.data.data;
95
+ }),
96
+ );
97
+ };
98
+
99
+ // 1. 提取并上传正文中的图片
100
+ const originContentImages = extractImgTag(params.content);
101
+ const targetContentImages = await uploadImages(originContentImages);
102
+ // 2. 替换正文中的图片
103
+ const content = replaceImgSrc(params.content, (dom) => {
104
+ if (dom.attribs.src) {
105
+ const idx = originContentImages.findIndex((it) => it === dom.attribs.src);
106
+ dom.attribs.src = targetContentImages[idx].image_url;
107
+ dom.attribs.web_uri = targetContentImages[idx].image_uri;
108
+ dom.attribs.img_width = targetContentImages[idx].image_width.toString();
109
+ dom.attribs.image_height = targetContentImages[idx].image_height.toString();
110
+ dom.attribs.image_type = targetContentImages[idx].image_type.toString();
111
+ dom.attribs.mime_type = targetContentImages[idx].image_mime_type;
112
+ }
113
+ return dom;
114
+ });
115
+
116
+ // 3. 上传横版封面
117
+ const coverUrl =
118
+ toutiaoCoverType === "single" ? [toutiaoSingleCover] : toutiaoCoverType === "multiple" ? toutiaoMultCover : [];
119
+ const coverRes = await uploadImages(coverUrl);
120
+
121
+ // 4. 构造发布数据
122
+ const isSingleTitle = params.settingInfo.toutiaoTitleType === "single";
123
+ const location = params.settingInfo.toutiaoLocation;
124
+ const topics = params.settingInfo.toutiaoTopic || [];
125
+
126
+ const multiTitleData = params.settingInfo.subTitles.map((title) => ({
127
+ id: "0",
128
+ visibility_level: 0,
129
+ source: "author",
130
+ old_source: "author",
131
+ text: title,
132
+ version: "author",
133
+ ai_title: "",
134
+ }));
135
+
136
+ const topicContent = topics
137
+ .map(
138
+ (topic) =>
139
+ `<p><a class="tteditor-forum" data-name="${topic.word}" data-id="${topic.id}" data-concern-id="${topic.id}">#${topic.word}#</a ></p >`,
140
+ )
141
+ .join("");
142
+
143
+ const extraData = {
144
+ content_word_cnt: params.settingInfo.cntWord,
145
+ is_multi_title: isSingleTitle ? 0 : 1,
146
+ sub_titles: isSingleTitle ? [] : multiTitleData,
147
+ gd_ext: {
148
+ entrance: "",
149
+ from_page: "publisher_mp",
150
+ enter_from: "PC",
151
+ device_platform: "mp",
152
+ is_message: 0,
153
+ },
154
+ tuwen_wtt_trans_flag: "0",
155
+ info_source: {
156
+ source_type: 5,
157
+ source_link: "",
158
+ time_format: "",
159
+ position: {},
160
+ },
161
+ ...(location ? { city: location.label, city_code: location.value } : null),
162
+ };
163
+
164
+ const publishData = {
165
+ article_type: 0,
166
+ source: 0,
167
+ search_creation_info: '{"searchTopOne": 0, "abstract": "", "clue_id": ""}',
168
+ title_id: "",
169
+ educluecard: "",
170
+ origin_debut_check_pgc_normal: 1,
171
+ is_fans_article: 0,
172
+ govern_forward: 0,
173
+ praise: 0,
174
+ disable_praise: 0,
175
+ tree_plan_article: 0,
176
+ star_order_id: "",
177
+ star_order_name: "",
178
+ customer_nick_name: "",
179
+ activity_tag: 0,
180
+ trends_writing_tag: 0,
181
+ is_refute_rumor: 0,
182
+ save: params.saveType === "publish" ? 1 : 0,
183
+ timer_status: 0,
184
+ timer_time: "",
185
+ title: params.title,
186
+ content: content + topicContent,
187
+ extra: JSON.stringify(extraData),
188
+ mp_editor_stat: toutiaoCoverType === "no" ? "{}" : '{"image": %d}',
189
+ draft_form_data: JSON.stringify({
190
+ coverType: COVER_TYPE[toutiaoCoverType],
191
+ }),
192
+ pgc_feed_covers: JSON.stringify(
193
+ coverRes.map((item) => ({
194
+ id: "",
195
+ url: item.image_url,
196
+ uri: item.image_uri,
197
+ ic_uri: "",
198
+ thumb_widt: item.image_width,
199
+ thumb_heigh: item.image_height,
200
+ extra: {
201
+ from_content_uri: "",
202
+ from_content: "0",
203
+ },
204
+ })),
205
+ ),
206
+ article_ad_type: params.settingInfo.toutiaoAd === "yes" ? 3 : 2,
207
+ claim_origin: toutiaoOriginal.includes("original") ? 1 : 0,
208
+ claim_exclusive: toutiaoOriginal.includes("exclusive") ? 1 : 0,
209
+ };
210
+
211
+ const publishResult = await api<{ data: { pgc_id: string } }>({
212
+ method: "post",
213
+ url: "https://mp.toutiao.com/mp/agw/article/publish?source=mp&type=article&aid=1",
214
+ data: publishData,
215
+ headers: {
216
+ "content-type": "application/x-www-form-urlencoded",
217
+ },
218
+ defaultErrorMsg: "文章发布出现问题,请联系客服",
219
+ });
220
+
221
+ return publishResult.data.data.pgc_id;
24
222
  };
@@ -3,7 +3,9 @@ import path from "node:path";
3
3
  import { downloadImage, getFilenameFromUrl } from "@iflyrpa/share";
4
4
  import axios from "axios";
5
5
  import FormData from "form-data";
6
+
6
7
  import type { PublishAction } from ".";
8
+ import type { Toutiao } from "../../types";
7
9
 
8
10
  export const mockAction: PublishAction = async (task, params) => {
9
11
  const tmpCachePath = task.getTmpPath();
@@ -17,9 +19,7 @@ export const mockAction: PublishAction = async (task, params) => {
17
19
  });
18
20
 
19
21
  // 0. 校验登录
20
- const userInfoRes = await api.get<{ code: number }>(
21
- "https://mp.toutiao.com/mp/agw/creator_center/user_info",
22
- );
22
+ const userInfoRes = await api.get<{ code: number }>("https://mp.toutiao.com/mp/agw/creator_center/user_info");
23
23
  if (userInfoRes.data.code !== 0) {
24
24
  throw new Error("登录失效");
25
25
  }
@@ -39,7 +39,7 @@ export const mockAction: PublishAction = async (task, params) => {
39
39
  const formData = new FormData();
40
40
  formData.append("image", fs.createReadStream(it));
41
41
 
42
- const response = await api<{ data: { image_uri: string } }>({
42
+ const response = await api<{ data: Toutiao.ImageData }>({
43
43
  method: "post",
44
44
  url: "https://mp.toutiao.com/spice/image?upload_source=20020003&aid=1231&device_platform=web",
45
45
  data: formData,
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { AutomateTask } from "@iflyrpa/share";
2
2
  import { type BaijiahaoPublishParams, baijiahaoPublish } from "./actions/baijiahaoPublish";
3
3
  import { type GetBaijiahaoActivityParams, getBaijiahaoActivity } from "./actions/getBaijiahaoActivity";
4
+ import { type GetToutiaoConfigParams, getToutiaoConfig } from "./actions/getToutiaoConfig";
5
+ import { type SearchToutiaoTopicListParams, searchToutiaoTopicList } from "./actions/searchToutiaoTopicList";
4
6
  import { type ToutiaoPublishParams, toutiaoPublish } from "./actions/toutiaoPublish";
5
7
  import { type WeitoutiaoPublishParams, weitoutiaoPublish } from "./actions/weitoutiaoPublish";
6
8
  import { type WeixinPublishParams, weixinPublish } from "./actions/weixinPublish";
@@ -10,6 +12,16 @@ import { type XiaohongshuPublishParams, xiaohongshuPublish } from "./actions/xia
10
12
  export class Action {
11
13
  constructor(private task: AutomateTask) {}
12
14
 
15
+ // 搜索头条话题列表
16
+ searchToutiaoTopicList(params: SearchToutiaoTopicListParams) {
17
+ return searchToutiaoTopicList(this.task, params);
18
+ }
19
+
20
+ // 获取头条配置
21
+ getToutiaoConfig(params: GetToutiaoConfigParams) {
22
+ return getToutiaoConfig(this.task, params);
23
+ }
24
+
13
25
  // 百家号发布
14
26
  baijiahaoPublish(params: BaijiahaoPublishParams) {
15
27
  return baijiahaoPublish(this.task, params);
package/src/types.ts CHANGED
@@ -18,3 +18,40 @@ export interface WeiXinCropResult {
18
18
  width: number;
19
19
  height: number;
20
20
  }
21
+
22
+ export namespace Toutiao {
23
+ export interface Topic {
24
+ concern_id: string;
25
+ id: string;
26
+ talk_count: string;
27
+ talk_count_str: string;
28
+ type: number;
29
+ word: string;
30
+ }
31
+
32
+ export interface CityDistrict {
33
+ gps_location: {
34
+ city_name: string;
35
+ city_code: string;
36
+ district_name: string;
37
+ district_code: string;
38
+ };
39
+ }
40
+
41
+ export interface UserRight {
42
+ benefit_list: Array<unknown>;
43
+ describe: string;
44
+ fans_num_threshold: number;
45
+ level: number;
46
+ type: number;
47
+ }
48
+
49
+ export interface ImageData {
50
+ image_url: string;
51
+ image_uri: string;
52
+ image_width: string;
53
+ image_height: string;
54
+ image_type: string;
55
+ image_mime_type: string;
56
+ }
57
+ }