@iflyrpa/actions 4.1.0-beta.5 → 4.1.0
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/actions/searchAccountInfo/index.d.ts +1 -1
- package/dist/actions/shipinhaoPublishVideo/index.d.ts +45 -1
- package/dist/actions/shipinhaoPublishVideo/payload.d.ts +70 -0
- package/dist/actions/shipinhaoPublishVideo/uploader.d.ts +19 -0
- package/dist/actions/shipinhaoPublishVideo/videoMeta.d.ts +43 -5
- package/dist/actions/shipinhaoPublishVideo/videoValidator.d.ts +4 -2
- package/dist/bundle.js +886 -310
- package/dist/bundle.js.map +1 -1
- package/dist/index.js +884 -308
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +884 -308
- package/dist/index.mjs.map +1 -1
- package/dist/utils/feishuAlarm.d.ts +4 -1
- package/dist/utils/http.d.ts +16 -0
- package/dist/utils/shipinhao/utils.d.ts +10 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="028a0eb4-9179-5708-bae0-75174165ae68")}catch(e){}}();
|
|
3
3
|
var __webpack_modules__ = {
|
|
4
4
|
"./src/utils/XhsXsCommonEnc.js": function(module) {
|
|
5
5
|
var encrypt_lookup = [
|
|
@@ -4403,7 +4403,9 @@ var __webpack_exports__ = {};
|
|
|
4403
4403
|
});
|
|
4404
4404
|
const package_json_namespaceObject = require("@iflyrpa/share/package.json");
|
|
4405
4405
|
var package_json_default = /*#__PURE__*/ __webpack_require__.n(package_json_namespaceObject);
|
|
4406
|
-
var package_namespaceObject =
|
|
4406
|
+
var package_namespaceObject = {
|
|
4407
|
+
i8: "4.1.0"
|
|
4408
|
+
};
|
|
4407
4409
|
const share_namespaceObject = require("@iflyrpa/share");
|
|
4408
4410
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
4409
4411
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
@@ -4452,6 +4454,11 @@ var __webpack_exports__ = {};
|
|
|
4452
4454
|
const RPA_ERROR_WEBHOOK_URL = "https://open.xfchat.iflytek.com/open-apis/bot/v2/hook/d202c0dc-5af5-40bc-83ed-abc677caa4a5";
|
|
4453
4455
|
const ALARM_THROTTLE_MS = 60000;
|
|
4454
4456
|
const lastSentAt = new Map();
|
|
4457
|
+
const THROTTLE_MAP_MAX_KEYS = 500;
|
|
4458
|
+
const pruneThrottleMap = (now)=>{
|
|
4459
|
+
if (lastSentAt.size < THROTTLE_MAP_MAX_KEYS) return;
|
|
4460
|
+
for (const [key, at] of lastSentAt)if (now - at >= ALARM_THROTTLE_MS) lastSentAt.delete(key);
|
|
4461
|
+
};
|
|
4455
4462
|
const postFeishuWebhook = (webhookUrl, payload)=>external_axios_default().post(webhookUrl, payload, {
|
|
4456
4463
|
headers: {
|
|
4457
4464
|
"Content-Type": "application/json"
|
|
@@ -4529,10 +4536,11 @@ var __webpack_exports__ = {};
|
|
|
4529
4536
|
};
|
|
4530
4537
|
const reportFeishuAlarm = (report)=>{
|
|
4531
4538
|
try {
|
|
4532
|
-
const key = `${report.platform}|${report.source}|${report.errorType}|${report.code ?? ""}`;
|
|
4539
|
+
const key = `${report.platform}|${report.source}|${report.stage}|${report.errorType}|${report.code ?? ""}`;
|
|
4533
4540
|
const now = Date.now();
|
|
4534
4541
|
const last = lastSentAt.get(key);
|
|
4535
4542
|
if (last && now - last < ALARM_THROTTLE_MS) return;
|
|
4543
|
+
pruneThrottleMap(now);
|
|
4536
4544
|
lastSentAt.set(key, now);
|
|
4537
4545
|
postFeishuWebhook(RPA_ERROR_WEBHOOK_URL, buildFeishuPostMessage(report)).catch(()=>{});
|
|
4538
4546
|
} catch {}
|
|
@@ -4679,6 +4687,19 @@ var __webpack_exports__ = {};
|
|
|
4679
4687
|
461,
|
|
4680
4688
|
471
|
|
4681
4689
|
]);
|
|
4690
|
+
function isLocalAddress(url) {
|
|
4691
|
+
let hostname;
|
|
4692
|
+
try {
|
|
4693
|
+
hostname = new URL(url).hostname.toLowerCase();
|
|
4694
|
+
} catch {
|
|
4695
|
+
return false;
|
|
4696
|
+
}
|
|
4697
|
+
if ("localhost" === hostname || "::1" === hostname || "[::1]" === hostname) return true;
|
|
4698
|
+
if (hostname.endsWith(".localhost") || hostname.endsWith(".local")) return true;
|
|
4699
|
+
if (/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostname)) return true;
|
|
4700
|
+
if ("0.0.0.0" === hostname) return true;
|
|
4701
|
+
return false;
|
|
4702
|
+
}
|
|
4682
4703
|
const HTTP_STATUS_MESSAGE = {
|
|
4683
4704
|
400: "请求参数错误,请检查参数格式是否正确!",
|
|
4684
4705
|
401: "登录状态已失效,请重新登录后重试!",
|
|
@@ -4715,7 +4736,14 @@ var __webpack_exports__ = {};
|
|
|
4715
4736
|
};
|
|
4716
4737
|
class Http {
|
|
4717
4738
|
static handleApiError(error) {
|
|
4718
|
-
if (error && "object" == typeof error && "code" in error && "message" in error)
|
|
4739
|
+
if (error && "object" == typeof error && "code" in error && "message" in error) {
|
|
4740
|
+
const resp = error;
|
|
4741
|
+
if ("string" != typeof resp.message || !resp.message.trim()) return {
|
|
4742
|
+
...resp,
|
|
4743
|
+
message: USER_MESSAGE.SYSTEM_ERROR
|
|
4744
|
+
};
|
|
4745
|
+
return resp;
|
|
4746
|
+
}
|
|
4719
4747
|
return {
|
|
4720
4748
|
code: 500,
|
|
4721
4749
|
message: USER_MESSAGE.SYSTEM_ERROR,
|
|
@@ -4853,25 +4881,47 @@ var __webpack_exports__ = {};
|
|
|
4853
4881
|
errorResponse.message = message;
|
|
4854
4882
|
}
|
|
4855
4883
|
if (error.message.includes("Proxy connection ended")) errorResponse.message = "所在区域代理连接超时,请更换区域或稍后重试!";
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
stage: `${(error.config?.method || "get").toUpperCase()} ${error.config?.url || "-"}`,
|
|
4862
|
-
errorType: status ? `HTTP_${status}` : error.code || "NETWORK_ERROR",
|
|
4863
|
-
code: errorResponse.code,
|
|
4864
|
-
msg: errorResponse.message,
|
|
4865
|
-
url: error.config?.url,
|
|
4866
|
-
title: "RPA接口异常"
|
|
4867
|
-
});
|
|
4884
|
+
errorResponse.extra = {
|
|
4885
|
+
...errorResponse.extra,
|
|
4886
|
+
alarmStatus: error.response?.status,
|
|
4887
|
+
alarmErrorCode: error.code
|
|
4888
|
+
};
|
|
4868
4889
|
throw errorResponse;
|
|
4869
4890
|
});
|
|
4870
4891
|
}
|
|
4892
|
+
reportRequestFailure(config, error, attempts) {
|
|
4893
|
+
const status = error.extra?.alarmStatus;
|
|
4894
|
+
const axiosCode = error.extra?.alarmErrorCode;
|
|
4895
|
+
const method = (config.method || "get").toUpperCase();
|
|
4896
|
+
const baseURL = config.baseURL || this.apiClient.defaults.baseURL || "";
|
|
4897
|
+
const fullUrl = config.url ? /^https?:\/\//.test(config.url) ? config.url : `${baseURL.replace(/\/$/, "")}${config.url}` : baseURL;
|
|
4898
|
+
if (!fullUrl) {
|
|
4899
|
+
this.logger?.debug(`[告警跳过] 请求失败但无 URL,不上报: ${error.message}`);
|
|
4900
|
+
return;
|
|
4901
|
+
}
|
|
4902
|
+
if (isLocalAddress(fullUrl)) {
|
|
4903
|
+
this.logger?.debug(`[告警跳过] 本机地址不上报: ${fullUrl}`);
|
|
4904
|
+
return;
|
|
4905
|
+
}
|
|
4906
|
+
const rawMsg = "string" == typeof error.message && error.message.trim() ? error.message : "";
|
|
4907
|
+
const baseMsg = rawMsg || `请求失败(无错误文案,code=${error.code ?? "unknown"})`;
|
|
4908
|
+
const retriedSuffix = attempts > 0 ? `(已重试${attempts}次仍失败)` : "";
|
|
4909
|
+
reportFeishuAlarm({
|
|
4910
|
+
level: status && ALARM_STATUS.has(status) ? "alarm" : "warning",
|
|
4911
|
+
platform: "@iflyrpa/playwright",
|
|
4912
|
+
source: "http",
|
|
4913
|
+
stage: `${method} ${fullUrl}`,
|
|
4914
|
+
errorType: status ? `HTTP_${status}` : axiosCode || "NETWORK_ERROR",
|
|
4915
|
+
code: error.code,
|
|
4916
|
+
msg: `${baseMsg}${retriedSuffix}`,
|
|
4917
|
+
url: fullUrl,
|
|
4918
|
+
title: "RPA接口异常"
|
|
4919
|
+
});
|
|
4920
|
+
}
|
|
4871
4921
|
async api(config, options) {
|
|
4872
4922
|
const retries = options?.retries ?? 0;
|
|
4873
4923
|
const retryDelay = options?.retryDelay ?? 500;
|
|
4874
|
-
const reqTimeout = options?.timeout ??
|
|
4924
|
+
const reqTimeout = options?.timeout ?? 60000;
|
|
4875
4925
|
const externalSignal = options?.signal;
|
|
4876
4926
|
let agent;
|
|
4877
4927
|
const sessionRt = async (Rtimes)=>{
|
|
@@ -4912,10 +4962,12 @@ var __webpack_exports__ = {};
|
|
|
4912
4962
|
].includes(handledError.code);
|
|
4913
4963
|
if (Rtimes < retries && isRetry) {
|
|
4914
4964
|
const url = config.url || "";
|
|
4915
|
-
|
|
4916
|
-
|
|
4965
|
+
const backoff = Math.min(retryDelay * 2 ** Rtimes, 5000);
|
|
4966
|
+
this.logger?.warn(`进入第${Rtimes + 1}次重试!错误码: ${handledError.code}, 等待: ${backoff}ms, 请求地址: ${url}`);
|
|
4967
|
+
await new Promise((resolve)=>setTimeout(resolve, backoff));
|
|
4917
4968
|
return sessionRt(Rtimes + 1);
|
|
4918
4969
|
}
|
|
4970
|
+
this.reportRequestFailure(config, handledError, Rtimes);
|
|
4919
4971
|
return Promise.reject(handledError);
|
|
4920
4972
|
}
|
|
4921
4973
|
};
|
|
@@ -6031,7 +6083,7 @@ var __webpack_exports__ = {};
|
|
|
6031
6083
|
const cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
|
|
6032
6084
|
const regexes_base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
|
|
6033
6085
|
const regexes_base64url = /^[A-Za-z0-9_-]*$/;
|
|
6034
|
-
const
|
|
6086
|
+
const regexes_hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
|
6035
6087
|
const e164 = /^\+(?:[0-9]){6,14}[0-9]$/;
|
|
6036
6088
|
const dateSource = "(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))";
|
|
6037
6089
|
const regexes_date = /*@__PURE__*/ new RegExp(`^${dateSource}$`);
|
|
@@ -6627,7 +6679,7 @@ var __webpack_exports__ = {};
|
|
|
6627
6679
|
code: "invalid_format",
|
|
6628
6680
|
format: "url",
|
|
6629
6681
|
note: "Invalid hostname",
|
|
6630
|
-
pattern:
|
|
6682
|
+
pattern: regexes_hostname.source,
|
|
6631
6683
|
input: payload.value,
|
|
6632
6684
|
inst,
|
|
6633
6685
|
continue: !def.abort
|
|
@@ -8638,6 +8690,14 @@ var __webpack_exports__ = {};
|
|
|
8638
8690
|
};
|
|
8639
8691
|
return new ZodObject(def);
|
|
8640
8692
|
}
|
|
8693
|
+
function looseObject(shape, params) {
|
|
8694
|
+
return new ZodObject({
|
|
8695
|
+
type: "object",
|
|
8696
|
+
shape,
|
|
8697
|
+
catchall: unknown(),
|
|
8698
|
+
...normalizeParams(params)
|
|
8699
|
+
});
|
|
8700
|
+
}
|
|
8641
8701
|
const ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def)=>{
|
|
8642
8702
|
$ZodUnion.init(inst, def);
|
|
8643
8703
|
ZodType.init(inst, def);
|
|
@@ -9332,7 +9392,7 @@ var __webpack_exports__ = {};
|
|
|
9332
9392
|
".png"
|
|
9333
9393
|
].includes(ext)) throw {
|
|
9334
9394
|
code: 414,
|
|
9335
|
-
message:
|
|
9395
|
+
message: "图片格式不支持,百家号仅支持 jpg、png 格式,请转换后重试。",
|
|
9336
9396
|
data: ""
|
|
9337
9397
|
};
|
|
9338
9398
|
const image = await (0, share_namespaceObject.downloadImage)(url, external_node_path_default().join(tmpCachePath, fileName));
|
|
@@ -10015,7 +10075,8 @@ var __webpack_exports__ = {};
|
|
|
10015
10075
|
},
|
|
10016
10076
|
_task.logger,
|
|
10017
10077
|
params.proxyLoc,
|
|
10018
|
-
params.accountId
|
|
10078
|
+
params.accountId,
|
|
10079
|
+
"xiaohongshu"
|
|
10019
10080
|
];
|
|
10020
10081
|
const http = new Http(...args);
|
|
10021
10082
|
const fans = {
|
|
@@ -10029,8 +10090,8 @@ var __webpack_exports__ = {};
|
|
|
10029
10090
|
url: "https://creator.xiaohongshu.com/api/galaxy/creator/home/personal_info"
|
|
10030
10091
|
}, {
|
|
10031
10092
|
retries: 3,
|
|
10032
|
-
retryDelay:
|
|
10033
|
-
timeout:
|
|
10093
|
+
retryDelay: 300,
|
|
10094
|
+
timeout: 30000
|
|
10034
10095
|
});
|
|
10035
10096
|
fans.fans_count = Number(res.data.fans_count);
|
|
10036
10097
|
fans.digg_count = Number(res.data.faved_count);
|
|
@@ -11167,7 +11228,8 @@ var __webpack_exports__ = {};
|
|
|
11167
11228
|
},
|
|
11168
11229
|
_task.logger,
|
|
11169
11230
|
params.proxyLoc,
|
|
11170
|
-
params.accountId
|
|
11231
|
+
params.accountId,
|
|
11232
|
+
"xiaohongshu"
|
|
11171
11233
|
];
|
|
11172
11234
|
const http = new Http(...args);
|
|
11173
11235
|
http.addResponseInterceptor((response)=>{
|
|
@@ -11215,8 +11277,8 @@ var __webpack_exports__ = {};
|
|
|
11215
11277
|
headers: loginBaseXsHeader
|
|
11216
11278
|
}, {
|
|
11217
11279
|
retries: 3,
|
|
11218
|
-
retryDelay:
|
|
11219
|
-
timeout:
|
|
11280
|
+
retryDelay: 300,
|
|
11281
|
+
timeout: 30000
|
|
11220
11282
|
}).catch((e)=>{
|
|
11221
11283
|
const clientTimestamp = Date.now();
|
|
11222
11284
|
const serverDate = e?.extra?.serverDate;
|
|
@@ -11248,8 +11310,8 @@ var __webpack_exports__ = {};
|
|
|
11248
11310
|
headers: webSessionXsHeader
|
|
11249
11311
|
}, {
|
|
11250
11312
|
retries: 3,
|
|
11251
|
-
retryDelay:
|
|
11252
|
-
timeout:
|
|
11313
|
+
retryDelay: 300,
|
|
11314
|
+
timeout: 30000
|
|
11253
11315
|
});
|
|
11254
11316
|
const [baseInfo, web_session] = await Promise.all([
|
|
11255
11317
|
_baseInfo,
|
|
@@ -11341,6 +11403,10 @@ var __webpack_exports__ = {};
|
|
|
11341
11403
|
};
|
|
11342
11404
|
return (0, share_namespaceObject.success)(data, message);
|
|
11343
11405
|
};
|
|
11406
|
+
const extractEncFileKey = (downloadUrl)=>{
|
|
11407
|
+
if (!downloadUrl) return "";
|
|
11408
|
+
return downloadUrl.split("encfilekey=")[1]?.split("&")[0] || "";
|
|
11409
|
+
};
|
|
11344
11410
|
const rid = ()=>`${Math.floor(Date.now() / 1e3).toString(16)}-${[
|
|
11345
11411
|
...Array(8)
|
|
11346
11412
|
].map(()=>Math.floor(16 * Math.random()).toString(16)).join("")}`;
|
|
@@ -15500,7 +15566,8 @@ var __webpack_exports__ = {};
|
|
|
15500
15566
|
},
|
|
15501
15567
|
_task.logger,
|
|
15502
15568
|
params.proxyLoc,
|
|
15503
|
-
params.accountId
|
|
15569
|
+
params.accountId,
|
|
15570
|
+
"xiaohongshu"
|
|
15504
15571
|
];
|
|
15505
15572
|
const http = new Http(...args);
|
|
15506
15573
|
let unreadCount = {
|
|
@@ -15529,8 +15596,8 @@ var __webpack_exports__ = {};
|
|
|
15529
15596
|
headers: xsHeader
|
|
15530
15597
|
}, {
|
|
15531
15598
|
retries: 3,
|
|
15532
|
-
retryDelay:
|
|
15533
|
-
timeout:
|
|
15599
|
+
retryDelay: 300,
|
|
15600
|
+
timeout: 30000
|
|
15534
15601
|
});
|
|
15535
15602
|
const isSuccess = 0 === res.code;
|
|
15536
15603
|
if (isSuccess) unreadCount = res.data;
|
|
@@ -15943,7 +16010,8 @@ var __webpack_exports__ = {};
|
|
|
15943
16010
|
},
|
|
15944
16011
|
_task.logger,
|
|
15945
16012
|
params.proxyLoc,
|
|
15946
|
-
params.accountId
|
|
16013
|
+
params.accountId,
|
|
16014
|
+
"xiaohongshu"
|
|
15947
16015
|
];
|
|
15948
16016
|
const http = new Http(...args);
|
|
15949
16017
|
const xsEncrypt = new Xhshow();
|
|
@@ -15959,8 +16027,8 @@ var __webpack_exports__ = {};
|
|
|
15959
16027
|
url: "https://creator.xiaohongshu.com/api/galaxy/creator/home/personal_info"
|
|
15960
16028
|
}, {
|
|
15961
16029
|
retries: 3,
|
|
15962
|
-
retryDelay:
|
|
15963
|
-
timeout:
|
|
16030
|
+
retryDelay: 300,
|
|
16031
|
+
timeout: 30000
|
|
15964
16032
|
}),
|
|
15965
16033
|
http.api({
|
|
15966
16034
|
method: "get",
|
|
@@ -15969,8 +16037,8 @@ var __webpack_exports__ = {};
|
|
|
15969
16037
|
headers: sevenDataXsHeader
|
|
15970
16038
|
}, {
|
|
15971
16039
|
retries: 3,
|
|
15972
|
-
retryDelay:
|
|
15973
|
-
timeout:
|
|
16040
|
+
retryDelay: 300,
|
|
16041
|
+
timeout: 30000
|
|
15974
16042
|
})
|
|
15975
16043
|
]);
|
|
15976
16044
|
const xhsData = {
|
|
@@ -18832,7 +18900,7 @@ var __webpack_exports__ = {};
|
|
|
18832
18900
|
name: params.music.name,
|
|
18833
18901
|
artist: params.music.authorName,
|
|
18834
18902
|
mediaStreamingUrl: params.music.url,
|
|
18835
|
-
docType: params.music.raw.
|
|
18903
|
+
docType: 2 === params.music.raw.bgmSource ? 0 : 1
|
|
18836
18904
|
},
|
|
18837
18905
|
groupId: params.music.id,
|
|
18838
18906
|
hasBgm: 1,
|
|
@@ -19009,7 +19077,7 @@ var __webpack_exports__ = {};
|
|
|
19009
19077
|
const resultMsg = publishResult.data?.baseResp?.errmsg ?? publishResult.errMsg;
|
|
19010
19078
|
if (0 === resultCode) {
|
|
19011
19079
|
task.logger.info("[shipinhaoPublish] 发布成功");
|
|
19012
|
-
const publishId = uploadedImages[0]?.thumbUrl
|
|
19080
|
+
const publishId = extractEncFileKey(uploadedImages[0]?.thumbUrl);
|
|
19013
19081
|
await updateTaskState?.({
|
|
19014
19082
|
state: share_namespaceObject.TaskState.SUCCESS,
|
|
19015
19083
|
result: {
|
|
@@ -19801,13 +19869,110 @@ var __webpack_exports__ = {};
|
|
|
19801
19869
|
pictureFileType
|
|
19802
19870
|
};
|
|
19803
19871
|
}
|
|
19872
|
+
const MENTION_TEXT_SUFFIX = "\u0020";
|
|
19873
|
+
const MENTION_XML_SUFFIX = "\u2005";
|
|
19874
|
+
function payload_buildDescription(params) {
|
|
19875
|
+
let description = params.description || "";
|
|
19876
|
+
for (const topic of params.topics || [])description += `#${topic}`;
|
|
19877
|
+
for (const user of params.mentionedUsers || [])description += `@${user.nickname}${MENTION_TEXT_SUFFIX}`;
|
|
19878
|
+
return description;
|
|
19879
|
+
}
|
|
19880
|
+
function buildMentionedUser(mentionedUsers) {
|
|
19881
|
+
return (mentionedUsers || []).map((user)=>({
|
|
19882
|
+
nickname: `${user.nickname}${MENTION_TEXT_SUFFIX}`
|
|
19883
|
+
}));
|
|
19884
|
+
}
|
|
19885
|
+
function payload_buildTopicXml(params) {
|
|
19886
|
+
const values = [];
|
|
19887
|
+
let atIndex = null;
|
|
19888
|
+
if (params.description) values.push(`<![CDATA[${params.description}]]>`);
|
|
19889
|
+
for (const topic of params.topics || [])values.push(`<topic><![CDATA[#${topic}#]]></topic>`);
|
|
19890
|
+
for (const user of params.mentionedUsers || []){
|
|
19891
|
+
if (null === atIndex) atIndex = values.length;
|
|
19892
|
+
values.push(`<![CDATA[@${user.nickname}${MENTION_XML_SUFFIX}]]>`);
|
|
19893
|
+
}
|
|
19894
|
+
let xml = "<finder>";
|
|
19895
|
+
xml += "<version>1</version>";
|
|
19896
|
+
xml += `<valuecount>${values.length}</valuecount>`;
|
|
19897
|
+
xml += `<style><at>${atIndex ?? ""}</at></style>`;
|
|
19898
|
+
values.forEach((value, index)=>{
|
|
19899
|
+
xml += `<value${index}>${value}</value${index}>`;
|
|
19900
|
+
});
|
|
19901
|
+
xml += "</finder>";
|
|
19902
|
+
return xml;
|
|
19903
|
+
}
|
|
19904
|
+
function payload_buildLocation(location) {
|
|
19905
|
+
if (!location) return {
|
|
19906
|
+
latitude: 0,
|
|
19907
|
+
longitude: 0,
|
|
19908
|
+
city: "",
|
|
19909
|
+
poiName: "",
|
|
19910
|
+
address: "",
|
|
19911
|
+
poiClassifyId: ""
|
|
19912
|
+
};
|
|
19913
|
+
return {
|
|
19914
|
+
latitude: location.latitude,
|
|
19915
|
+
longitude: location.longitude,
|
|
19916
|
+
city: location.city,
|
|
19917
|
+
poiName: location.poiName || "",
|
|
19918
|
+
address: location.address || "",
|
|
19919
|
+
poiClassifyId: location.poiClassifyId || ""
|
|
19920
|
+
};
|
|
19921
|
+
}
|
|
19922
|
+
function buildTopic(params) {
|
|
19923
|
+
const topic = {
|
|
19924
|
+
finderTopicInfo: payload_buildTopicXml(params)
|
|
19925
|
+
};
|
|
19926
|
+
if (params.collection) {
|
|
19927
|
+
topic.collectionId = params.collection.collectionId;
|
|
19928
|
+
topic.collectionName = params.collection.collectionName;
|
|
19929
|
+
}
|
|
19930
|
+
return topic;
|
|
19931
|
+
}
|
|
19932
|
+
function buildEvent(event) {
|
|
19933
|
+
if (!event) return {};
|
|
19934
|
+
return {
|
|
19935
|
+
eventTopicId: event.eventTopicId,
|
|
19936
|
+
eventName: event.eventName,
|
|
19937
|
+
eventCreatorNickname: event.eventCreatorNickname || ""
|
|
19938
|
+
};
|
|
19939
|
+
}
|
|
19940
|
+
function buildExtReading(link) {
|
|
19941
|
+
if (!link) return {
|
|
19942
|
+
link: "",
|
|
19943
|
+
title: "",
|
|
19944
|
+
urlType: 1
|
|
19945
|
+
};
|
|
19946
|
+
return {
|
|
19947
|
+
link: link.link.replace(/[\s\u200b]/g, ""),
|
|
19948
|
+
title: link.title,
|
|
19949
|
+
urlType: link.urlType ?? 1
|
|
19950
|
+
};
|
|
19951
|
+
}
|
|
19952
|
+
function buildTagInfo(tagInfo, tagKey) {
|
|
19953
|
+
return {
|
|
19954
|
+
...tagInfo,
|
|
19955
|
+
tagKey
|
|
19956
|
+
};
|
|
19957
|
+
}
|
|
19804
19958
|
const CHUNK_SIZE = 8388608;
|
|
19959
|
+
const UPLOAD_STAGE_TIMEOUT = 180000;
|
|
19960
|
+
const DEFAULT_TUNING = {
|
|
19961
|
+
metaTimeout: UPLOAD_STAGE_TIMEOUT,
|
|
19962
|
+
partTimeout: UPLOAD_STAGE_TIMEOUT,
|
|
19963
|
+
partRetries: 3,
|
|
19964
|
+
completeTimeout: UPLOAD_STAGE_TIMEOUT
|
|
19965
|
+
};
|
|
19805
19966
|
async function uploader_uploadFile(opts) {
|
|
19806
|
-
const { filePath, fileType, uin, authKey, http, logger } = opts;
|
|
19967
|
+
const { filePath, fileType, uin, authKey, http, logger, tuning } = opts;
|
|
19807
19968
|
const stat = external_node_fs_default().statSync(filePath);
|
|
19808
19969
|
const fileSize = stat.size;
|
|
19809
19970
|
const fileName = filePath.split(/[\\/]/).pop() || "file";
|
|
19810
|
-
|
|
19971
|
+
const metaTimeout = tuning?.metaTimeout ?? DEFAULT_TUNING.metaTimeout;
|
|
19972
|
+
const partTimeout = tuning?.partTimeout ?? DEFAULT_TUNING.partTimeout;
|
|
19973
|
+
const partRetries = tuning?.partRetries ?? DEFAULT_TUNING.partRetries;
|
|
19974
|
+
const completeTimeout = tuning?.completeTimeout ?? DEFAULT_TUNING.completeTimeout;
|
|
19975
|
+
logger?.info(`[shipinhaoPublishVideo] 开始上传: ${fileName} (${fileSize} B, filetype=${fileType})`);
|
|
19811
19976
|
const fileMd5 = await computeFileMd5(filePath);
|
|
19812
19977
|
const taskId = generateTaskId(fileName, fileSize, fileMd5);
|
|
19813
19978
|
const baseUrl = "https://finderassistancea.video.qq.com";
|
|
@@ -19818,7 +19983,7 @@ var __webpack_exports__ = {};
|
|
|
19818
19983
|
const chunkCount = Math.ceil(fileSize / CHUNK_SIZE);
|
|
19819
19984
|
const blockPartLength = [];
|
|
19820
19985
|
for(let i = 0; i < chunkCount; i++)blockPartLength.push(Math.min((i + 1) * CHUNK_SIZE, fileSize));
|
|
19821
|
-
logger?.info(
|
|
19986
|
+
logger?.info(`[shipinhaoPublishVideo] 视频分片: ${chunkCount} 片`);
|
|
19822
19987
|
const applyRes = await http.api({
|
|
19823
19988
|
method: "PUT",
|
|
19824
19989
|
url: `${baseUrl}/applyuploaddfs`,
|
|
@@ -19830,12 +19995,15 @@ var __webpack_exports__ = {};
|
|
|
19830
19995
|
BlockSum: chunkCount,
|
|
19831
19996
|
BlockPartLength: blockPartLength
|
|
19832
19997
|
}
|
|
19998
|
+
}, {
|
|
19999
|
+
timeout: metaTimeout,
|
|
20000
|
+
retries: 2,
|
|
20001
|
+
retryDelay: 2000
|
|
19833
20002
|
});
|
|
19834
20003
|
if (!applyRes.UploadID && !applyRes.ListPartsResult) throw new Error("申请 UploadID 失败: " + JSON.stringify(applyRes));
|
|
19835
20004
|
let uploadId = applyRes.UploadID;
|
|
19836
20005
|
const uploadedParts = new Set();
|
|
19837
20006
|
if (applyRes.ListPartsResult) {
|
|
19838
|
-
logger?.info("检测到已上传分片,执行续传");
|
|
19839
20007
|
const parts = Array.isArray(applyRes.ListPartsResult.Part) ? applyRes.ListPartsResult.Part : applyRes.ListPartsResult.Part ? [
|
|
19840
20008
|
applyRes.ListPartsResult.Part
|
|
19841
20009
|
] : [];
|
|
@@ -19851,6 +20019,10 @@ var __webpack_exports__ = {};
|
|
|
19851
20019
|
BlockSum: chunkCount,
|
|
19852
20020
|
BlockPartLength: blockPartLength
|
|
19853
20021
|
}
|
|
20022
|
+
}, {
|
|
20023
|
+
timeout: metaTimeout,
|
|
20024
|
+
retries: 2,
|
|
20025
|
+
retryDelay: 2000
|
|
19854
20026
|
});
|
|
19855
20027
|
uploadId = retryRes.UploadID;
|
|
19856
20028
|
if (!uploadId) throw new Error("续传获取 UploadID 失败");
|
|
@@ -19867,7 +20039,6 @@ var __webpack_exports__ = {};
|
|
|
19867
20039
|
PartNumber: partNumber,
|
|
19868
20040
|
ETag: existing.ETag
|
|
19869
20041
|
});
|
|
19870
|
-
logger?.info(`分片 ${partNumber}/${chunkCount} 已存在,跳过`);
|
|
19871
20042
|
continue;
|
|
19872
20043
|
}
|
|
19873
20044
|
}
|
|
@@ -19877,6 +20048,7 @@ var __webpack_exports__ = {};
|
|
|
19877
20048
|
const chunk = Buffer.alloc(chunkSize);
|
|
19878
20049
|
external_node_fs_default().readSync(fd, chunk, 0, chunkSize, start);
|
|
19879
20050
|
const chunkMd5 = external_node_crypto_default().createHash("md5").update(chunk).digest("hex");
|
|
20051
|
+
const partStart = Date.now();
|
|
19880
20052
|
await http.api({
|
|
19881
20053
|
method: "PUT",
|
|
19882
20054
|
url: `${baseUrl}/uploadpartdfs?PartNumber=${partNumber}&UploadID=${encodeURIComponent(uploadId)}`,
|
|
@@ -19886,17 +20058,20 @@ var __webpack_exports__ = {};
|
|
|
19886
20058
|
"Content-MD5": chunkMd5
|
|
19887
20059
|
},
|
|
19888
20060
|
data: chunk
|
|
20061
|
+
}, {
|
|
20062
|
+
timeout: partTimeout,
|
|
20063
|
+
retries: partRetries,
|
|
20064
|
+
retryDelay: 2000
|
|
19889
20065
|
});
|
|
20066
|
+
Date.now();
|
|
19890
20067
|
partInfo.push({
|
|
19891
20068
|
PartNumber: partNumber,
|
|
19892
20069
|
ETag: `"${chunkMd5}"`
|
|
19893
20070
|
});
|
|
19894
|
-
logger?.info(`分片 ${partNumber}/${chunkCount} 完成 (${chunkSize} B)`);
|
|
19895
20071
|
}
|
|
19896
20072
|
} finally{
|
|
19897
20073
|
external_node_fs_default().closeSync(fd);
|
|
19898
20074
|
}
|
|
19899
|
-
logger?.info("合并分片...");
|
|
19900
20075
|
const completeRes = await http.api({
|
|
19901
20076
|
method: "POST",
|
|
19902
20077
|
url: `${baseUrl}/completepartuploaddfs?UploadID=${encodeURIComponent(uploadId)}`,
|
|
@@ -19908,9 +20083,13 @@ var __webpack_exports__ = {};
|
|
|
19908
20083
|
TransFlag: "0_0",
|
|
19909
20084
|
PartInfo: partInfo
|
|
19910
20085
|
}
|
|
20086
|
+
}, {
|
|
20087
|
+
timeout: completeTimeout,
|
|
20088
|
+
retries: 1,
|
|
20089
|
+
retryDelay: 3000
|
|
19911
20090
|
});
|
|
19912
20091
|
if (!completeRes.DownloadURL) throw new Error("合并分片失败: " + JSON.stringify(completeRes));
|
|
19913
|
-
logger?.info(
|
|
20092
|
+
logger?.info(`[shipinhaoPublishVideo] ${fileName} 上传成功`);
|
|
19914
20093
|
return {
|
|
19915
20094
|
downloadUrl: completeRes.DownloadURL,
|
|
19916
20095
|
md5: fileMd5,
|
|
@@ -19930,85 +20109,233 @@ var __webpack_exports__ = {};
|
|
|
19930
20109
|
const input = `${fileName}-${fileSize}-${fileMd5}`;
|
|
19931
20110
|
return external_node_crypto_default().createHash("md5").update(input).digest("hex").slice(0, 32);
|
|
19932
20111
|
}
|
|
20112
|
+
const MAX_METADATA_BOX_SIZE = 268435456;
|
|
20113
|
+
function readBoxHeader(fd, offset, limit) {
|
|
20114
|
+
if (offset + 8 > limit) return null;
|
|
20115
|
+
const head = Buffer.alloc(16);
|
|
20116
|
+
const read = external_node_fs_default().readSync(fd, head, 0, 16, offset);
|
|
20117
|
+
if (read < 8) return null;
|
|
20118
|
+
let size = head.readUInt32BE(0);
|
|
20119
|
+
const type = head.toString("latin1", 4, 8);
|
|
20120
|
+
let headerSize = 8;
|
|
20121
|
+
if (1 === size) {
|
|
20122
|
+
if (read < 16) return null;
|
|
20123
|
+
size = head.readUInt32BE(8) * 2 ** 32 + head.readUInt32BE(12);
|
|
20124
|
+
headerSize = 16;
|
|
20125
|
+
} else if (0 === size) size = limit - offset;
|
|
20126
|
+
if (size < headerSize || offset + size > limit) return null;
|
|
20127
|
+
return {
|
|
20128
|
+
type,
|
|
20129
|
+
size,
|
|
20130
|
+
headerSize
|
|
20131
|
+
};
|
|
20132
|
+
}
|
|
19933
20133
|
function parseVideoMeta(filePath) {
|
|
19934
|
-
let
|
|
20134
|
+
let fd;
|
|
20135
|
+
let fileSize;
|
|
20136
|
+
try {
|
|
20137
|
+
fd = external_node_fs_default().openSync(filePath, "r");
|
|
20138
|
+
} catch {
|
|
20139
|
+
return null;
|
|
20140
|
+
}
|
|
19935
20141
|
try {
|
|
19936
|
-
|
|
20142
|
+
fileSize = external_node_fs_default().fstatSync(fd).size;
|
|
20143
|
+
const state = {
|
|
20144
|
+
movie: null,
|
|
20145
|
+
tracks: [],
|
|
20146
|
+
trexDefaults: new Map(),
|
|
20147
|
+
fragmentDurations: new Map(),
|
|
20148
|
+
trafTrackId: 0,
|
|
20149
|
+
trafDefaultSampleDuration: 0
|
|
20150
|
+
};
|
|
20151
|
+
let offset = 0;
|
|
20152
|
+
while(offset + 8 <= fileSize){
|
|
20153
|
+
const header = readBoxHeader(fd, offset, fileSize);
|
|
20154
|
+
if (!header) break;
|
|
20155
|
+
if ("moov" === header.type || "moof" === header.type) {
|
|
20156
|
+
const bodyLength = header.size - header.headerSize;
|
|
20157
|
+
if (bodyLength > 0 && bodyLength <= MAX_METADATA_BOX_SIZE) {
|
|
20158
|
+
const body = Buffer.alloc(bodyLength);
|
|
20159
|
+
const read = external_node_fs_default().readSync(fd, body, 0, bodyLength, offset + header.headerSize);
|
|
20160
|
+
state.trafTrackId = 0;
|
|
20161
|
+
state.trafDefaultSampleDuration = 0;
|
|
20162
|
+
walkBoxes(body.subarray(0, read), 0, read, state);
|
|
20163
|
+
}
|
|
20164
|
+
}
|
|
20165
|
+
offset += header.size;
|
|
20166
|
+
}
|
|
20167
|
+
const { movie, tracks } = state;
|
|
20168
|
+
const video = tracks.find((t)=>"vide" === t.handler) || tracks.find((t)=>t.width > 0 && t.height > 0);
|
|
20169
|
+
if (!video) return null;
|
|
20170
|
+
let { width, height } = video;
|
|
20171
|
+
if (90 === video.rotation || 270 === video.rotation) [width, height] = [
|
|
20172
|
+
height,
|
|
20173
|
+
width
|
|
20174
|
+
];
|
|
20175
|
+
return {
|
|
20176
|
+
width: Math.round(width),
|
|
20177
|
+
height: Math.round(height),
|
|
20178
|
+
duration: resolveDuration(movie, video, state.fragmentDurations),
|
|
20179
|
+
rotation: video.rotation,
|
|
20180
|
+
fileSize,
|
|
20181
|
+
codec: video.codec
|
|
20182
|
+
};
|
|
19937
20183
|
} catch {
|
|
19938
20184
|
return null;
|
|
20185
|
+
} finally{
|
|
20186
|
+
try {
|
|
20187
|
+
external_node_fs_default().closeSync(fd);
|
|
20188
|
+
} catch {}
|
|
19939
20189
|
}
|
|
19940
|
-
|
|
19941
|
-
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
if (
|
|
19949
|
-
|
|
19950
|
-
|
|
19951
|
-
|
|
19952
|
-
|
|
19953
|
-
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
20190
|
+
}
|
|
20191
|
+
function walkBoxes(buf, start, end, state) {
|
|
20192
|
+
let off = start;
|
|
20193
|
+
while(off + 8 <= end){
|
|
20194
|
+
let size = buf.readUInt32BE(off);
|
|
20195
|
+
const type = buf.toString("latin1", off + 4, off + 8);
|
|
20196
|
+
let headerSize = 8;
|
|
20197
|
+
if (1 === size) {
|
|
20198
|
+
if (off + 16 > end) break;
|
|
20199
|
+
const hi = buf.readUInt32BE(off + 8);
|
|
20200
|
+
const lo = buf.readUInt32BE(off + 12);
|
|
20201
|
+
size = hi * 2 ** 32 + lo;
|
|
20202
|
+
headerSize = 16;
|
|
20203
|
+
} else if (0 === size) size = end - off;
|
|
20204
|
+
if (size < headerSize || off + size > end) break;
|
|
20205
|
+
const bodyStart = off + headerSize;
|
|
20206
|
+
const bodyEnd = off + size;
|
|
20207
|
+
switch(type){
|
|
20208
|
+
case "trak":
|
|
20209
|
+
case "mdia":
|
|
20210
|
+
case "minf":
|
|
20211
|
+
case "stbl":
|
|
20212
|
+
case "mvex":
|
|
20213
|
+
case "traf":
|
|
20214
|
+
walkBoxes(buf, bodyStart, bodyEnd, state);
|
|
20215
|
+
break;
|
|
20216
|
+
case "mvhd":
|
|
20217
|
+
state.movie = parseMvhd(buf, bodyStart, bodyEnd);
|
|
20218
|
+
break;
|
|
20219
|
+
case "tkhd":
|
|
20220
|
+
state.tracks.push({
|
|
20221
|
+
...parseTkhd(buf, bodyStart, bodyEnd),
|
|
20222
|
+
handler: null,
|
|
20223
|
+
codec: null,
|
|
20224
|
+
timescale: 0,
|
|
20225
|
+
mdhdDuration: 0,
|
|
20226
|
+
sttsDuration: 0
|
|
20227
|
+
});
|
|
20228
|
+
break;
|
|
20229
|
+
case "mdhd":
|
|
20230
|
+
{
|
|
20231
|
+
const mdhd = parseMvhd(buf, bodyStart, bodyEnd);
|
|
20232
|
+
if (mdhd && state.tracks.length) {
|
|
20233
|
+
const track = state.tracks[state.tracks.length - 1];
|
|
20234
|
+
track.timescale = mdhd.timescale;
|
|
20235
|
+
track.mdhdDuration = mdhd.duration;
|
|
20236
|
+
}
|
|
19965
20237
|
break;
|
|
19966
|
-
|
|
19967
|
-
|
|
20238
|
+
}
|
|
20239
|
+
case "hdlr":
|
|
20240
|
+
if (bodyEnd - bodyStart >= 12 && state.tracks.length) state.tracks[state.tracks.length - 1].handler = buf.toString("latin1", bodyStart + 8, bodyStart + 12);
|
|
20241
|
+
break;
|
|
20242
|
+
case "stsd":
|
|
20243
|
+
{
|
|
20244
|
+
const codec = parseStsdCodec(buf, bodyStart, bodyEnd);
|
|
20245
|
+
if (codec && state.tracks.length) state.tracks[state.tracks.length - 1].codec = codec;
|
|
19968
20246
|
break;
|
|
19969
|
-
|
|
19970
|
-
|
|
19971
|
-
|
|
19972
|
-
|
|
19973
|
-
|
|
19974
|
-
|
|
20247
|
+
}
|
|
20248
|
+
case "stts":
|
|
20249
|
+
if (state.tracks.length) state.tracks[state.tracks.length - 1].sttsDuration = parseSttsDuration(buf, bodyStart, bodyEnd);
|
|
20250
|
+
break;
|
|
20251
|
+
case "trex":
|
|
20252
|
+
if (bodyStart + 20 > bodyEnd) break;
|
|
20253
|
+
state.trexDefaults.set(buf.readUInt32BE(bodyStart + 4), buf.readUInt32BE(bodyStart + 12));
|
|
20254
|
+
break;
|
|
20255
|
+
case "tfhd":
|
|
20256
|
+
{
|
|
20257
|
+
const tfhd = parseTfhd(buf, bodyStart, bodyEnd);
|
|
20258
|
+
state.trafTrackId = tfhd.trackId;
|
|
20259
|
+
state.trafDefaultSampleDuration = tfhd.defaultSampleDuration || state.trexDefaults.get(tfhd.trackId) || 0;
|
|
19975
20260
|
break;
|
|
19976
|
-
|
|
19977
|
-
|
|
19978
|
-
|
|
19979
|
-
|
|
19980
|
-
|
|
20261
|
+
}
|
|
20262
|
+
case "trun":
|
|
20263
|
+
{
|
|
20264
|
+
const duration = parseTrunDuration(buf, bodyStart, bodyEnd, state.trafDefaultSampleDuration);
|
|
20265
|
+
state.fragmentDurations.set(state.trafTrackId, (state.fragmentDurations.get(state.trafTrackId) || 0) + duration);
|
|
19981
20266
|
break;
|
|
19982
|
-
|
|
19983
|
-
{
|
|
19984
|
-
const codec = parseStsdCodec(buf, bodyStart, bodyEnd);
|
|
19985
|
-
if (codec && tracks.length) tracks[tracks.length - 1].codec = codec;
|
|
19986
|
-
break;
|
|
19987
|
-
}
|
|
19988
|
-
}
|
|
19989
|
-
off += size;
|
|
20267
|
+
}
|
|
19990
20268
|
}
|
|
20269
|
+
off += size;
|
|
19991
20270
|
}
|
|
19992
|
-
|
|
19993
|
-
|
|
19994
|
-
|
|
19995
|
-
|
|
19996
|
-
|
|
19997
|
-
|
|
19998
|
-
|
|
19999
|
-
|
|
20000
|
-
|
|
20271
|
+
}
|
|
20272
|
+
const UNKNOWN_DURATION_32 = 0xffffffff;
|
|
20273
|
+
function isUsableDuration(duration) {
|
|
20274
|
+
return duration > 0 && duration !== UNKNOWN_DURATION_32;
|
|
20275
|
+
}
|
|
20276
|
+
function resolveDuration(movie, video, fragmentDurations) {
|
|
20277
|
+
if (movie && movie.timescale && isUsableDuration(movie.duration)) return movie.duration / movie.timescale;
|
|
20278
|
+
if (video.timescale) {
|
|
20279
|
+
if (isUsableDuration(video.mdhdDuration)) return video.mdhdDuration / video.timescale;
|
|
20280
|
+
if (video.sttsDuration > 0) return video.sttsDuration / video.timescale;
|
|
20281
|
+
const fragment = fragmentDurations.get(video.trackId) ?? (1 === fragmentDurations.size ? [
|
|
20282
|
+
...fragmentDurations.values()
|
|
20283
|
+
][0] : 0);
|
|
20284
|
+
if (fragment > 0) return fragment / video.timescale;
|
|
20285
|
+
}
|
|
20286
|
+
return 0;
|
|
20287
|
+
}
|
|
20288
|
+
function parseSttsDuration(buf, start, end) {
|
|
20289
|
+
if (start + 8 > end) return 0;
|
|
20290
|
+
const entryCount = buf.readUInt32BE(start + 4);
|
|
20291
|
+
let total = 0;
|
|
20292
|
+
for(let i = 0; i < entryCount; i++){
|
|
20293
|
+
const off = start + 8 + 8 * i;
|
|
20294
|
+
if (off + 8 > end) break;
|
|
20295
|
+
total += buf.readUInt32BE(off) * buf.readUInt32BE(off + 4);
|
|
20296
|
+
}
|
|
20297
|
+
return total;
|
|
20298
|
+
}
|
|
20299
|
+
function parseTfhd(buf, start, end) {
|
|
20300
|
+
if (start + 8 > end) return {
|
|
20301
|
+
trackId: 0,
|
|
20302
|
+
defaultSampleDuration: 0
|
|
20303
|
+
};
|
|
20304
|
+
const flags = buf.readUIntBE(start + 1, 3);
|
|
20305
|
+
const trackId = buf.readUInt32BE(start + 4);
|
|
20306
|
+
let off = start + 8;
|
|
20307
|
+
if (0x000001 & flags) off += 8;
|
|
20308
|
+
if (0x000002 & flags) off += 4;
|
|
20309
|
+
if (0x000008 & flags && off + 4 <= end) return {
|
|
20310
|
+
trackId,
|
|
20311
|
+
defaultSampleDuration: buf.readUInt32BE(off)
|
|
20312
|
+
};
|
|
20001
20313
|
return {
|
|
20002
|
-
|
|
20003
|
-
|
|
20004
|
-
duration: movieData.timescale ? movieData.duration / movieData.timescale : 0,
|
|
20005
|
-
rotation: video.rotation,
|
|
20006
|
-
fileSize: buf.length,
|
|
20007
|
-
codec: video.codec
|
|
20314
|
+
trackId,
|
|
20315
|
+
defaultSampleDuration: 0
|
|
20008
20316
|
};
|
|
20009
20317
|
}
|
|
20318
|
+
function parseTrunDuration(buf, start, end, defaultSampleDuration) {
|
|
20319
|
+
if (start + 8 > end) return 0;
|
|
20320
|
+
const flags = buf.readUIntBE(start + 1, 3);
|
|
20321
|
+
const sampleCount = buf.readUInt32BE(start + 4);
|
|
20322
|
+
let off = start + 8;
|
|
20323
|
+
if (0x000001 & flags) off += 4;
|
|
20324
|
+
if (0x000004 & flags) off += 4;
|
|
20325
|
+
const hasDuration = (0x000100 & flags) !== 0;
|
|
20326
|
+
if (!hasDuration) return sampleCount * defaultSampleDuration;
|
|
20327
|
+
const entrySize = 4 + ((0x000200 & flags) !== 0 ? 4 : 0) + ((0x000400 & flags) !== 0 ? 4 : 0) + ((0x000800 & flags) !== 0 ? 4 : 0);
|
|
20328
|
+
let total = 0;
|
|
20329
|
+
for(let i = 0; i < sampleCount; i++){
|
|
20330
|
+
const entryOff = off + i * entrySize;
|
|
20331
|
+
if (entryOff + 4 > end) break;
|
|
20332
|
+
total += buf.readUInt32BE(entryOff);
|
|
20333
|
+
}
|
|
20334
|
+
return total;
|
|
20335
|
+
}
|
|
20010
20336
|
function parseStsdCodec(buf, start, end) {
|
|
20011
20337
|
if (start + 16 > end) return null;
|
|
20338
|
+
if (0 === buf.readUInt32BE(start + 4)) return null;
|
|
20012
20339
|
return buf.toString("latin1", start + 12, start + 16).toLowerCase();
|
|
20013
20340
|
}
|
|
20014
20341
|
function parseMvhd(buf, start, end) {
|
|
@@ -20034,7 +20361,10 @@ var __webpack_exports__ = {};
|
|
|
20034
20361
|
const afterDuration = 1 === version ? 36 : 24;
|
|
20035
20362
|
const matrixOff = start + afterDuration + 16;
|
|
20036
20363
|
const whOff = matrixOff + 36;
|
|
20364
|
+
const trackIdOff = start + (1 === version ? 20 : 12);
|
|
20365
|
+
const trackId = trackIdOff + 4 <= end ? buf.readUInt32BE(trackIdOff) : 0;
|
|
20037
20366
|
if (whOff + 8 > end) return {
|
|
20367
|
+
trackId,
|
|
20038
20368
|
width: 0,
|
|
20039
20369
|
height: 0,
|
|
20040
20370
|
rotation: 0
|
|
@@ -20048,11 +20378,25 @@ var __webpack_exports__ = {};
|
|
|
20048
20378
|
else if (Math.abs(a + 1) < 0.01 && Math.abs(b) < 0.01) rotation = 180;
|
|
20049
20379
|
else if (Math.abs(a) < 0.01 && Math.abs(b + 1) < 0.01) rotation = 270;
|
|
20050
20380
|
return {
|
|
20381
|
+
trackId,
|
|
20051
20382
|
width,
|
|
20052
20383
|
height,
|
|
20053
20384
|
rotation
|
|
20054
20385
|
};
|
|
20055
20386
|
}
|
|
20387
|
+
function parseVideoCodec(filePath) {
|
|
20388
|
+
return parseVideoMeta(filePath)?.codec ?? null;
|
|
20389
|
+
}
|
|
20390
|
+
function buildVideoMetaFromParams(filePath, metadata) {
|
|
20391
|
+
return {
|
|
20392
|
+
width: Math.round(metadata.width),
|
|
20393
|
+
height: Math.round(metadata.height),
|
|
20394
|
+
duration: metadata.duration,
|
|
20395
|
+
rotation: 0,
|
|
20396
|
+
fileSize: metadata.fileSize,
|
|
20397
|
+
codec: parseVideoCodec(filePath)
|
|
20398
|
+
};
|
|
20399
|
+
}
|
|
20056
20400
|
const MAX_DURATION_SECONDS = 28800;
|
|
20057
20401
|
const MAX_FILE_SIZE = 21474836480;
|
|
20058
20402
|
const ALLOWED_EXTENSIONS = [
|
|
@@ -20063,6 +20407,7 @@ var __webpack_exports__ = {};
|
|
|
20063
20407
|
"avc3"
|
|
20064
20408
|
];
|
|
20065
20409
|
const MIN_TITLE_LENGTH = 6;
|
|
20410
|
+
const MAX_TITLE_LENGTH = 16;
|
|
20066
20411
|
function formatFileSize(bytes) {
|
|
20067
20412
|
if (bytes < 1048576) return `${(bytes / 1024).toFixed(2)} KB`;
|
|
20068
20413
|
if (bytes < 1073741824) return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
|
|
@@ -20089,26 +20434,62 @@ var __webpack_exports__ = {};
|
|
|
20089
20434
|
function validateShipinhaoTitle(title) {
|
|
20090
20435
|
if (void 0 === title) return null;
|
|
20091
20436
|
const trimmed = title.trim();
|
|
20437
|
+
if ("" === trimmed) return null;
|
|
20092
20438
|
const length = [
|
|
20093
20439
|
...trimmed
|
|
20094
20440
|
].length;
|
|
20095
|
-
if (length < MIN_TITLE_LENGTH) return
|
|
20441
|
+
if (length < MIN_TITLE_LENGTH || length > MAX_TITLE_LENGTH) return `视频号标题需要在 ${MIN_TITLE_LENGTH}-${MAX_TITLE_LENGTH} 个字符之间,当前 ${length} 个字符,请调整后重试。`;
|
|
20096
20442
|
return null;
|
|
20097
20443
|
}
|
|
20098
|
-
|
|
20099
|
-
|
|
20444
|
+
const POST_CREATE_PAGE_URL = "https://channels.weixin.qq.com/micro/content/post/create";
|
|
20445
|
+
const MICRO_CONTENT_BASE = "https://channels.weixin.qq.com/micro/content/cgi-bin/mmfinderassistant-bin";
|
|
20446
|
+
function resolveClientContext(params, fallbackUin) {
|
|
20447
|
+
const extra = params.extraParam || {};
|
|
20448
|
+
const deviceIdCookie = params.cookies.find((c)=>"device_id" === c.name || "finger_print_device_id" === c.name)?.value;
|
|
20449
|
+
return {
|
|
20450
|
+
aId: "string" == typeof extra.aId ? extra.aId : "",
|
|
20451
|
+
fingerPrintDeviceId: "string" == typeof extra.fingerPrintDeviceId ? extra.fingerPrintDeviceId : deviceIdCookie || "",
|
|
20452
|
+
uin: "string" == typeof extra.uin ? extra.uin : String(fallbackUin)
|
|
20453
|
+
};
|
|
20454
|
+
}
|
|
20455
|
+
function buildPublishHeaders(cookieString, client) {
|
|
20456
|
+
const headers = {
|
|
20457
|
+
cookie: cookieString,
|
|
20458
|
+
referer: POST_CREATE_PAGE_URL,
|
|
20459
|
+
origin: "https://channels.weixin.qq.com",
|
|
20460
|
+
"content-type": "application/json"
|
|
20461
|
+
};
|
|
20462
|
+
if (client.fingerPrintDeviceId) headers["finger-print-device-id"] = client.fingerPrintDeviceId;
|
|
20463
|
+
if (client.uin) headers["x-wechat-uin"] = client.uin;
|
|
20464
|
+
return headers;
|
|
20465
|
+
}
|
|
20466
|
+
function buildPublishQuery(client) {
|
|
20467
|
+
const query = {
|
|
20468
|
+
_rid: rid(),
|
|
20469
|
+
_pageUrl: POST_CREATE_PAGE_URL
|
|
20470
|
+
};
|
|
20471
|
+
if (client.aId) query._aid = client.aId;
|
|
20472
|
+
return query;
|
|
20473
|
+
}
|
|
20474
|
+
function buildCommonBody(finderUsername) {
|
|
20475
|
+
return {
|
|
20476
|
+
timestamp: String(Date.now()),
|
|
20477
|
+
_log_finder_uin: "",
|
|
20478
|
+
_log_finder_id: finderUsername,
|
|
20479
|
+
rawKeyBuff: "",
|
|
20480
|
+
pluginSessionId: null,
|
|
20481
|
+
scene: 7,
|
|
20482
|
+
reqScene: 7
|
|
20483
|
+
};
|
|
20484
|
+
}
|
|
20485
|
+
async function getTraceKey(auth, client, http, logger) {
|
|
20100
20486
|
const res = await http.api({
|
|
20101
20487
|
method: "POST",
|
|
20102
|
-
url:
|
|
20488
|
+
url: `${MICRO_CONTENT_BASE}/post/get-finder-post-trace-key`,
|
|
20489
|
+
params: buildPublishQuery(client),
|
|
20103
20490
|
data: {
|
|
20104
20491
|
objectId: "",
|
|
20105
|
-
|
|
20106
|
-
_log_finder_uin: "",
|
|
20107
|
-
_log_finder_id: auth.finderUsername,
|
|
20108
|
-
rawKeyBuff: "",
|
|
20109
|
-
pluginSessionId: null,
|
|
20110
|
-
scene: 7,
|
|
20111
|
-
reqScene: 7
|
|
20492
|
+
...buildCommonBody(auth.finderUsername)
|
|
20112
20493
|
},
|
|
20113
20494
|
defaultErrorMsg: "获取 traceKey 失败"
|
|
20114
20495
|
});
|
|
@@ -20116,18 +20497,38 @@ var __webpack_exports__ = {};
|
|
|
20116
20497
|
logger.error("[getTraceKey] 获取失败:", JSON.stringify(res));
|
|
20117
20498
|
throw new Error(`获取 traceKey 失败: ${JSON.stringify(res)}`);
|
|
20118
20499
|
}
|
|
20119
|
-
logger.info(`[getTraceKey] 获取成功: ${res.data.traceKey}`);
|
|
20120
20500
|
return res.data.traceKey;
|
|
20121
20501
|
}
|
|
20502
|
+
async function getObjectTagKey(auth, client, http, logger) {
|
|
20503
|
+
try {
|
|
20504
|
+
const res = await http.api({
|
|
20505
|
+
method: "POST",
|
|
20506
|
+
url: `${MICRO_CONTENT_BASE}/post/finder_get_object_tag_list`,
|
|
20507
|
+
params: buildPublishQuery(client),
|
|
20508
|
+
data: {
|
|
20509
|
+
source: 1,
|
|
20510
|
+
...buildCommonBody(auth.finderUsername)
|
|
20511
|
+
},
|
|
20512
|
+
defaultErrorMsg: "获取内容声明标注失败"
|
|
20513
|
+
});
|
|
20514
|
+
if (0 !== res.errCode || !res.data?.tagKey) {
|
|
20515
|
+
logger.warn(`[getObjectTagKey] 未取到 tagKey: ${JSON.stringify(res)}`);
|
|
20516
|
+
return null;
|
|
20517
|
+
}
|
|
20518
|
+
return res.data.tagKey;
|
|
20519
|
+
} catch (error) {
|
|
20520
|
+
logger.warn(`[getObjectTagKey] 获取 tagKey 异常: ${stringifyError(error)}`);
|
|
20521
|
+
return null;
|
|
20522
|
+
}
|
|
20523
|
+
}
|
|
20122
20524
|
async function submitAndPollTranscode(opts) {
|
|
20123
|
-
const { videoUrl, videoMeta, traceKey, uploadStartTime, uploadEndTime, finderUsername, http, logger } = opts;
|
|
20124
|
-
logger.info("[submitAndPollTranscode] 开始提交转码任务...");
|
|
20525
|
+
const { videoUrl, videoMeta, traceKey, uploadStartTime, uploadEndTime, finderUsername, client, http, logger } = opts;
|
|
20125
20526
|
const finderUrl = videoUrl.includes("wxapp.tc.qq.com") ? `https://finder.video.qq.com${videoUrl.split("qq.com")[1]}` : videoUrl;
|
|
20126
|
-
logger.info(`[submitAndPollTranscode] 视频URL: ${finderUrl}`);
|
|
20127
20527
|
logger.info(`[submitAndPollTranscode] 视频尺寸: ${videoMeta.width}x${videoMeta.height}, 时长: ${videoMeta.duration}s`);
|
|
20128
20528
|
const submitRes = await http.api({
|
|
20129
20529
|
method: "POST",
|
|
20130
|
-
url:
|
|
20530
|
+
url: `${MICRO_CONTENT_BASE}/post/post_clip_video`,
|
|
20531
|
+
params: buildPublishQuery(client),
|
|
20131
20532
|
data: {
|
|
20132
20533
|
url: finderUrl,
|
|
20133
20534
|
timeStart: 0,
|
|
@@ -20151,13 +20552,7 @@ var __webpack_exports__ = {};
|
|
|
20151
20552
|
targetHeight: videoMeta.height,
|
|
20152
20553
|
type: 4,
|
|
20153
20554
|
useAstraThumbCover: 1,
|
|
20154
|
-
|
|
20155
|
-
_log_finder_uin: "",
|
|
20156
|
-
_log_finder_id: finderUsername,
|
|
20157
|
-
rawKeyBuff: "",
|
|
20158
|
-
pluginSessionId: null,
|
|
20159
|
-
scene: 7,
|
|
20160
|
-
reqScene: 7
|
|
20555
|
+
...buildCommonBody(finderUsername)
|
|
20161
20556
|
},
|
|
20162
20557
|
defaultErrorMsg: "提交转码失败"
|
|
20163
20558
|
});
|
|
@@ -20166,43 +20561,39 @@ var __webpack_exports__ = {};
|
|
|
20166
20561
|
throw new Error(`提交转码失败: ${JSON.stringify(submitRes)}`);
|
|
20167
20562
|
}
|
|
20168
20563
|
const { clipKey, draftId } = submitRes.data;
|
|
20169
|
-
logger.info(`[submitAndPollTranscode] 转码任务已提交,clipKey: ${clipKey}, draftId: ${draftId}`);
|
|
20170
|
-
const maxPolls = 60;
|
|
20171
20564
|
const pollInterval = 5000;
|
|
20565
|
+
const pollBudget = Math.min(1800000, 300000 + 1000 * Math.ceil(1.5 * videoMeta.duration));
|
|
20566
|
+
const maxPolls = Math.ceil(pollBudget / pollInterval);
|
|
20172
20567
|
let pollCount = 0;
|
|
20173
|
-
logger.info(`[submitAndPollTranscode] 开始轮询转码结果,最多 ${maxPolls} 次,间隔 ${pollInterval / 1000}s`);
|
|
20174
20568
|
while(pollCount < maxPolls){
|
|
20175
20569
|
await sleep(pollInterval);
|
|
20176
20570
|
pollCount++;
|
|
20177
20571
|
const pollRes = await http.api({
|
|
20178
20572
|
method: "POST",
|
|
20179
|
-
url:
|
|
20573
|
+
url: `${MICRO_CONTENT_BASE}/post/post_clip_video_result`,
|
|
20574
|
+
params: buildPublishQuery(client),
|
|
20180
20575
|
data: {
|
|
20181
20576
|
clipKey,
|
|
20182
20577
|
draftId,
|
|
20183
|
-
|
|
20184
|
-
_log_finder_uin: "",
|
|
20185
|
-
_log_finder_id: finderUsername,
|
|
20186
|
-
rawKeyBuff: "",
|
|
20187
|
-
pluginSessionId: null,
|
|
20188
|
-
scene: 7,
|
|
20189
|
-
reqScene: 7
|
|
20578
|
+
...buildCommonBody(finderUsername)
|
|
20190
20579
|
},
|
|
20191
20580
|
defaultErrorMsg: "转码轮询失败"
|
|
20581
|
+
}, {
|
|
20582
|
+
timeout: 60000,
|
|
20583
|
+
retries: 2,
|
|
20584
|
+
retryDelay: 3000
|
|
20192
20585
|
});
|
|
20193
20586
|
if (0 !== pollRes.errCode) {
|
|
20194
20587
|
logger.error(`[submitAndPollTranscode] 转码轮询失败 (poll ${pollCount}):`, JSON.stringify(pollRes));
|
|
20195
20588
|
throw new Error(`转码轮询失败 (poll ${pollCount}): ${JSON.stringify(pollRes)}`);
|
|
20196
20589
|
}
|
|
20197
20590
|
const { flag, url, width, height, duration, md5, fileSize } = pollRes.data || {};
|
|
20198
|
-
logger.info(`[submitAndPollTranscode] 轮询第 ${pollCount} 次,flag=${flag}`);
|
|
20199
20591
|
if (1 === flag) {
|
|
20200
20592
|
if (!url || !width || !height || !duration || !md5 || !fileSize) {
|
|
20201
20593
|
logger.error("[submitAndPollTranscode] 转码完成但返回数据不完整:", JSON.stringify(pollRes.data));
|
|
20202
20594
|
throw new Error(`转码完成但返回数据不完整: ${JSON.stringify(pollRes.data)}`);
|
|
20203
20595
|
}
|
|
20204
20596
|
logger.info(`[submitAndPollTranscode] 转码完成! 用时: ${pollCount * pollInterval / 1000}s`);
|
|
20205
|
-
logger.info(`[submitAndPollTranscode] 视频信息: ${width}x${height}, 时长: ${duration}s, 大小: ${fileSize}`);
|
|
20206
20597
|
return {
|
|
20207
20598
|
clipKey,
|
|
20208
20599
|
url,
|
|
@@ -20213,7 +20604,7 @@ var __webpack_exports__ = {};
|
|
|
20213
20604
|
fileSize
|
|
20214
20605
|
};
|
|
20215
20606
|
}
|
|
20216
|
-
if (2 === flag)
|
|
20607
|
+
if (2 === flag) ;
|
|
20217
20608
|
else {
|
|
20218
20609
|
logger.error(`[submitAndPollTranscode] 转码失败,未知 flag=${flag}:`, JSON.stringify(pollRes.data));
|
|
20219
20610
|
throw new Error(`转码失败,未知 flag=${flag}: ${JSON.stringify(pollRes.data)}`);
|
|
@@ -20223,162 +20614,151 @@ var __webpack_exports__ = {};
|
|
|
20223
20614
|
throw new Error(`转码超时 (${maxPolls * pollInterval / 1000}s)`);
|
|
20224
20615
|
}
|
|
20225
20616
|
async function publishVideo(opts) {
|
|
20226
|
-
const { params, auth, clipResult, videoUpload, coverUpload, traceKey, uploadStartTime, uploadEndTime, proxyHttp, logger } = opts;
|
|
20227
|
-
|
|
20228
|
-
const
|
|
20229
|
-
|
|
20617
|
+
const { params, auth, client, clipResult, videoUpload, coverUpload, verticalCoverUpload, videoMeta, traceKey, tagKey, uploadStartTime, uploadEndTime, proxyHttp, logger } = opts;
|
|
20618
|
+
const toFinderUrl = (url)=>url.includes("wxapp.tc.qq.com") ? `https://finder.video.qq.com${url.split("qq.com")[1]}` : url;
|
|
20619
|
+
const thumbFinderUrl = toFinderUrl(coverUpload.downloadUrl);
|
|
20620
|
+
const coverFinderUrl = toFinderUrl(verticalCoverUpload.downloadUrl);
|
|
20230
20621
|
const md5sumUuid = external_node_crypto_default().randomUUID();
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20245
|
-
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
20252
|
-
|
|
20253
|
-
|
|
20254
|
-
|
|
20255
|
-
objectDesc: {
|
|
20256
|
-
mpTitle: "",
|
|
20257
|
-
description: params.description,
|
|
20258
|
-
shortTitle: params.title || "",
|
|
20259
|
-
extReading: {},
|
|
20622
|
+
const description = params.description;
|
|
20623
|
+
const objectDesc = {
|
|
20624
|
+
mpTitle: "",
|
|
20625
|
+
description,
|
|
20626
|
+
extReading: buildExtReading(params.link),
|
|
20627
|
+
mediaType: 4,
|
|
20628
|
+
location: payload_buildLocation(params.location),
|
|
20629
|
+
topic: buildTopic({
|
|
20630
|
+
description: params.description,
|
|
20631
|
+
topics: params.topics,
|
|
20632
|
+
mentionedUsers: params.mentionedUsers,
|
|
20633
|
+
collection: params.collection
|
|
20634
|
+
}),
|
|
20635
|
+
event: buildEvent(params.event),
|
|
20636
|
+
mentionedUser: buildMentionedUser(params.mentionedUsers),
|
|
20637
|
+
media: [
|
|
20638
|
+
{
|
|
20639
|
+
url: clipResult.url,
|
|
20640
|
+
fileSize: clipResult.fileSize,
|
|
20641
|
+
thumbUrl: thumbFinderUrl,
|
|
20642
|
+
fullThumbUrl: thumbFinderUrl,
|
|
20643
|
+
coverUrl: coverFinderUrl,
|
|
20644
|
+
fullCoverUrl: coverFinderUrl,
|
|
20645
|
+
shareCoverUrl: coverFinderUrl,
|
|
20260
20646
|
mediaType: 4,
|
|
20261
|
-
|
|
20262
|
-
latitude: params.location.latitude,
|
|
20263
|
-
longitude: params.location.longitude,
|
|
20264
|
-
city: params.location.city,
|
|
20265
|
-
poiClassifyId: params.location.poiClassifyId || ""
|
|
20266
|
-
} : {
|
|
20267
|
-
latitude: 0,
|
|
20268
|
-
longitude: 0,
|
|
20269
|
-
city: "",
|
|
20270
|
-
poiClassifyId: ""
|
|
20271
|
-
},
|
|
20272
|
-
topic: {
|
|
20273
|
-
finderTopicInfo: `<finder><version>1</version><valuecount>1</valuecount><style><at></at></style><value0><![CDATA[${params.description}]]></value0></finder>`
|
|
20274
|
-
},
|
|
20275
|
-
event: {},
|
|
20276
|
-
mentionedUser: [],
|
|
20277
|
-
media: [
|
|
20278
|
-
{
|
|
20279
|
-
url: clipResult.url,
|
|
20280
|
-
fileSize: clipResult.fileSize,
|
|
20281
|
-
thumbUrl: coverFinderUrl,
|
|
20282
|
-
fullThumbUrl: coverFinderUrl,
|
|
20283
|
-
coverUrl: coverFinderUrl,
|
|
20284
|
-
fullCoverUrl: coverFinderUrl,
|
|
20285
|
-
shareCoverUrl: coverFinderUrl,
|
|
20286
|
-
mediaType: 4,
|
|
20287
|
-
videoPlayLen: Math.round(clipResult.duration),
|
|
20288
|
-
width: clipResult.width,
|
|
20289
|
-
height: clipResult.height,
|
|
20290
|
-
md5sum: md5sumUuid,
|
|
20291
|
-
cardShowStyle: 2,
|
|
20292
|
-
urlCdnTaskId: clipResult.clipKey
|
|
20293
|
-
}
|
|
20294
|
-
],
|
|
20295
|
-
member: {}
|
|
20296
|
-
},
|
|
20297
|
-
effectiveTime: params.scheduleTime || 0,
|
|
20298
|
-
report: {
|
|
20299
|
-
clipKey: clipResult.clipKey,
|
|
20300
|
-
draftId: clipResult.clipKey,
|
|
20301
|
-
timestamp: String(Date.now()),
|
|
20302
|
-
_log_finder_uin: "",
|
|
20303
|
-
_log_finder_id: auth.finderUsername,
|
|
20304
|
-
rawKeyBuff: "",
|
|
20305
|
-
pluginSessionId: null,
|
|
20306
|
-
scene: 7,
|
|
20307
|
-
reqScene: 7,
|
|
20308
|
-
height: clipResult.height,
|
|
20647
|
+
videoPlayLen: Math.round(clipResult.duration),
|
|
20309
20648
|
width: clipResult.width,
|
|
20310
|
-
|
|
20311
|
-
|
|
20312
|
-
|
|
20313
|
-
|
|
20314
|
-
|
|
20315
|
-
|
|
20316
|
-
|
|
20317
|
-
|
|
20318
|
-
|
|
20319
|
-
|
|
20320
|
-
|
|
20321
|
-
|
|
20322
|
-
|
|
20323
|
-
|
|
20649
|
+
height: clipResult.height,
|
|
20650
|
+
md5sum: md5sumUuid,
|
|
20651
|
+
cardShowStyle: 2,
|
|
20652
|
+
urlCdnTaskId: clipResult.clipKey
|
|
20653
|
+
}
|
|
20654
|
+
],
|
|
20655
|
+
shortTitle: params.title ? [
|
|
20656
|
+
{
|
|
20657
|
+
shortTitle: params.title
|
|
20658
|
+
}
|
|
20659
|
+
] : [],
|
|
20660
|
+
member: {}
|
|
20661
|
+
};
|
|
20662
|
+
const publishData = {
|
|
20663
|
+
objectType: 0,
|
|
20664
|
+
longitude: 0,
|
|
20665
|
+
latitude: 0,
|
|
20666
|
+
feedLongitude: 0,
|
|
20667
|
+
feedLatitude: 0,
|
|
20668
|
+
originalFlag: params.originalFlag ?? 0,
|
|
20669
|
+
topics: params.topics || [],
|
|
20670
|
+
isFullPost: 1,
|
|
20671
|
+
handleFlag: 2,
|
|
20672
|
+
videoClipTaskId: clipResult.clipKey,
|
|
20673
|
+
traceInfo: {
|
|
20674
|
+
traceKey,
|
|
20675
|
+
uploadCdnStart: uploadStartTime,
|
|
20676
|
+
uploadCdnEnd: uploadEndTime
|
|
20324
20677
|
},
|
|
20678
|
+
objectDesc,
|
|
20679
|
+
report: {
|
|
20680
|
+
clipKey: clipResult.clipKey,
|
|
20681
|
+
draftId: clipResult.clipKey,
|
|
20682
|
+
...buildCommonBody(auth.finderUsername),
|
|
20683
|
+
height: videoMeta.height,
|
|
20684
|
+
width: videoMeta.width,
|
|
20685
|
+
duration: videoMeta.duration,
|
|
20686
|
+
fileSize: videoUpload.fileSize,
|
|
20687
|
+
uploadCost: (uploadEndTime - uploadStartTime) * 1000
|
|
20688
|
+
},
|
|
20689
|
+
postFlag: 0,
|
|
20690
|
+
mode: 1,
|
|
20691
|
+
clientid: external_node_crypto_default().randomUUID(),
|
|
20692
|
+
...buildCommonBody(auth.finderUsername)
|
|
20693
|
+
};
|
|
20694
|
+
if (params.scheduledTime) publishData.effectiveTime = params.scheduledTime;
|
|
20695
|
+
if (params.tagInfo && tagKey) publishData.tagInfo = buildTagInfo(params.tagInfo, tagKey);
|
|
20696
|
+
const publishRes = await proxyHttp.api({
|
|
20697
|
+
method: "POST",
|
|
20698
|
+
url: `${MICRO_CONTENT_BASE}/post/post_create`,
|
|
20699
|
+
params: buildPublishQuery(client),
|
|
20700
|
+
data: publishData,
|
|
20325
20701
|
defaultErrorMsg: "发布视频失败"
|
|
20326
20702
|
});
|
|
20327
|
-
logger.info(`[publishVideo]
|
|
20703
|
+
logger.info(`[publishVideo] 发布结果: errCode=${publishRes.errCode}, baseResp.errcode=${publishRes.data?.baseResp?.errcode}`);
|
|
20328
20704
|
return publishRes;
|
|
20329
20705
|
}
|
|
20330
20706
|
function sleep(ms) {
|
|
20331
20707
|
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
20332
20708
|
}
|
|
20709
|
+
async function resolveLocalCoverPath(coverPath, label, tmpCachePath, logger) {
|
|
20710
|
+
if (!/^https?:\/\//i.test(coverPath)) return coverPath;
|
|
20711
|
+
const fileName = (0, share_namespaceObject.getFilenameFromUrl)(coverPath);
|
|
20712
|
+
const savePath = external_node_path_default().join(tmpCachePath, `${Date.now()}-${label}-${fileName}`);
|
|
20713
|
+
await (0, share_namespaceObject.downloadImage)(coverPath, savePath);
|
|
20714
|
+
return savePath;
|
|
20715
|
+
}
|
|
20333
20716
|
const shipinhaoPublishVideo_mock_mockAction = async (task, params)=>{
|
|
20334
|
-
task.logger.info("[shipinhaoPublishVideo] 开始执行视频号视频发布 - Mock API 方式");
|
|
20335
20717
|
const updateTaskState = task.taskStageStore?.update?.bind(task.taskStageStore, task.taskId || "");
|
|
20336
20718
|
let currentStep = "初始化";
|
|
20337
20719
|
try {
|
|
20338
20720
|
currentStep = "解析认证信息";
|
|
20339
20721
|
const cookieString = params.cookies.map((c)=>`${c.name}=${c.value}`).join("; ");
|
|
20340
|
-
const
|
|
20341
|
-
|
|
20342
|
-
|
|
20722
|
+
const http = new Http({
|
|
20723
|
+
headers: {
|
|
20724
|
+
cookie: cookieString
|
|
20725
|
+
}
|
|
20726
|
+
});
|
|
20727
|
+
currentStep = "验证发布参数";
|
|
20728
|
+
if (!params.videoPath) return (0, share_namespaceObject.response)(414, "视频文件路径不能为空", "");
|
|
20729
|
+
if (!params.coverPath) return (0, share_namespaceObject.response)(414, "横屏封面图片路径不能为空", "");
|
|
20730
|
+
currentStep = "获取上传认证";
|
|
20731
|
+
const auth = await getShipinhaoUploadAuth(cookieString, http);
|
|
20732
|
+
const client = resolveClientContext(params, auth.uin);
|
|
20733
|
+
const publishHeaders = buildPublishHeaders(cookieString, client);
|
|
20734
|
+
const microHttp = new Http({
|
|
20735
|
+
headers: publishHeaders
|
|
20736
|
+
});
|
|
20343
20737
|
const args = [
|
|
20344
20738
|
{
|
|
20345
|
-
headers
|
|
20739
|
+
headers: publishHeaders
|
|
20346
20740
|
},
|
|
20347
20741
|
task.logger,
|
|
20348
20742
|
params.proxyLoc,
|
|
20349
20743
|
params.accountId,
|
|
20350
20744
|
"shipinhao"
|
|
20351
20745
|
];
|
|
20352
|
-
const http = new Http({
|
|
20353
|
-
headers
|
|
20354
|
-
});
|
|
20355
20746
|
const proxyHttp = new Http(...args);
|
|
20356
|
-
currentStep = "
|
|
20357
|
-
|
|
20358
|
-
if (!params.coverPath) return (0, share_namespaceObject.response)(414, "封面图片路径不能为空", "");
|
|
20359
|
-
currentStep = "获取上传认证";
|
|
20360
|
-
task.logger.info("[shipinhaoPublishVideo] 获取上传认证...");
|
|
20361
|
-
const auth = await getShipinhaoUploadAuth(cookieString, http);
|
|
20362
|
-
currentStep = "解析视频元数据";
|
|
20363
|
-
task.logger.info("[shipinhaoPublishVideo] 解析视频元数据...");
|
|
20364
|
-
const videoMeta = parseVideoMeta(params.videoPath);
|
|
20365
|
-
if (!videoMeta) return (0, share_namespaceObject.response)(414, "视频文件解析失败,请检查文件格式(仅支持 MP4)", "");
|
|
20747
|
+
currentStep = "组装视频元数据";
|
|
20748
|
+
const videoMeta = buildVideoMetaFromParams(params.videoPath, params.videoMetadata);
|
|
20366
20749
|
task.logger.info(`[shipinhaoPublishVideo] 视频: ${videoMeta.width}×${videoMeta.height}, ${videoMeta.duration.toFixed(2)}s, ${(videoMeta.fileSize / 1024 / 1024).toFixed(2)}MB, codec=${videoMeta.codec || "unknown"}`);
|
|
20367
20750
|
currentStep = "校验视频限制";
|
|
20368
20751
|
const validationError = validateShipinhaoVideo(params.videoPath, videoMeta);
|
|
20369
20752
|
if (validationError) {
|
|
20370
|
-
task.logger.error(`[shipinhaoPublishVideo] 视频校验未通过: ${validationError}`);
|
|
20371
20753
|
await updateTaskState?.({
|
|
20372
20754
|
state: share_namespaceObject.TaskState.FAILED,
|
|
20373
20755
|
error: validationError
|
|
20374
20756
|
});
|
|
20375
20757
|
return (0, share_namespaceObject.response)(414, validationError, "");
|
|
20376
20758
|
}
|
|
20377
|
-
task.logger.info("[shipinhaoPublishVideo] 视频校验通过");
|
|
20378
20759
|
currentStep = "校验标题";
|
|
20379
20760
|
const titleError = validateShipinhaoTitle(params.title);
|
|
20380
20761
|
if (titleError) {
|
|
20381
|
-
task.logger.error(`[shipinhaoPublishVideo] 标题校验未通过: ${titleError}`);
|
|
20382
20762
|
await updateTaskState?.({
|
|
20383
20763
|
state: share_namespaceObject.TaskState.FAILED,
|
|
20384
20764
|
error: titleError
|
|
@@ -20386,14 +20766,14 @@ var __webpack_exports__ = {};
|
|
|
20386
20766
|
return (0, share_namespaceObject.response)(414, titleError, "");
|
|
20387
20767
|
}
|
|
20388
20768
|
currentStep = "获取 traceKey";
|
|
20389
|
-
task.logger
|
|
20390
|
-
|
|
20769
|
+
const traceKey = await getTraceKey(auth, client, microHttp, task.logger);
|
|
20770
|
+
let tagKey = null;
|
|
20771
|
+
if (params.tagInfo) {
|
|
20772
|
+
currentStep = "获取内容声明 tagKey";
|
|
20773
|
+
tagKey = await getObjectTagKey(auth, client, microHttp, task.logger);
|
|
20774
|
+
}
|
|
20391
20775
|
const uploadStartTime = Math.floor(Date.now() / 1000);
|
|
20392
|
-
task.logger.info(`[shipinhaoPublishVideo] 上传开始时间: ${uploadStartTime}`);
|
|
20393
20776
|
currentStep = "上传视频";
|
|
20394
|
-
task.logger.info("[shipinhaoPublishVideo] 上传视频...");
|
|
20395
|
-
task.logger.info(`[shipinhaoPublishVideo] 视频路径: ${params.videoPath}`);
|
|
20396
|
-
task.logger.info(`[shipinhaoPublishVideo] 视频文件类型: ${auth.videoFileType}`);
|
|
20397
20777
|
const videoUpload = await uploader_uploadFile({
|
|
20398
20778
|
filePath: params.videoPath,
|
|
20399
20779
|
fileType: auth.videoFileType,
|
|
@@ -20402,24 +20782,32 @@ var __webpack_exports__ = {};
|
|
|
20402
20782
|
http,
|
|
20403
20783
|
logger: task.logger
|
|
20404
20784
|
});
|
|
20405
|
-
task.logger.info(`[shipinhaoPublishVideo] 视频上传完成,URL: ${videoUpload.downloadUrl}`);
|
|
20406
20785
|
const uploadEndTime = Math.floor(Date.now() / 1000);
|
|
20407
|
-
task.logger.info(`[shipinhaoPublishVideo]
|
|
20408
|
-
currentStep = "
|
|
20409
|
-
task.
|
|
20410
|
-
task.logger.info(`[shipinhaoPublishVideo] 封面路径: ${params.coverPath}`);
|
|
20411
|
-
task.logger.info(`[shipinhaoPublishVideo] 封面文件类型: ${auth.pictureFileType}`);
|
|
20786
|
+
task.logger.info(`[shipinhaoPublishVideo] 耗时: ${uploadEndTime - uploadStartTime}s`);
|
|
20787
|
+
currentStep = "上传横屏封面";
|
|
20788
|
+
const localCoverPath = await resolveLocalCoverPath(params.coverPath, "横屏封面", task.getTmpPath(), task.logger);
|
|
20412
20789
|
const coverUpload = await uploader_uploadFile({
|
|
20413
|
-
filePath:
|
|
20790
|
+
filePath: localCoverPath,
|
|
20414
20791
|
fileType: auth.pictureFileType,
|
|
20415
20792
|
uin: auth.uin,
|
|
20416
20793
|
authKey: auth.authKey,
|
|
20417
20794
|
http,
|
|
20418
20795
|
logger: task.logger
|
|
20419
20796
|
});
|
|
20420
|
-
|
|
20797
|
+
let verticalCoverUpload = coverUpload;
|
|
20798
|
+
if (params.verticalCoverPath) {
|
|
20799
|
+
currentStep = "上传竖屏封面";
|
|
20800
|
+
const localVerticalPath = await resolveLocalCoverPath(params.verticalCoverPath, "竖屏封面", task.getTmpPath(), task.logger);
|
|
20801
|
+
verticalCoverUpload = await uploader_uploadFile({
|
|
20802
|
+
filePath: localVerticalPath,
|
|
20803
|
+
fileType: auth.pictureFileType,
|
|
20804
|
+
uin: auth.uin,
|
|
20805
|
+
authKey: auth.authKey,
|
|
20806
|
+
http,
|
|
20807
|
+
logger: task.logger
|
|
20808
|
+
});
|
|
20809
|
+
}
|
|
20421
20810
|
currentStep = "提交转码";
|
|
20422
|
-
task.logger.info("[shipinhaoPublishVideo] 提交转码...");
|
|
20423
20811
|
const clipResult = await submitAndPollTranscode({
|
|
20424
20812
|
videoUrl: videoUpload.downloadUrl,
|
|
20425
20813
|
videoMeta,
|
|
@@ -20427,21 +20815,24 @@ var __webpack_exports__ = {};
|
|
|
20427
20815
|
uploadStartTime,
|
|
20428
20816
|
uploadEndTime,
|
|
20429
20817
|
finderUsername: auth.finderUsername,
|
|
20430
|
-
|
|
20818
|
+
client,
|
|
20819
|
+
http: microHttp,
|
|
20431
20820
|
logger: task.logger
|
|
20432
20821
|
});
|
|
20433
20822
|
currentStep = "发布视频";
|
|
20434
|
-
task.logger.info("[shipinhaoPublishVideo] 发布视频...");
|
|
20435
|
-
task.logger.info(`[shipinhaoPublishVideo] clipKey: ${clipResult.clipKey}`);
|
|
20436
20823
|
let publishResult;
|
|
20437
20824
|
try {
|
|
20438
20825
|
publishResult = await publishVideo({
|
|
20439
20826
|
params,
|
|
20440
20827
|
auth,
|
|
20828
|
+
client,
|
|
20441
20829
|
clipResult,
|
|
20442
20830
|
videoUpload,
|
|
20443
20831
|
coverUpload,
|
|
20832
|
+
verticalCoverUpload,
|
|
20833
|
+
videoMeta,
|
|
20444
20834
|
traceKey,
|
|
20835
|
+
tagKey,
|
|
20445
20836
|
uploadStartTime,
|
|
20446
20837
|
uploadEndTime,
|
|
20447
20838
|
proxyHttp,
|
|
@@ -20453,7 +20844,6 @@ var __webpack_exports__ = {};
|
|
|
20453
20844
|
const classified = classifyPublishError(handledError);
|
|
20454
20845
|
if (classified) {
|
|
20455
20846
|
const message = `${classified.userMessage}${task.debug ? ` ${http.proxyInfo}` : ""}`;
|
|
20456
|
-
task.logger.error(`[shipinhaoPublishVideo] ${classified.category},直接返回: ${handledError.message} (code=${handledError.code})`, stringifyError(handledError));
|
|
20457
20847
|
await updateTaskState?.({
|
|
20458
20848
|
state: share_namespaceObject.TaskState.FAILED,
|
|
20459
20849
|
error: message
|
|
@@ -20468,12 +20858,10 @@ var __webpack_exports__ = {};
|
|
|
20468
20858
|
}
|
|
20469
20859
|
task.logger.info(`[shipinhaoPublishVideo] publishResult: ${JSON.stringify(publishResult)}`);
|
|
20470
20860
|
const resultCode = publishResult.data?.baseResp?.errcode ?? publishResult.errCode;
|
|
20471
|
-
const resultMsg = publishResult.data?.baseResp?.errmsg ?? "发布成功";
|
|
20861
|
+
const resultMsg = publishResult.data?.baseResp?.errmsg ?? (0 === resultCode ? "发布成功" : `发布失败(errCode=${resultCode})`);
|
|
20472
20862
|
if (0 === resultCode) {
|
|
20473
|
-
|
|
20474
|
-
task.logger.
|
|
20475
|
-
task.logger.info(`[shipinhaoPublishVideo] 视频URL: ${clipResult.url}`);
|
|
20476
|
-
task.logger.info(`[shipinhaoPublishVideo] 封面URL: ${coverUpload.downloadUrl}`);
|
|
20863
|
+
const publishId = extractEncFileKey(verticalCoverUpload.downloadUrl);
|
|
20864
|
+
if (!publishId) task.logger.error(`[shipinhaoPublishVideo] 封面 DownloadURL 中未解析到 encfilekey,关联 id 为空: ${verticalCoverUpload.downloadUrl}`);
|
|
20477
20865
|
await updateTaskState?.({
|
|
20478
20866
|
state: share_namespaceObject.TaskState.SUCCESS,
|
|
20479
20867
|
result: {
|
|
@@ -20489,41 +20877,49 @@ var __webpack_exports__ = {};
|
|
|
20489
20877
|
uid: params.uid,
|
|
20490
20878
|
publishParams: {
|
|
20491
20879
|
videoPath: params.videoPath,
|
|
20492
|
-
coverPath: params.coverPath
|
|
20880
|
+
coverPath: params.coverPath,
|
|
20881
|
+
verticalCoverPath: params.verticalCoverPath,
|
|
20882
|
+
title: params.title,
|
|
20883
|
+
topics: params.topics,
|
|
20884
|
+
mentionedUsers: params.mentionedUsers,
|
|
20885
|
+
collection: params.collection,
|
|
20886
|
+
event: params.event,
|
|
20887
|
+
link: params.link,
|
|
20888
|
+
tagInfo: params.tagInfo,
|
|
20889
|
+
originalFlag: params.originalFlag,
|
|
20890
|
+
scheduledTime: params.scheduledTime
|
|
20493
20891
|
},
|
|
20494
20892
|
platform: "shipinhao"
|
|
20495
20893
|
});
|
|
20496
|
-
|
|
20497
|
-
return (0, share_namespaceObject.response)(0, "发布成功", clipResult.clipKey);
|
|
20894
|
+
return (0, share_namespaceObject.response)(0, "发布成功", publishId);
|
|
20498
20895
|
}
|
|
20499
20896
|
let errorMessage = resultMsg;
|
|
20500
20897
|
if (-11224 === resultCode) errorMessage = "视频号管理员完成实名且绑定手机号后才可以发表";
|
|
20501
20898
|
else if (300333 === resultCode || 300334 === resultCode) errorMessage = "登录失效";
|
|
20502
20899
|
else if (300330 === resultCode) errorMessage = "未登录";
|
|
20900
|
+
else if (300002 === resultCode) errorMessage = "官方平台在校验音乐/位置/定时信息时失败了,请重新编辑后发布";
|
|
20503
20901
|
task.logger.error(`[shipinhaoPublishVideo] 发布失败: ${errorMessage} (errCode=${resultCode})`);
|
|
20504
20902
|
await updateTaskState?.({
|
|
20505
20903
|
state: share_namespaceObject.TaskState.FAILED,
|
|
20506
20904
|
error: errorMessage
|
|
20507
20905
|
});
|
|
20508
|
-
return (0, share_namespaceObject.response)(
|
|
20906
|
+
return (0, share_namespaceObject.response)(414, errorMessage, "");
|
|
20509
20907
|
} catch (error) {
|
|
20510
20908
|
const handledError = Http.handleApiError(error);
|
|
20511
20909
|
const errorMsg = handledError.message || "发布失败,请稍后重试";
|
|
20512
|
-
const errorCode = handledError.code || 414;
|
|
20513
20910
|
task.logger.error(`[shipinhaoPublishVideo] 发布流程异常 [${currentStep}]: ${errorMsg}`, stringifyError(error), handledError.extra);
|
|
20514
|
-
task.logger.error(`[shipinhaoPublishVideo] 错误码: ${errorCode}, 当前步骤: ${currentStep}`);
|
|
20515
20911
|
await updateTaskState?.({
|
|
20516
20912
|
state: share_namespaceObject.TaskState.FAILED,
|
|
20517
20913
|
error: errorMsg
|
|
20518
20914
|
});
|
|
20519
|
-
return (0, share_namespaceObject.response)(
|
|
20915
|
+
return (0, share_namespaceObject.response)(414, errorMsg, "");
|
|
20520
20916
|
}
|
|
20521
20917
|
};
|
|
20522
20918
|
const shipinhaoPublishVideo_rpa_rpaAction = async (task, params)=>{
|
|
20523
20919
|
task.logger.info("开始微信视频号视频发布(RPA 模式)");
|
|
20524
|
-
const videoMeta =
|
|
20525
|
-
if (!videoMeta) return (0, share_namespaceObject.response)(414, "视频文件解析失败,请检查文件格式(仅支持 MP4)", "");
|
|
20920
|
+
const videoMeta = buildVideoMetaFromParams(params.videoPath, params.videoMetadata);
|
|
20526
20921
|
task.logger.info(`视频: ${videoMeta.width}×${videoMeta.height}, ${videoMeta.duration.toFixed(2)}s, ${(videoMeta.fileSize / 1024 / 1024).toFixed(2)}MB, codec=${videoMeta.codec || "unknown"}`);
|
|
20922
|
+
if (!videoMeta.codec) task.logger.warn("未能读取视频编码格式,跳过 H.264 预检,交由服务端判断");
|
|
20527
20923
|
const validationError = validateShipinhaoVideo(params.videoPath, videoMeta);
|
|
20528
20924
|
if (validationError) {
|
|
20529
20925
|
task.logger.error(`视频校验未通过: ${validationError}`);
|
|
@@ -20535,6 +20931,17 @@ var __webpack_exports__ = {};
|
|
|
20535
20931
|
task.logger.error(`标题校验未通过: ${titleError}`);
|
|
20536
20932
|
return (0, share_namespaceObject.response)(414, titleError, "");
|
|
20537
20933
|
}
|
|
20934
|
+
const unsupported = [
|
|
20935
|
+
params.verticalCoverPath && "verticalCoverPath",
|
|
20936
|
+
params.collection && "collection",
|
|
20937
|
+
params.originalFlag && "originalFlag",
|
|
20938
|
+
params.postWithMemberZoneLink && "postWithMemberZoneLink"
|
|
20939
|
+
].filter(Boolean);
|
|
20940
|
+
if (unsupported.length) task.logger.warn(`RPA 模式不支持以下参数,将被忽略: ${unsupported.join("、")};如需生效请使用 mockApi 模式`);
|
|
20941
|
+
if (params.tagInfo && 5 === params.tagInfo.tagType) {
|
|
20942
|
+
const shootInfo = params.tagInfo.shootInfo;
|
|
20943
|
+
if (shootInfo && (shootInfo.provinceCode || shootInfo.cityCode)) task.logger.warn("tagInfo.tagType=5 在 RPA 模式下仅支持拍摄时间和国家选择,省市选择需要使用 mockApi 模式");
|
|
20944
|
+
}
|
|
20538
20945
|
const tmpCachePath = task.getTmpPath();
|
|
20539
20946
|
const page = await task.createPage({
|
|
20540
20947
|
url: "https://channels.weixin.qq.com/platform/post/create",
|
|
@@ -20645,7 +21052,12 @@ var __webpack_exports__ = {};
|
|
|
20645
21052
|
}
|
|
20646
21053
|
});
|
|
20647
21054
|
}
|
|
20648
|
-
|
|
21055
|
+
const descriptionText = payload_buildDescription({
|
|
21056
|
+
description: params.description,
|
|
21057
|
+
topics: params.topics,
|
|
21058
|
+
mentionedUsers: params.mentionedUsers
|
|
21059
|
+
});
|
|
21060
|
+
if (descriptionText) {
|
|
20649
21061
|
task.logger.info("填写视频描述");
|
|
20650
21062
|
await retryAction(async ()=>{
|
|
20651
21063
|
const descEditor = await waitForElement(".input-editor", 10000);
|
|
@@ -20657,7 +21069,7 @@ var __webpack_exports__ = {};
|
|
|
20657
21069
|
});
|
|
20658
21070
|
await page.waitForTimeout(300);
|
|
20659
21071
|
task.logger.info("已清空编辑器内容");
|
|
20660
|
-
await descEditor.pressSequentially(
|
|
21072
|
+
await descEditor.pressSequentially(descriptionText, {
|
|
20661
21073
|
delay: 10
|
|
20662
21074
|
});
|
|
20663
21075
|
await page.waitForTimeout(500);
|
|
@@ -20692,7 +21104,59 @@ var __webpack_exports__ = {};
|
|
|
20692
21104
|
await poperInstance.nth(1).click();
|
|
20693
21105
|
task.logger.info("地点选择完成");
|
|
20694
21106
|
}
|
|
20695
|
-
if (params.
|
|
21107
|
+
if (params.collection) {
|
|
21108
|
+
task.logger.info(`选择合集: ${params.collection.collectionName}`);
|
|
21109
|
+
const instanceCollection = page.locator(".post-album-display-wrap");
|
|
21110
|
+
await instanceCollection.click();
|
|
21111
|
+
await page.waitForTimeout(1000);
|
|
21112
|
+
page.locator(".post-album-wrap .option-item").filter({
|
|
21113
|
+
hasText: params.collection.collectionName
|
|
21114
|
+
}).first().click({
|
|
21115
|
+
force: true
|
|
21116
|
+
});
|
|
21117
|
+
}
|
|
21118
|
+
if (params.link) {
|
|
21119
|
+
task.logger.info(`设置扩展阅读链接: ${params.link.title}`);
|
|
21120
|
+
await page.locator(".post-link-wrap .link-display-wrap").click();
|
|
21121
|
+
await page.waitForTimeout(300);
|
|
21122
|
+
const linkTypeText = 2 === params.link.urlType ? "红包封面" : "公众号文章";
|
|
21123
|
+
await page.locator(".link-option-item .title-wrap span").filter({
|
|
21124
|
+
hasText: linkTypeText
|
|
21125
|
+
}).click();
|
|
21126
|
+
await page.waitForTimeout(300);
|
|
21127
|
+
const placeholder = 2 === params.link.urlType ? "粘贴红包封面链接" : "粘贴公众号文章链接";
|
|
21128
|
+
await page.locator(`.link-input-wrap input[placeholder="${placeholder}"]`).fill(params.link.link);
|
|
21129
|
+
await page.waitForTimeout(500);
|
|
21130
|
+
task.logger.info(`已设置${linkTypeText}: ${params.link.link}`);
|
|
21131
|
+
}
|
|
21132
|
+
if (params.event) {
|
|
21133
|
+
task.logger.info(`选择活动: ${params.event.eventName}`);
|
|
21134
|
+
await page.locator(".post-activity-wrap .activity-display").click();
|
|
21135
|
+
await page.waitForTimeout(500);
|
|
21136
|
+
await page.locator(".activity-filter-wrap .weui-desktop-form__input[placeholder='搜索活动']").fill(params.event.eventName);
|
|
21137
|
+
await page.waitForTimeout(500);
|
|
21138
|
+
const searchLoading = page.locator(".search-loading");
|
|
21139
|
+
await searchLoading.waitFor({
|
|
21140
|
+
state: "hidden",
|
|
21141
|
+
timeout: 5000
|
|
21142
|
+
}).catch(()=>{
|
|
21143
|
+
task.logger.warn("活动搜索加载超时,继续尝试选择");
|
|
21144
|
+
});
|
|
21145
|
+
const activityItem = page.locator(".option-item .activity-item .activity-item-info .name").filter({
|
|
21146
|
+
hasText: params.event.eventName
|
|
21147
|
+
});
|
|
21148
|
+
const count = await activityItem.count();
|
|
21149
|
+
if (count > 0) {
|
|
21150
|
+
await activityItem.first().click();
|
|
21151
|
+
await page.waitForTimeout(300);
|
|
21152
|
+
task.logger.info(`已选择活动: ${params.event.eventName}`);
|
|
21153
|
+
} else {
|
|
21154
|
+
task.logger.warn(`未找到活动: ${params.event.eventName},将不参与活动`);
|
|
21155
|
+
await page.locator(".post-activity-wrap .activity-display").click();
|
|
21156
|
+
await page.waitForTimeout(300);
|
|
21157
|
+
}
|
|
21158
|
+
}
|
|
21159
|
+
if (params.scheduledTime) {
|
|
20696
21160
|
task.logger.info("设置定时发布");
|
|
20697
21161
|
const timingRadio = page.locator(".weui-desktop-form__check-label").filter({
|
|
20698
21162
|
hasNotText: "不定时"
|
|
@@ -20701,10 +21165,10 @@ var __webpack_exports__ = {};
|
|
|
20701
21165
|
await page.waitForTimeout(500);
|
|
20702
21166
|
const instance = page.locator(".weui-desktop-picker__date");
|
|
20703
21167
|
await instance.click();
|
|
20704
|
-
const dateD = utils_TimeFormatter.format(1000 * params.
|
|
21168
|
+
const dateD = utils_TimeFormatter.format(1000 * params.scheduledTime, "d");
|
|
20705
21169
|
const nowMonth = utils_TimeFormatter.format(Date.now(), "MM月");
|
|
20706
21170
|
const nowMonthText = utils_TimeFormatter.format(Date.now(), "M月");
|
|
20707
|
-
const month = utils_TimeFormatter.format(1000 * params.
|
|
21171
|
+
const month = utils_TimeFormatter.format(1000 * params.scheduledTime, "MM月");
|
|
20708
21172
|
const monthLocator = await page.locator("weui-desktop-picker__panel__label").filter({
|
|
20709
21173
|
hasText: month
|
|
20710
21174
|
}).first();
|
|
@@ -20721,14 +21185,85 @@ var __webpack_exports__ = {};
|
|
|
20721
21185
|
await page.locator(".weui-desktop-picker__table-row td a").filter({
|
|
20722
21186
|
hasText: dateD
|
|
20723
21187
|
}).first().click();
|
|
20724
|
-
await page.locator(".weui-desktop-form__input-wrp input[placeholder*='请选择时间']").fill(utils_TimeFormatter.format(1000 * params.
|
|
21188
|
+
await page.locator(".weui-desktop-form__input-wrp input[placeholder*='请选择时间']").fill(utils_TimeFormatter.format(1000 * params.scheduledTime, "hh:mm"));
|
|
20725
21189
|
await page.locator("i.weui-desktop-icon__time").click();
|
|
20726
21190
|
await page.locator(".post-time-wrap .form-item .label").filter({
|
|
20727
21191
|
hasText: "发表时间"
|
|
20728
21192
|
}).click();
|
|
20729
21193
|
}
|
|
21194
|
+
if (params.tagInfo) {
|
|
21195
|
+
task.logger.info(`设置视频标注: tagType=${params.tagInfo.tagType}`);
|
|
21196
|
+
await page.locator(".mark-tag-select").click();
|
|
21197
|
+
await page.waitForTimeout(300);
|
|
21198
|
+
const tagTypeTextMap = {
|
|
21199
|
+
0: "无需标注",
|
|
21200
|
+
1: "含AI生成内容",
|
|
21201
|
+
2: "内容包含营销广告",
|
|
21202
|
+
3: "内容为虚构剧情,仅供娱乐",
|
|
21203
|
+
5: "内容为自行拍摄",
|
|
21204
|
+
7: "内容为转载",
|
|
21205
|
+
8: "个人观点,仅供参考"
|
|
21206
|
+
};
|
|
21207
|
+
const tagText = tagTypeTextMap[params.tagInfo.tagType];
|
|
21208
|
+
if (tagText) {
|
|
21209
|
+
await page.locator(".mark-tag-option .option-main").filter({
|
|
21210
|
+
hasText: tagText
|
|
21211
|
+
}).click();
|
|
21212
|
+
await page.waitForTimeout(300);
|
|
21213
|
+
if (5 === params.tagInfo.tagType) {
|
|
21214
|
+
const shootInfo = params.tagInfo.shootInfo;
|
|
21215
|
+
if (shootInfo) {
|
|
21216
|
+
task.logger.info("填写拍摄时间和地点...");
|
|
21217
|
+
await page.waitForTimeout(500);
|
|
21218
|
+
if (shootInfo.postTimestamp) {
|
|
21219
|
+
task.logger.info(`设置拍摄时间: ${shootInfo.postTimestamp}`);
|
|
21220
|
+
const timestamp = 1000 * parseInt(shootInfo.postTimestamp, 10);
|
|
21221
|
+
const date = new Date(timestamp);
|
|
21222
|
+
await page.locator(".original-dialog-content .weui-desktop-picker__date input[placeholder*='请选择拍摄时间']").click();
|
|
21223
|
+
await page.waitForTimeout(300);
|
|
21224
|
+
const dayNum = date.getDate();
|
|
21225
|
+
await page.locator(".weui-desktop-picker__table a").filter({
|
|
21226
|
+
hasText: new RegExp(`^\\s*${dayNum}\\s*$`)
|
|
21227
|
+
}).first().click();
|
|
21228
|
+
await page.waitForTimeout(300);
|
|
21229
|
+
}
|
|
21230
|
+
if (shootInfo.countryCode || shootInfo.provinceCode || shootInfo.cityCode) {
|
|
21231
|
+
task.logger.info("设置拍摄地点...");
|
|
21232
|
+
await page.locator(".original-dialog-content .weui-desktop-form__dropdowncascade .weui-desktop-form__dropdowncascade__dt").click();
|
|
21233
|
+
await page.waitForTimeout(300);
|
|
21234
|
+
if (1156 === shootInfo.countryCode) {
|
|
21235
|
+
await page.locator(".weui-desktop-dropdown__list-ele .weui-desktop-dropdown__list-ele__text").filter({
|
|
21236
|
+
hasText: "中国"
|
|
21237
|
+
}).click();
|
|
21238
|
+
await page.waitForTimeout(300);
|
|
21239
|
+
task.logger.warn("RPA 模式下暂不支持选择具体省份和城市,仅选择了国家");
|
|
21240
|
+
} else task.logger.warn(`不支持的国家代码: ${shootInfo.countryCode},跳过地点设置`);
|
|
21241
|
+
}
|
|
21242
|
+
const confirmBtn = await waitForElement(".weui-desktop-dialog .weui-desktop-btn_primary");
|
|
21243
|
+
if (confirmBtn) {
|
|
21244
|
+
await confirmBtn.click();
|
|
21245
|
+
await page.waitForTimeout(300);
|
|
21246
|
+
}
|
|
21247
|
+
} else task.logger.warn("tagType=5 需要提供 shootInfo 字段(拍摄时间和地点)");
|
|
21248
|
+
}
|
|
21249
|
+
if (7 === params.tagInfo.tagType) {
|
|
21250
|
+
const repostSource = params.tagInfo.repostSource;
|
|
21251
|
+
if (repostSource) {
|
|
21252
|
+
task.logger.info(`填写转载来源: ${repostSource}`);
|
|
21253
|
+
await page.waitForTimeout(500);
|
|
21254
|
+
await page.locator(".repost-dialog-content .repost-textarea").fill(repostSource);
|
|
21255
|
+
await page.waitForTimeout(300);
|
|
21256
|
+
const confirmBtn = await waitForElement(".weui-desktop-dialog .weui-desktop-btn_primary");
|
|
21257
|
+
if (confirmBtn) {
|
|
21258
|
+
await confirmBtn.click();
|
|
21259
|
+
await page.waitForTimeout(300);
|
|
21260
|
+
}
|
|
21261
|
+
} else task.logger.warn("tagType=7 需要提供 repostSource 字段(转载来源)");
|
|
21262
|
+
}
|
|
21263
|
+
} else task.logger.warn(`未知的 tagType: ${params.tagInfo.tagType},跳过标注设置`);
|
|
21264
|
+
}
|
|
20730
21265
|
task.logger.info("准备发布...");
|
|
20731
|
-
await page.waitForTimeout(
|
|
21266
|
+
await page.waitForTimeout(500);
|
|
20732
21267
|
let videoId = "";
|
|
20733
21268
|
const handleResponse = async (response)=>{
|
|
20734
21269
|
const url = response.url();
|
|
@@ -20794,19 +21329,60 @@ var __webpack_exports__ = {};
|
|
|
20794
21329
|
};
|
|
20795
21330
|
const ShipinhaoPublishVideoParamsSchema = ActionCommonParamsSchema.extend({
|
|
20796
21331
|
videoPath: schemas_string().min(1),
|
|
21332
|
+
videoMetadata: schemas_object({
|
|
21333
|
+
duration: schemas_number().positive(),
|
|
21334
|
+
width: schemas_number().int().positive(),
|
|
21335
|
+
height: schemas_number().int().positive(),
|
|
21336
|
+
fileSize: schemas_number().int().positive(),
|
|
21337
|
+
path: schemas_string().min(1).optional(),
|
|
21338
|
+
fileName: schemas_string().min(1)
|
|
21339
|
+
}),
|
|
20797
21340
|
coverPath: schemas_string().min(1),
|
|
21341
|
+
verticalCoverPath: schemas_string().min(1).optional(),
|
|
20798
21342
|
description: schemas_string(),
|
|
20799
21343
|
title: schemas_string().optional(),
|
|
20800
|
-
|
|
21344
|
+
scheduledTime: schemas_number().int().positive().optional(),
|
|
21345
|
+
isImmediatelyPublish: schemas_boolean().optional(),
|
|
21346
|
+
topics: schemas_array(schemas_string()).optional(),
|
|
21347
|
+
mentionedUsers: schemas_array(schemas_object({
|
|
21348
|
+
nickname: schemas_string()
|
|
21349
|
+
})).optional(),
|
|
21350
|
+
collection: schemas_object({
|
|
21351
|
+
collectionId: schemas_string(),
|
|
21352
|
+
collectionName: schemas_string()
|
|
21353
|
+
}).optional(),
|
|
21354
|
+
event: schemas_object({
|
|
21355
|
+
eventTopicId: schemas_string(),
|
|
21356
|
+
eventName: schemas_string(),
|
|
21357
|
+
eventCreatorNickname: schemas_string().optional()
|
|
21358
|
+
}).optional(),
|
|
21359
|
+
link: schemas_object({
|
|
21360
|
+
link: schemas_string(),
|
|
21361
|
+
title: schemas_string(),
|
|
21362
|
+
urlType: schemas_number().int().default(1)
|
|
21363
|
+
}).optional(),
|
|
21364
|
+
tagInfo: looseObject({
|
|
21365
|
+
tagType: schemas_number().int()
|
|
21366
|
+
}).optional(),
|
|
21367
|
+
originalFlag: union([
|
|
21368
|
+
literal(0),
|
|
21369
|
+
literal(1)
|
|
21370
|
+
]).optional(),
|
|
21371
|
+
postWithMemberZoneLink: union([
|
|
21372
|
+
literal(0),
|
|
21373
|
+
literal(1)
|
|
21374
|
+
]).optional(),
|
|
20801
21375
|
location: schemas_object({
|
|
20802
21376
|
latitude: schemas_number(),
|
|
20803
21377
|
longitude: schemas_number(),
|
|
20804
21378
|
city: schemas_string(),
|
|
21379
|
+
poiName: schemas_string().optional(),
|
|
21380
|
+
address: schemas_string().optional(),
|
|
20805
21381
|
poiClassifyId: schemas_string().optional()
|
|
20806
21382
|
}).optional()
|
|
20807
21383
|
});
|
|
20808
21384
|
const shipinhaoPublishVideo = async (task, params)=>{
|
|
20809
|
-
task.logger.info(`shipinhaoPublishVideo actionType: ${params.actionType}`);
|
|
21385
|
+
task.logger.info(`[shipinhaoPublishVideo] actionType: ${params.actionType}`);
|
|
20810
21386
|
if ("rpa" === params.actionType) return shipinhaoPublishVideo_rpa_rpaAction(task, params);
|
|
20811
21387
|
if ("mockApi" === params.actionType) return shipinhaoPublishVideo_mock_mockAction(task, params);
|
|
20812
21388
|
return executeAction(shipinhaoPublishVideo_mock_mockAction, shipinhaoPublishVideo_rpa_rpaAction)(task, params);
|
|
@@ -26908,4 +27484,4 @@ if (__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_targe
|
|
|
26908
27484
|
});
|
|
26909
27485
|
|
|
26910
27486
|
//# sourceMappingURL=index.js.map
|
|
26911
|
-
//# debugId=
|
|
27487
|
+
//# debugId=028a0eb4-9179-5708-bae0-75174165ae68
|