karin-plugin-kkk 2.25.1 → 2.25.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/CHANGELOG.md +22 -0
- package/config/default_config/app.yaml +11 -2
- package/lib/apps/admin.js +3 -3
- package/lib/apps/help.js +3 -3
- package/lib/apps/push.js +3 -3
- package/lib/apps/qrlogin.js +3 -3
- package/lib/apps/statistics.js +3 -3
- package/lib/apps/tools.js +3 -3
- package/lib/apps/update.js +3 -3
- package/lib/build-metadata.json +5 -5
- package/lib/core_chunk/{main-BY6eDfoV.js → main-Cfpmwn8o.js} +871 -687
- package/lib/core_chunk/{template-DekmxKd7.js → template-B7RenK2I.js} +235 -4
- package/lib/core_chunk/template.d.mts +11 -1
- package/lib/core_chunk/template.js +3 -3
- package/lib/core_chunk/{vendor-DxfKHvj-.js → vendor-rZ5rQnq1.js} +39674 -39678
- package/lib/index.js +3 -3
- package/lib/karin-plugin-kkk.css +42 -0
- package/lib/root.js +1 -1
- package/lib/web.config.js +3 -3
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __esmMin, o as __toESM, r as __export } from "./rolldown-runtime-BMXAG3ag.js";
|
|
2
|
-
import { A as init_locale, An as init_zod, Cn as Chalk, Dn as axios_default, En as init_axios, On as Xhshow, Sn as require_protobufjs, Tn as AxiosError$1, _n as require_png, a as Window, bn as require_heic_decode, dt as init_date_fns, ft as fromUnixTime, ht as differenceInSeconds, i as init_lib, j as zhCN, jn as zod_default, kn as init_dist, mt as format, n as require_lib, pt as formatDistanceToNow, r as require_qr_code_styling, t as require_dist, vn as require_jsQR, wn as init_source, xn as require_express, yn as require_jpeg_js } from "./vendor-
|
|
3
|
-
import { n as init_client, r as reactServerRender } from "./template-
|
|
2
|
+
import { A as init_locale, An as init_zod, Cn as Chalk, Dn as axios_default, En as init_axios, On as Xhshow, Sn as require_protobufjs, Tn as AxiosError$1, _n as require_png, a as Window, bn as require_heic_decode, dt as init_date_fns, ft as fromUnixTime, ht as differenceInSeconds, i as init_lib, j as zhCN, jn as zod_default, kn as init_dist, mt as format, n as require_lib, pt as formatDistanceToNow, r as require_qr_code_styling, t as require_dist, vn as require_jsQR, wn as init_source, xn as require_express, yn as require_jpeg_js } from "./vendor-rZ5rQnq1.js";
|
|
3
|
+
import { i as renderVideoPreviewPage, n as init_client, r as reactServerRender } from "./template-B7RenK2I.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import karin$1, { BOT_CONNECT, app, authMiddleware, checkPkgUpdate, checkPort, common, components, config, copyConfigSync, createBadRequestResponse, createNotFoundResponse, createServerErrorResponse, createSuccessResponse, db, defineConfig, ffmpeg, ffprobe, filesByExt, getBot, hooks, karin, karinPathHtml, karinPathTemp, logger, logs, mkdirSync, range, render, requireFileSync, restart, segment, updatePkg, watch } from "node-karin";
|
|
6
6
|
import fs from "node:fs";
|
|
@@ -17,7 +17,6 @@ import axios, { AxiosError } from "node-karin/axios";
|
|
|
17
17
|
import { Transform } from "node:stream";
|
|
18
18
|
import { pipeline } from "node:stream/promises";
|
|
19
19
|
import express from "node-karin/express";
|
|
20
|
-
import template from "node-karin/template";
|
|
21
20
|
import _ from "node-karin/lodash";
|
|
22
21
|
import { snapka } from "@snapka/puppeteer";
|
|
23
22
|
import { newInjectedPage } from "fingerprint-injector";
|
|
@@ -5767,7 +5766,7 @@ var init_src = __esmMin(() => {
|
|
|
5767
5766
|
init_server();
|
|
5768
5767
|
init_types$1();
|
|
5769
5768
|
init_api_spec();
|
|
5770
|
-
getVersion = () => "6.0.0
|
|
5769
|
+
getVersion = () => "6.0.0";
|
|
5771
5770
|
VERSION = getVersion();
|
|
5772
5771
|
Object.defineProperty(CreateAmagiApp, "version", {
|
|
5773
5772
|
value: VERSION,
|
|
@@ -6228,11 +6227,12 @@ var init_Base = __esmMin(() => {
|
|
|
6228
6227
|
throw error;
|
|
6229
6228
|
} finally {
|
|
6230
6229
|
const filePath = file.filepath;
|
|
6230
|
+
Common.registerVideoPreview(filePath, Config.app.removeCache, 1800 * 1e3);
|
|
6231
6231
|
logger.mark(`临时预览地址:http://localhost:${process.env.HTTP_PORT}/api/kkk/video/${encodeURIComponent(filePath.split("/").pop() ?? "")}`);
|
|
6232
|
-
Config.app.removeCache && logger.info(`文件 ${filePath} 将在
|
|
6232
|
+
Config.app.removeCache && logger.info(`文件 ${filePath} 将在 30 分钟后删除`);
|
|
6233
6233
|
setTimeout(async () => {
|
|
6234
|
-
await Common.removeFile(filePath);
|
|
6235
|
-
},
|
|
6234
|
+
if (await Common.removeFile(filePath)) Common.markVideoPreviewRemoved(filePath);
|
|
6235
|
+
}, 1800 * 1e3);
|
|
6236
6236
|
}
|
|
6237
6237
|
};
|
|
6238
6238
|
downloadVideo = async (event, downloadOpt, uploadOpt) => {
|
|
@@ -6842,12 +6842,14 @@ var init_Common = __esmMin(async () => {
|
|
|
6842
6842
|
await init_module();
|
|
6843
6843
|
Tools = class {
|
|
6844
6844
|
tempDri;
|
|
6845
|
+
videoPreviewState;
|
|
6845
6846
|
constructor() {
|
|
6846
6847
|
this.tempDri = {
|
|
6847
6848
|
default: `${karinPathTemp$1}/${Root.pluginName}/`.replace(/\\/g, "/"),
|
|
6848
6849
|
video: `${karinPathTemp$1}/${Root.pluginName}/kkkdownload/video/`.replace(/\\/g, "/"),
|
|
6849
6850
|
images: `${karinPathTemp$1}/${Root.pluginName}/kkkdownload/images/`.replace(/\\/g, "/")
|
|
6850
6851
|
};
|
|
6852
|
+
this.videoPreviewState = /* @__PURE__ */ new Map();
|
|
6851
6853
|
}
|
|
6852
6854
|
async getReplyMessage(e) {
|
|
6853
6855
|
if (e.replyId) {
|
|
@@ -6948,6 +6950,33 @@ var init_Common = __esmMin(async () => {
|
|
|
6948
6950
|
}
|
|
6949
6951
|
return true;
|
|
6950
6952
|
}
|
|
6953
|
+
registerVideoPreview(filePath, removeCache, ttlMs) {
|
|
6954
|
+
const filename = path.basename(filePath);
|
|
6955
|
+
const createdAt = Date.now();
|
|
6956
|
+
const info = {
|
|
6957
|
+
filename,
|
|
6958
|
+
filePath,
|
|
6959
|
+
createdAt,
|
|
6960
|
+
expireAt: removeCache ? createdAt + ttlMs : void 0,
|
|
6961
|
+
removeCache
|
|
6962
|
+
};
|
|
6963
|
+
this.videoPreviewState.set(filename, info);
|
|
6964
|
+
return info;
|
|
6965
|
+
}
|
|
6966
|
+
getVideoPreview(filename) {
|
|
6967
|
+
return this.videoPreviewState.get(filename) ?? null;
|
|
6968
|
+
}
|
|
6969
|
+
markVideoPreviewRemoved(filePathOrFilename) {
|
|
6970
|
+
const filename = filePathOrFilename.includes("/") || filePathOrFilename.includes("\\") ? path.basename(filePathOrFilename) : filePathOrFilename;
|
|
6971
|
+
const info = this.videoPreviewState.get(filename);
|
|
6972
|
+
if (!info) return null;
|
|
6973
|
+
const updated = {
|
|
6974
|
+
...info,
|
|
6975
|
+
removedAt: Date.now()
|
|
6976
|
+
};
|
|
6977
|
+
this.videoPreviewState.set(filename, updated);
|
|
6978
|
+
return updated;
|
|
6979
|
+
}
|
|
6951
6980
|
useDarkTheme() {
|
|
6952
6981
|
let dark = true;
|
|
6953
6982
|
const configTheme = Config.app.Theme;
|
|
@@ -11175,28 +11204,57 @@ var init_app_schema = __esmMin(() => {
|
|
|
11175
11204
|
type: "divider",
|
|
11176
11205
|
title: "Live Photo 兼容设置"
|
|
11177
11206
|
},
|
|
11207
|
+
{
|
|
11208
|
+
key: "livePhotoMode",
|
|
11209
|
+
type: "radio",
|
|
11210
|
+
label: "Live Photo 处理和发送方式",
|
|
11211
|
+
description: "解析遇到实况图时的处理和发送方式。注意:生成视频性能开销大,2C2G 服务器单张约需 20 秒",
|
|
11212
|
+
orientation: "horizontal",
|
|
11213
|
+
options: [
|
|
11214
|
+
{
|
|
11215
|
+
label: "视频 + 实况图",
|
|
11216
|
+
value: "video_and_livephoto",
|
|
11217
|
+
description: "生成并发送仿 iPhone Live Photo 播放效果的视频(播放三次)+ 对应系统的实况图"
|
|
11218
|
+
},
|
|
11219
|
+
{
|
|
11220
|
+
label: "仅视频",
|
|
11221
|
+
value: "video_only",
|
|
11222
|
+
description: "仅生成并发送仿 iPhone Live Photo 播放效果的视频(播放三次)"
|
|
11223
|
+
},
|
|
11224
|
+
{
|
|
11225
|
+
label: "仅实况图",
|
|
11226
|
+
value: "livephoto_only",
|
|
11227
|
+
description: "仅生成并发送对应系统的实况图,性能开销小"
|
|
11228
|
+
}
|
|
11229
|
+
]
|
|
11230
|
+
},
|
|
11178
11231
|
{
|
|
11179
11232
|
key: "livePhotoSystem",
|
|
11180
11233
|
type: "radio",
|
|
11181
11234
|
label: "Live Photo 静态图兼容系统",
|
|
11182
|
-
description: "当解析到作品/动态包含 Live Photo 时,合并转发里发送的 Live Photo
|
|
11235
|
+
description: "当解析到作品/动态包含 Live Photo 时,合并转发里发送的 Live Photo 静态图按所选系统生成。推荐 OPPO,兼容性最广",
|
|
11183
11236
|
orientation: "horizontal",
|
|
11237
|
+
disabled: $ne("livePhotoMode", "livephoto_only"),
|
|
11184
11238
|
options: [
|
|
11185
11239
|
{
|
|
11186
11240
|
label: "Google",
|
|
11187
|
-
value: "google"
|
|
11241
|
+
value: "google",
|
|
11242
|
+
description: "Google Motion Photo 格式"
|
|
11188
11243
|
},
|
|
11189
11244
|
{
|
|
11190
11245
|
label: "小米(HyperOS)",
|
|
11191
|
-
value: "xiaomi"
|
|
11246
|
+
value: "xiaomi",
|
|
11247
|
+
description: "兼容小米(任何版本)和 Google,但无法被 OPPO 识别"
|
|
11192
11248
|
},
|
|
11193
11249
|
{
|
|
11194
11250
|
label: "OPPO(ColorOS)",
|
|
11195
|
-
value: "oppo"
|
|
11251
|
+
value: "oppo",
|
|
11252
|
+
description: "推荐,兼容 OPPO、小米(较新版本)和 Google"
|
|
11196
11253
|
},
|
|
11197
11254
|
{
|
|
11198
11255
|
label: "华为/荣耀(HarmonyOS/MagicOS)",
|
|
11199
|
-
value: "huawei_honor"
|
|
11256
|
+
value: "huawei_honor",
|
|
11257
|
+
description: "理论可行但未实测"
|
|
11200
11258
|
}
|
|
11201
11259
|
]
|
|
11202
11260
|
},
|
|
@@ -12882,11 +12940,18 @@ var init_api = __esmMin(async () => {
|
|
|
12882
12940
|
apiRouter.use("/platforms/douyin", ...authMiddlewares, router$1);
|
|
12883
12941
|
apiRouter.use("/platforms/bilibili", ...authMiddlewares, router);
|
|
12884
12942
|
});
|
|
12885
|
-
var videoStreamRouter, getVideoRouter;
|
|
12943
|
+
var videoStreamRouter, getVideoRouter, videoPreviewEventsRouter;
|
|
12886
12944
|
var init_router = __esmMin(async () => {
|
|
12945
|
+
await init_client();
|
|
12887
12946
|
await init_utils$1();
|
|
12947
|
+
await init_Config();
|
|
12888
12948
|
videoStreamRouter = (req, res) => {
|
|
12889
|
-
const
|
|
12949
|
+
const filenameParam = req.params.filename;
|
|
12950
|
+
const filename = Array.isArray(filenameParam) ? filenameParam[0] : filenameParam;
|
|
12951
|
+
if (!filename) {
|
|
12952
|
+
createNotFoundResponse(res, "无效的文件名");
|
|
12953
|
+
return;
|
|
12954
|
+
}
|
|
12890
12955
|
const videoPath = Common.validateVideoRequest(filename, res);
|
|
12891
12956
|
if (!videoPath) return;
|
|
12892
12957
|
try {
|
|
@@ -12949,17 +13014,76 @@ var init_router = __esmMin(async () => {
|
|
|
12949
13014
|
}
|
|
12950
13015
|
};
|
|
12951
13016
|
getVideoRouter = (req, res) => {
|
|
12952
|
-
const
|
|
12953
|
-
|
|
13017
|
+
const filenameParam = req.params.filename;
|
|
13018
|
+
const filename = Array.isArray(filenameParam) ? filenameParam[0] : filenameParam;
|
|
13019
|
+
if (!filename) {
|
|
13020
|
+
createNotFoundResponse(res, "无效的文件名");
|
|
13021
|
+
return;
|
|
13022
|
+
}
|
|
13023
|
+
const videoPath = Common.validateVideoRequest(filename, res);
|
|
13024
|
+
if (!videoPath) return;
|
|
12954
13025
|
const videoDataUrl = `/api/kkk/stream/${encodeURIComponent(filename)}`;
|
|
12955
|
-
const
|
|
12956
|
-
const
|
|
12957
|
-
|
|
12958
|
-
|
|
13026
|
+
const previewInfo = Common.getVideoPreview(filename);
|
|
13027
|
+
const removeCache = previewInfo?.removeCache ?? Config.app.removeCache;
|
|
13028
|
+
const createdAt = previewInfo?.createdAt ?? Date.now();
|
|
13029
|
+
const expireAt = previewInfo?.expireAt ?? (removeCache ? createdAt + 600 * 1e3 : void 0);
|
|
13030
|
+
const htmlContent = renderVideoPreviewPage({
|
|
13031
|
+
filename,
|
|
13032
|
+
filePath: previewInfo?.filePath ?? videoPath,
|
|
13033
|
+
videoUrl: videoDataUrl,
|
|
13034
|
+
removeCache,
|
|
13035
|
+
createdAt,
|
|
13036
|
+
expireAt,
|
|
13037
|
+
eventsUrl: `/api/kkk/video/${encodeURIComponent(filename)}/events`
|
|
12959
13038
|
});
|
|
13039
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
12960
13040
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
12961
13041
|
res.send(htmlContent);
|
|
12962
13042
|
};
|
|
13043
|
+
videoPreviewEventsRouter = (req, res) => {
|
|
13044
|
+
const filenameParam = req.params.filename;
|
|
13045
|
+
const filename = Array.isArray(filenameParam) ? filenameParam[0] : filenameParam;
|
|
13046
|
+
if (!filename) {
|
|
13047
|
+
createNotFoundResponse(res, "无效的文件名");
|
|
13048
|
+
return;
|
|
13049
|
+
}
|
|
13050
|
+
if (path.basename(filename) !== filename || filename.includes("/") || filename.includes("\\")) {
|
|
13051
|
+
createNotFoundResponse(res, "无效的文件名");
|
|
13052
|
+
return;
|
|
13053
|
+
}
|
|
13054
|
+
const previewInfo = Common.getVideoPreview(filename);
|
|
13055
|
+
if (!previewInfo) {
|
|
13056
|
+
createNotFoundResponse(res, "预览信息不存在");
|
|
13057
|
+
return;
|
|
13058
|
+
}
|
|
13059
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
13060
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
13061
|
+
res.setHeader("Connection", "keep-alive");
|
|
13062
|
+
res.flushHeaders?.();
|
|
13063
|
+
const sendPayload = () => {
|
|
13064
|
+
const now = Date.now();
|
|
13065
|
+
const remainingMs = previewInfo.expireAt ? Math.max(previewInfo.expireAt - now, 0) : null;
|
|
13066
|
+
const fileMissing = previewInfo.filePath ? !fs.existsSync(previewInfo.filePath) : false;
|
|
13067
|
+
const removed = Boolean(previewInfo.removedAt) || previewInfo.removeCache && remainingMs === 0 && fileMissing;
|
|
13068
|
+
if (removed && !previewInfo.removedAt) Common.markVideoPreviewRemoved(previewInfo.filename);
|
|
13069
|
+
const payload = {
|
|
13070
|
+
filename: previewInfo.filename,
|
|
13071
|
+
filePath: previewInfo.filePath,
|
|
13072
|
+
removeCache: previewInfo.removeCache,
|
|
13073
|
+
createdAt: previewInfo.createdAt,
|
|
13074
|
+
expireAt: previewInfo.expireAt,
|
|
13075
|
+
remainingMs,
|
|
13076
|
+
removed,
|
|
13077
|
+
serverNow: now
|
|
13078
|
+
};
|
|
13079
|
+
res.write(`data: ${JSON.stringify(payload)}\n\n`);
|
|
13080
|
+
};
|
|
13081
|
+
sendPayload();
|
|
13082
|
+
const timer = setInterval(sendPayload, 1e3);
|
|
13083
|
+
res.on("close", () => {
|
|
13084
|
+
clearInterval(timer);
|
|
13085
|
+
});
|
|
13086
|
+
};
|
|
12963
13087
|
});
|
|
12964
13088
|
var import_lib, import_dist, server, proxyOptions, app$1;
|
|
12965
13089
|
var init_Register = __esmMin(async () => {
|
|
@@ -12998,6 +13122,7 @@ var init_Register = __esmMin(async () => {
|
|
|
12998
13122
|
} }).startServer(Config.app.APIServerPort);
|
|
12999
13123
|
app$1.get("/stream/:filename", videoStreamRouter);
|
|
13000
13124
|
app$1.get("/video/:filename", getVideoRouter);
|
|
13125
|
+
app$1.get("/video/:filename/events", videoPreviewEventsRouter);
|
|
13001
13126
|
app$1.use("/v1", apiRouter);
|
|
13002
13127
|
app.use("/api/kkk", app$1);
|
|
13003
13128
|
});
|
|
@@ -13916,7 +14041,7 @@ const DouyinWeb = (all) => [components.accordion.create("douyin", {
|
|
|
13916
14041
|
label: "合辑 Live 图 BGM 合并方式",
|
|
13917
14042
|
orientation: "horizontal",
|
|
13918
14043
|
defaultValue: all.douyin.liveImageMergeMode.toString(),
|
|
13919
|
-
isDisabled: !all.douyin.switch,
|
|
14044
|
+
isDisabled: !all.douyin.switch || all.app.livePhotoMode === "livephoto_only",
|
|
13920
14045
|
radio: [components.radio.create("liveImageMergeMode:radio-1", {
|
|
13921
14046
|
label: "连续",
|
|
13922
14047
|
value: "continuous",
|
|
@@ -14584,27 +14709,67 @@ const webConfig = defineConfig({
|
|
|
14584
14709
|
description: "Live Photo 兼容设置",
|
|
14585
14710
|
descPosition: 20
|
|
14586
14711
|
}),
|
|
14712
|
+
components.radio.group("livePhotoMode", {
|
|
14713
|
+
label: "Live Photo 处理和发送方式",
|
|
14714
|
+
description: "解析遇到实况图时的处理和发送方式。注意:生成视频性能开销大,2C2G 服务器单张约需 20 秒",
|
|
14715
|
+
orientation: "horizontal",
|
|
14716
|
+
defaultValue: all.app.livePhotoMode || "video_and_livephoto",
|
|
14717
|
+
radio: [
|
|
14718
|
+
components.radio.create("livePhotoMode-video-and-livephoto", {
|
|
14719
|
+
label: "视频 + 实况图",
|
|
14720
|
+
description: "生成并发送仿 iPhone Live Photo 播放效果的视频(播放三次)+ 对应系统的实况图",
|
|
14721
|
+
value: "video_and_livephoto"
|
|
14722
|
+
}),
|
|
14723
|
+
components.radio.create("livePhotoMode-video-only", {
|
|
14724
|
+
label: "仅视频",
|
|
14725
|
+
description: "仅生成并发送仿 iPhone Live Photo 播放效果的视频(播放三次)",
|
|
14726
|
+
value: "video_only"
|
|
14727
|
+
}),
|
|
14728
|
+
components.radio.create("livePhotoMode-livephoto-only", {
|
|
14729
|
+
label: "仅实况图",
|
|
14730
|
+
description: "仅生成并发送对应系统的实况图,性能开销小",
|
|
14731
|
+
value: "livephoto_only"
|
|
14732
|
+
})
|
|
14733
|
+
]
|
|
14734
|
+
}),
|
|
14587
14735
|
components.radio.group("livePhotoSystem", {
|
|
14588
14736
|
label: "Live Photo 静态图兼容系统",
|
|
14589
|
-
description: "当解析到作品/动态包含 Live Photo 时,合并转发里发送的 Live Photo
|
|
14737
|
+
description: "当解析到作品/动态包含 Live Photo 时,合并转发里发送的 Live Photo 静态图按所选系统生成。推荐 OPPO,兼容性最广",
|
|
14590
14738
|
orientation: "horizontal",
|
|
14591
|
-
defaultValue: all.app.livePhotoSystem || "
|
|
14739
|
+
defaultValue: all.app.livePhotoSystem || "oppo",
|
|
14740
|
+
isDisabled: all.app.livePhotoMode === "video_only",
|
|
14592
14741
|
radio: [
|
|
14593
14742
|
components.radio.create("livePhotoSystem-google", {
|
|
14594
14743
|
label: "Google",
|
|
14744
|
+
description: "Google Motion Photo 格式",
|
|
14595
14745
|
value: "google"
|
|
14596
14746
|
}),
|
|
14597
14747
|
components.radio.create("livePhotoSystem-xiaomi", {
|
|
14598
14748
|
label: "小米(HyperOS)",
|
|
14749
|
+
description: "兼容小米(任何版本)和 Google,但无法被 OPPO 识别",
|
|
14599
14750
|
value: "xiaomi"
|
|
14600
14751
|
}),
|
|
14601
14752
|
components.radio.create("livePhotoSystem-oppo", {
|
|
14602
14753
|
label: "OPPO(ColorOS)",
|
|
14754
|
+
description: "推荐,兼容 OPPO、小米(较新版本)和 Google",
|
|
14603
14755
|
value: "oppo"
|
|
14604
14756
|
}),
|
|
14605
14757
|
components.radio.create("livePhotoSystem-huawei-honor", {
|
|
14606
14758
|
label: "华为/荣耀(HarmonyOS/MagicOS)",
|
|
14759
|
+
description: "理论可行但未实测(作者无对应设备)",
|
|
14607
14760
|
value: "huawei_honor"
|
|
14761
|
+
}),
|
|
14762
|
+
components.radio.create("livePhotoSystem-vivo", {
|
|
14763
|
+
label: "vivo(Origin OS)",
|
|
14764
|
+
description: "需要独立的图片和同名视频文件,暂不支持",
|
|
14765
|
+
value: "vivo",
|
|
14766
|
+
isDisabled: true
|
|
14767
|
+
}),
|
|
14768
|
+
components.radio.create("livePhotoSystem-iphone", {
|
|
14769
|
+
label: "iPhone(iOS)",
|
|
14770
|
+
description: "需要独立的图片和同名视频文件,暂不支持",
|
|
14771
|
+
value: "iphone",
|
|
14772
|
+
isDisabled: true
|
|
14608
14773
|
})
|
|
14609
14774
|
]
|
|
14610
14775
|
}),
|
|
@@ -15963,7 +16128,6 @@ var Bilibili = class extends Base {
|
|
|
15963
16128
|
});
|
|
15964
16129
|
if (livePhoto.filepath) {
|
|
15965
16130
|
const outputPath = Common.tempDri.video + `Bilibili_Live_${Date.now()}_${index}.mp4`;
|
|
15966
|
-
let success;
|
|
15967
16131
|
const staticImg = await downloadFile(img$2.url, {
|
|
15968
16132
|
title: `Bilibili_static_${Date.now()}_${index}.jpg`,
|
|
15969
16133
|
headers: BASE_HEADERS,
|
|
@@ -15973,28 +16137,34 @@ var Bilibili = class extends Base {
|
|
|
15973
16137
|
filepath: staticImg.filepath,
|
|
15974
16138
|
totalBytes: 0
|
|
15975
16139
|
});
|
|
16140
|
+
const livePhotoMode = Config.app.livePhotoMode ?? "video_and_livephoto";
|
|
16141
|
+
const shouldGenerateVideo = livePhotoMode === "video_and_livephoto" || livePhotoMode === "video_only";
|
|
16142
|
+
const shouldGenerateLivePhoto = livePhotoMode === "video_and_livephoto" || livePhotoMode === "livephoto_only";
|
|
15976
16143
|
const loopCount = 3;
|
|
15977
16144
|
if (!staticImg.filepath) {
|
|
15978
16145
|
await Common.removeFile(livePhoto.filepath, true);
|
|
15979
16146
|
continue;
|
|
15980
16147
|
}
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
16148
|
+
if (shouldGenerateVideo) {
|
|
16149
|
+
if ((await loopVideoWithTransition({
|
|
16150
|
+
inputPath: livePhoto.filepath,
|
|
16151
|
+
outputPath,
|
|
16152
|
+
loopCount,
|
|
16153
|
+
staticImagePath: staticImg.filepath,
|
|
16154
|
+
transitionEnabled: loopCount > 1
|
|
16155
|
+
})).success) {
|
|
16156
|
+
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
16157
|
+
fs.renameSync(outputPath, filePath);
|
|
16158
|
+
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
16159
|
+
temp.push({
|
|
16160
|
+
filepath: filePath,
|
|
16161
|
+
totalBytes: 0
|
|
16162
|
+
});
|
|
16163
|
+
const videoPath = Config.upload.videoSendMode === "base64" ? `base64://${fs.readFileSync(filePath).toString("base64")}` : `file://${filePath}`;
|
|
16164
|
+
imgArray.push(segment.video(videoPath));
|
|
16165
|
+
}
|
|
16166
|
+
}
|
|
16167
|
+
if (shouldGenerateLivePhoto) {
|
|
15998
16168
|
let hasPushedMotionPhotoCover = false;
|
|
15999
16169
|
if (staticImg.filepath) {
|
|
16000
16170
|
const motionPhotoCoverPath = Common.tempDri.images + `MVIMG_${format(/* @__PURE__ */ new Date(), "yyyyMMdd_HHmmss_SSS")}_${index}.jpg`;
|
|
@@ -16016,9 +16186,9 @@ var Bilibili = class extends Base {
|
|
|
16016
16186
|
const imageUrl = await processImageUrl(img$2.url, title, index);
|
|
16017
16187
|
imgArray.push(segment.image(imageUrl));
|
|
16018
16188
|
}
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16189
|
+
}
|
|
16190
|
+
logger.mark("正在尝试删除缓存文件");
|
|
16191
|
+
await Common.removeFile(livePhoto.filepath, true);
|
|
16022
16192
|
}
|
|
16023
16193
|
} else {
|
|
16024
16194
|
const imageUrl = await processImageUrl(img$2.url, title, index);
|
|
@@ -17806,27 +17976,34 @@ var Bilibilipush = class extends Base {
|
|
|
17806
17976
|
filepath: staticImg.filepath,
|
|
17807
17977
|
totalBytes: 0
|
|
17808
17978
|
});
|
|
17979
|
+
const livePhotoMode = Config.app.livePhotoMode ?? "video_and_livephoto";
|
|
17980
|
+
const shouldGenerateVideo = livePhotoMode === "video_and_livephoto" || livePhotoMode === "video_only";
|
|
17981
|
+
const shouldGenerateLivePhoto = livePhotoMode === "video_and_livephoto" || livePhotoMode === "livephoto_only";
|
|
17809
17982
|
const loopCount = 3;
|
|
17810
17983
|
if (!staticImg.filepath) {
|
|
17811
17984
|
await Common.removeFile(livePhoto.filepath, true);
|
|
17812
17985
|
continue;
|
|
17813
17986
|
}
|
|
17814
|
-
if (
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17987
|
+
if (shouldGenerateVideo) {
|
|
17988
|
+
if ((await loopVideoWithTransition({
|
|
17989
|
+
inputPath: livePhoto.filepath,
|
|
17990
|
+
outputPath,
|
|
17991
|
+
loopCount,
|
|
17992
|
+
staticImagePath: staticImg.filepath,
|
|
17993
|
+
transitionEnabled: loopCount > 1
|
|
17994
|
+
})).success) {
|
|
17995
|
+
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
17996
|
+
fs.renameSync(outputPath, filePath);
|
|
17997
|
+
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
17998
|
+
temp.push({
|
|
17999
|
+
filepath: filePath,
|
|
18000
|
+
totalBytes: 0
|
|
18001
|
+
});
|
|
18002
|
+
const videoPath = Config.upload.videoSendMode === "base64" ? `base64://${fs.readFileSync(filePath).toString("base64")}` : `file://${filePath}`;
|
|
18003
|
+
imgArray.push(segment.video(videoPath));
|
|
18004
|
+
}
|
|
18005
|
+
}
|
|
18006
|
+
if (shouldGenerateLivePhoto) {
|
|
17830
18007
|
let hasPushedMotionPhotoCover = false;
|
|
17831
18008
|
if (staticImg.filepath) {
|
|
17832
18009
|
const motionPhotoCoverPath = Common.tempDri.images + `MVIMG_${Date.now()}_${index}.jpg`;
|
|
@@ -17848,11 +18025,10 @@ var Bilibilipush = class extends Base {
|
|
|
17848
18025
|
const imageUrl = await processImageUrl(imageSrc, title, index);
|
|
17849
18026
|
imgArray.push(segment.image(imageUrl));
|
|
17850
18027
|
}
|
|
17851
|
-
logger.mark("正在尝试删除缓存文件");
|
|
17852
|
-
await Common.removeFile(livePhoto.filepath, true);
|
|
17853
|
-
continue;
|
|
17854
18028
|
}
|
|
18029
|
+
logger.mark("正在尝试删除缓存文件");
|
|
17855
18030
|
await Common.removeFile(livePhoto.filepath, true);
|
|
18031
|
+
continue;
|
|
17856
18032
|
}
|
|
17857
18033
|
}
|
|
17858
18034
|
if (imageSrc) {
|
|
@@ -18733,56 +18909,61 @@ var DouYin = class extends Base {
|
|
|
18733
18909
|
});
|
|
18734
18910
|
staticImgPath = staticImg.filepath ?? "";
|
|
18735
18911
|
}
|
|
18736
|
-
const
|
|
18737
|
-
const
|
|
18738
|
-
const
|
|
18739
|
-
|
|
18740
|
-
|
|
18741
|
-
|
|
18742
|
-
|
|
18743
|
-
|
|
18744
|
-
|
|
18745
|
-
|
|
18746
|
-
|
|
18747
|
-
|
|
18748
|
-
|
|
18749
|
-
|
|
18750
|
-
|
|
18751
|
-
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
18752
|
-
fs.renameSync(outputPath, filePath);
|
|
18753
|
-
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
18754
|
-
temp.push({
|
|
18755
|
-
filepath: filePath,
|
|
18756
|
-
totalBytes: 0
|
|
18912
|
+
const livePhotoMode = Config.app.livePhotoMode ?? "video_and_livephoto";
|
|
18913
|
+
const shouldGenerateVideo = livePhotoMode === "video_and_livephoto" || livePhotoMode === "video_only";
|
|
18914
|
+
const shouldGenerateLivePhoto = livePhotoMode === "video_and_livephoto" || livePhotoMode === "livephoto_only";
|
|
18915
|
+
if (shouldGenerateVideo) {
|
|
18916
|
+
const transitionEnabled = loopCount > 1 && Boolean(staticImgPath);
|
|
18917
|
+
const safeStaticPath = staticImgPath || liveimg.filepath;
|
|
18918
|
+
const result = await loopVideoWithTransition({
|
|
18919
|
+
inputPath: liveimg.filepath,
|
|
18920
|
+
outputPath,
|
|
18921
|
+
loopCount,
|
|
18922
|
+
staticImagePath: safeStaticPath,
|
|
18923
|
+
transitionEnabled,
|
|
18924
|
+
bgmPath: liveimgbgm?.filepath,
|
|
18925
|
+
mergeMode,
|
|
18926
|
+
context: bgmContext ?? void 0
|
|
18757
18927
|
});
|
|
18758
|
-
const
|
|
18759
|
-
|
|
18760
|
-
if (
|
|
18761
|
-
|
|
18762
|
-
|
|
18763
|
-
|
|
18764
|
-
|
|
18765
|
-
|
|
18766
|
-
|
|
18767
|
-
|
|
18768
|
-
|
|
18769
|
-
|
|
18770
|
-
|
|
18771
|
-
|
|
18772
|
-
|
|
18773
|
-
|
|
18774
|
-
|
|
18775
|
-
|
|
18776
|
-
|
|
18777
|
-
|
|
18778
|
-
|
|
18779
|
-
|
|
18780
|
-
|
|
18928
|
+
const success = result.success;
|
|
18929
|
+
if (mergeMode === "continuous" && result.context) bgmContext = result.context;
|
|
18930
|
+
if (success) {
|
|
18931
|
+
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
18932
|
+
fs.renameSync(outputPath, filePath);
|
|
18933
|
+
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
18934
|
+
temp.push({
|
|
18935
|
+
filepath: filePath,
|
|
18936
|
+
totalBytes: 0
|
|
18937
|
+
});
|
|
18938
|
+
const videoPath = Config.upload.videoSendMode === "base64" ? `base64://${fs.readFileSync(filePath).toString("base64")}` : `file://${filePath}`;
|
|
18939
|
+
processedImages.push(segment.video(videoPath));
|
|
18940
|
+
}
|
|
18941
|
+
}
|
|
18942
|
+
if (shouldGenerateLivePhoto && imageItem.clip_type === 5 && imageItem.url_list?.[0]) {
|
|
18943
|
+
let hasPushedMotionPhotoCover = false;
|
|
18944
|
+
if (staticImgPath) {
|
|
18945
|
+
const motionPhotoCoverPath = Common.tempDri.images + `MVIMG_${format(/* @__PURE__ */ new Date(), "yyyyMMdd_HHmmss_SSS")}_${index}.jpg`;
|
|
18946
|
+
if (await buildGoogleMotionPhoto({
|
|
18947
|
+
imagePath: staticImgPath,
|
|
18948
|
+
videoPath: liveimg.filepath,
|
|
18949
|
+
outputPath: motionPhotoCoverPath
|
|
18950
|
+
})) {
|
|
18951
|
+
temp.push({
|
|
18952
|
+
filepath: motionPhotoCoverPath,
|
|
18953
|
+
totalBytes: 0
|
|
18954
|
+
});
|
|
18955
|
+
const motionPhotoCover = Config.upload.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
|
|
18956
|
+
processedImages.push(segment.image(motionPhotoCover));
|
|
18957
|
+
hasPushedMotionPhotoCover = true;
|
|
18781
18958
|
}
|
|
18782
18959
|
}
|
|
18783
|
-
|
|
18784
|
-
|
|
18785
|
-
|
|
18960
|
+
if (!hasPushedMotionPhotoCover) {
|
|
18961
|
+
const imageUrl = await processImageUrl(imageItem.url_list[0], g_title, index);
|
|
18962
|
+
processedImages.push(segment.image(imageUrl));
|
|
18963
|
+
}
|
|
18964
|
+
}
|
|
18965
|
+
logger.mark("正在尝试删除缓存文件");
|
|
18966
|
+
await Common.removeFile(liveimg.filepath, true);
|
|
18786
18967
|
}
|
|
18787
18968
|
}
|
|
18788
18969
|
const Element = common.makeForward(processedImages, Config.app.fakeForward ? this.e.sender.userId : this.e.bot.account.selfId, Config.app.fakeForward ? this.e.sender.nick : this.e.bot.account.name);
|
|
@@ -18873,56 +19054,61 @@ var DouYin = class extends Base {
|
|
|
18873
19054
|
});
|
|
18874
19055
|
staticImgPath = staticImg.filepath ?? "";
|
|
18875
19056
|
}
|
|
18876
|
-
const
|
|
18877
|
-
const
|
|
18878
|
-
const
|
|
18879
|
-
|
|
18880
|
-
|
|
18881
|
-
|
|
18882
|
-
|
|
18883
|
-
|
|
18884
|
-
|
|
18885
|
-
|
|
18886
|
-
|
|
18887
|
-
|
|
18888
|
-
|
|
18889
|
-
|
|
18890
|
-
|
|
18891
|
-
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
18892
|
-
fs.renameSync(outputPath, filePath);
|
|
18893
|
-
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
18894
|
-
temp.push({
|
|
18895
|
-
filepath: filePath,
|
|
18896
|
-
totalBytes: 0
|
|
19057
|
+
const livePhotoMode = Config.app.livePhotoMode ?? "video_and_livephoto";
|
|
19058
|
+
const shouldGenerateVideo = livePhotoMode === "video_and_livephoto" || livePhotoMode === "video_only";
|
|
19059
|
+
const shouldGenerateLivePhoto = livePhotoMode === "video_and_livephoto" || livePhotoMode === "livephoto_only";
|
|
19060
|
+
if (shouldGenerateVideo) {
|
|
19061
|
+
const transitionEnabled = loopCount > 1 && Boolean(staticImgPath);
|
|
19062
|
+
const safeStaticPath = staticImgPath || livePhoto.filepath;
|
|
19063
|
+
const result = await loopVideoWithTransition({
|
|
19064
|
+
inputPath: livePhoto.filepath,
|
|
19065
|
+
outputPath,
|
|
19066
|
+
loopCount,
|
|
19067
|
+
staticImagePath: safeStaticPath,
|
|
19068
|
+
transitionEnabled,
|
|
19069
|
+
bgmPath: liveimgbgm?.filepath,
|
|
19070
|
+
mergeMode,
|
|
19071
|
+
context: bgmContext ?? void 0
|
|
18897
19072
|
});
|
|
18898
|
-
const
|
|
18899
|
-
|
|
18900
|
-
if (
|
|
18901
|
-
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
|
|
18913
|
-
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
18917
|
-
|
|
18918
|
-
|
|
18919
|
-
|
|
18920
|
-
|
|
19073
|
+
const success = result.success;
|
|
19074
|
+
if (mergeMode === "continuous" && result.context) bgmContext = result.context;
|
|
19075
|
+
if (success) {
|
|
19076
|
+
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
19077
|
+
fs.renameSync(outputPath, filePath);
|
|
19078
|
+
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
19079
|
+
temp.push({
|
|
19080
|
+
filepath: filePath,
|
|
19081
|
+
totalBytes: 0
|
|
19082
|
+
});
|
|
19083
|
+
const videoPath = Config.upload.videoSendMode === "base64" ? `base64://${fs.readFileSync(filePath).toString("base64")}` : `file://${filePath}`;
|
|
19084
|
+
images.push(segment.video(videoPath));
|
|
19085
|
+
}
|
|
19086
|
+
}
|
|
19087
|
+
if (shouldGenerateLivePhoto && item.clip_type === 5 && item.url_list?.[0]) {
|
|
19088
|
+
let hasPushedMotionPhotoCover = false;
|
|
19089
|
+
if (staticImgPath) {
|
|
19090
|
+
const motionPhotoCoverPath = Common.tempDri.images + `MVIMG_${format(/* @__PURE__ */ new Date(), "yyyyMMdd_HHmmss_SSS")}_${index}.jpg`;
|
|
19091
|
+
if (await buildGoogleMotionPhoto({
|
|
19092
|
+
imagePath: staticImgPath,
|
|
19093
|
+
videoPath: livePhoto.filepath,
|
|
19094
|
+
outputPath: motionPhotoCoverPath
|
|
19095
|
+
})) {
|
|
19096
|
+
temp.push({
|
|
19097
|
+
filepath: motionPhotoCoverPath,
|
|
19098
|
+
totalBytes: 0
|
|
19099
|
+
});
|
|
19100
|
+
const motionPhotoCover = Config.upload.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
|
|
19101
|
+
images.push(segment.image(motionPhotoCover));
|
|
19102
|
+
hasPushedMotionPhotoCover = true;
|
|
18921
19103
|
}
|
|
18922
19104
|
}
|
|
18923
|
-
|
|
18924
|
-
|
|
18925
|
-
|
|
19105
|
+
if (!hasPushedMotionPhotoCover) {
|
|
19106
|
+
const imageUrl = await processImageUrl(item.url_list[0], g_title, index);
|
|
19107
|
+
images.push(segment.image(imageUrl));
|
|
19108
|
+
}
|
|
19109
|
+
}
|
|
19110
|
+
logger.mark("正在尝试删除缓存文件");
|
|
19111
|
+
await Common.removeFile(livePhoto.filepath, true);
|
|
18926
19112
|
}
|
|
18927
19113
|
}
|
|
18928
19114
|
const Element = common.makeForward(images, Config.app.fakeForward ? this.e.sender.userId : this.e.bot.account.selfId, Config.app.fakeForward ? this.e.sender.nick : this.e.bot.account.name);
|
|
@@ -20027,56 +20213,61 @@ var DouYinpush = class extends Base {
|
|
|
20027
20213
|
});
|
|
20028
20214
|
staticImgPath = staticImg.filepath ?? "";
|
|
20029
20215
|
}
|
|
20030
|
-
const
|
|
20031
|
-
const
|
|
20032
|
-
const
|
|
20033
|
-
|
|
20034
|
-
|
|
20035
|
-
|
|
20036
|
-
|
|
20037
|
-
|
|
20038
|
-
|
|
20039
|
-
|
|
20040
|
-
|
|
20041
|
-
|
|
20042
|
-
|
|
20043
|
-
|
|
20044
|
-
|
|
20045
|
-
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
20046
|
-
fs.renameSync(outputPath, filePath);
|
|
20047
|
-
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
20048
|
-
temp.push({
|
|
20049
|
-
filepath: filePath,
|
|
20050
|
-
totalBytes: 0
|
|
20216
|
+
const livePhotoMode = Config.app.livePhotoMode ?? "video_and_livephoto";
|
|
20217
|
+
const shouldGenerateVideo = livePhotoMode === "video_and_livephoto" || livePhotoMode === "video_only";
|
|
20218
|
+
const shouldGenerateLivePhoto = livePhotoMode === "video_and_livephoto" || livePhotoMode === "livephoto_only";
|
|
20219
|
+
if (shouldGenerateVideo) {
|
|
20220
|
+
const transitionEnabled = loopCount > 1 && Boolean(staticImgPath);
|
|
20221
|
+
const safeStaticPath = staticImgPath || liveimg.filepath;
|
|
20222
|
+
const result = await loopVideoWithTransition({
|
|
20223
|
+
inputPath: liveimg.filepath,
|
|
20224
|
+
outputPath,
|
|
20225
|
+
loopCount,
|
|
20226
|
+
staticImagePath: safeStaticPath,
|
|
20227
|
+
transitionEnabled,
|
|
20228
|
+
bgmPath: liveimgbgm?.filepath,
|
|
20229
|
+
mergeMode,
|
|
20230
|
+
context: bgmContext ?? void 0
|
|
20051
20231
|
});
|
|
20052
|
-
const
|
|
20053
|
-
|
|
20054
|
-
if (
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
|
|
20058
|
-
|
|
20059
|
-
|
|
20060
|
-
|
|
20061
|
-
|
|
20062
|
-
|
|
20063
|
-
|
|
20064
|
-
|
|
20065
|
-
|
|
20066
|
-
|
|
20067
|
-
|
|
20068
|
-
|
|
20069
|
-
|
|
20070
|
-
|
|
20071
|
-
|
|
20072
|
-
|
|
20073
|
-
|
|
20074
|
-
|
|
20232
|
+
const success = result.success;
|
|
20233
|
+
if (mergeMode === "continuous" && result.context) bgmContext = result.context;
|
|
20234
|
+
if (success) {
|
|
20235
|
+
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
20236
|
+
fs.renameSync(outputPath, filePath);
|
|
20237
|
+
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
20238
|
+
temp.push({
|
|
20239
|
+
filepath: filePath,
|
|
20240
|
+
totalBytes: 0
|
|
20241
|
+
});
|
|
20242
|
+
const videoPath = Config.upload.videoSendMode === "base64" ? `base64://${fs.readFileSync(filePath).toString("base64")}` : `file://${filePath}`;
|
|
20243
|
+
images.push(segment.video(videoPath));
|
|
20244
|
+
}
|
|
20245
|
+
}
|
|
20246
|
+
if (shouldGenerateLivePhoto && item.clip_type === 5 && item.url_list?.[0]) {
|
|
20247
|
+
let hasPushedMotionPhotoCover = false;
|
|
20248
|
+
if (staticImgPath) {
|
|
20249
|
+
const motionPhotoCoverPath = Common.tempDri.images + `MVIMG_${format(/* @__PURE__ */ new Date(), "yyyyMMdd_HHmmss_SSS")}_${index}.jpg`;
|
|
20250
|
+
if (await buildGoogleMotionPhoto({
|
|
20251
|
+
imagePath: staticImgPath,
|
|
20252
|
+
videoPath: liveimg.filepath,
|
|
20253
|
+
outputPath: motionPhotoCoverPath
|
|
20254
|
+
})) {
|
|
20255
|
+
temp.push({
|
|
20256
|
+
filepath: motionPhotoCoverPath,
|
|
20257
|
+
totalBytes: 0
|
|
20258
|
+
});
|
|
20259
|
+
const motionPhotoCover = Config.upload.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
|
|
20260
|
+
images.push(segment.image(motionPhotoCover));
|
|
20261
|
+
hasPushedMotionPhotoCover = true;
|
|
20075
20262
|
}
|
|
20076
20263
|
}
|
|
20077
|
-
|
|
20078
|
-
|
|
20079
|
-
|
|
20264
|
+
if (!hasPushedMotionPhotoCover) {
|
|
20265
|
+
const imageUrl = await processImageUrl(item.url_list[0], Detail_Data.desc, index);
|
|
20266
|
+
images.push(segment.image(imageUrl));
|
|
20267
|
+
}
|
|
20268
|
+
}
|
|
20269
|
+
logger.mark("正在尝试删除缓存文件");
|
|
20270
|
+
await Common.removeFile(liveimg.filepath, true);
|
|
20080
20271
|
}
|
|
20081
20272
|
}
|
|
20082
20273
|
const bot = karin$1.getBot(botId);
|
|
@@ -20135,56 +20326,61 @@ var DouYinpush = class extends Base {
|
|
|
20135
20326
|
});
|
|
20136
20327
|
staticImgPath = staticImg.filepath ?? "";
|
|
20137
20328
|
}
|
|
20138
|
-
const
|
|
20139
|
-
const
|
|
20140
|
-
const
|
|
20141
|
-
|
|
20142
|
-
|
|
20143
|
-
|
|
20144
|
-
|
|
20145
|
-
|
|
20146
|
-
|
|
20147
|
-
|
|
20148
|
-
|
|
20149
|
-
|
|
20150
|
-
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
20154
|
-
fs.renameSync(outputPath, filePath);
|
|
20155
|
-
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
20156
|
-
temp.push({
|
|
20157
|
-
filepath: filePath,
|
|
20158
|
-
totalBytes: 0
|
|
20329
|
+
const livePhotoMode = Config.app.livePhotoMode ?? "video_and_livephoto";
|
|
20330
|
+
const shouldGenerateVideo = livePhotoMode === "video_and_livephoto" || livePhotoMode === "video_only";
|
|
20331
|
+
const shouldGenerateLivePhoto = livePhotoMode === "video_and_livephoto" || livePhotoMode === "livephoto_only";
|
|
20332
|
+
if (shouldGenerateVideo) {
|
|
20333
|
+
const transitionEnabled = loopCount > 1 && Boolean(staticImgPath);
|
|
20334
|
+
const safeStaticPath = staticImgPath || liveimg.filepath;
|
|
20335
|
+
const result = await loopVideoWithTransition({
|
|
20336
|
+
inputPath: liveimg.filepath,
|
|
20337
|
+
outputPath,
|
|
20338
|
+
loopCount,
|
|
20339
|
+
staticImagePath: safeStaticPath,
|
|
20340
|
+
transitionEnabled,
|
|
20341
|
+
bgmPath: liveimgbgm?.filepath,
|
|
20342
|
+
mergeMode,
|
|
20343
|
+
context: bgmContext ?? void 0
|
|
20159
20344
|
});
|
|
20160
|
-
const
|
|
20161
|
-
|
|
20162
|
-
if (
|
|
20163
|
-
|
|
20164
|
-
|
|
20165
|
-
|
|
20166
|
-
|
|
20167
|
-
|
|
20168
|
-
|
|
20169
|
-
|
|
20170
|
-
|
|
20171
|
-
|
|
20172
|
-
|
|
20173
|
-
|
|
20174
|
-
|
|
20175
|
-
|
|
20176
|
-
|
|
20177
|
-
|
|
20178
|
-
|
|
20179
|
-
|
|
20180
|
-
|
|
20181
|
-
|
|
20182
|
-
|
|
20345
|
+
const success = result.success;
|
|
20346
|
+
if (mergeMode === "continuous" && result.context) bgmContext = result.context;
|
|
20347
|
+
if (success) {
|
|
20348
|
+
const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
|
|
20349
|
+
fs.renameSync(outputPath, filePath);
|
|
20350
|
+
logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
|
|
20351
|
+
temp.push({
|
|
20352
|
+
filepath: filePath,
|
|
20353
|
+
totalBytes: 0
|
|
20354
|
+
});
|
|
20355
|
+
const videoPath = Config.upload.videoSendMode === "base64" ? `base64://${fs.readFileSync(filePath).toString("base64")}` : `file://${filePath}`;
|
|
20356
|
+
processedImages.push(segment.video(videoPath));
|
|
20357
|
+
}
|
|
20358
|
+
}
|
|
20359
|
+
if (shouldGenerateLivePhoto && item.clip_type === 5 && item.url_list?.[0]) {
|
|
20360
|
+
let hasPushedMotionPhotoCover = false;
|
|
20361
|
+
if (staticImgPath) {
|
|
20362
|
+
const motionPhotoCoverPath = Common.tempDri.images + `MVIMG_${format(/* @__PURE__ */ new Date(), "yyyyMMdd_HHmmss_SSS")}_${index}.jpg`;
|
|
20363
|
+
if (await buildGoogleMotionPhoto({
|
|
20364
|
+
imagePath: staticImgPath,
|
|
20365
|
+
videoPath: liveimg.filepath,
|
|
20366
|
+
outputPath: motionPhotoCoverPath
|
|
20367
|
+
})) {
|
|
20368
|
+
temp.push({
|
|
20369
|
+
filepath: motionPhotoCoverPath,
|
|
20370
|
+
totalBytes: 0
|
|
20371
|
+
});
|
|
20372
|
+
const motionPhotoCover = Config.upload.imageSendMode === "base64" ? `base64://${fs.readFileSync(motionPhotoCoverPath).toString("base64")}` : `file://${motionPhotoCoverPath}`;
|
|
20373
|
+
processedImages.push(segment.image(motionPhotoCover));
|
|
20374
|
+
hasPushedMotionPhotoCover = true;
|
|
20183
20375
|
}
|
|
20184
20376
|
}
|
|
20185
|
-
|
|
20186
|
-
|
|
20187
|
-
|
|
20377
|
+
if (!hasPushedMotionPhotoCover) {
|
|
20378
|
+
const imageUrl = await processImageUrl(item.url_list[0], Detail_Data.desc, index);
|
|
20379
|
+
processedImages.push(segment.image(imageUrl));
|
|
20380
|
+
}
|
|
20381
|
+
}
|
|
20382
|
+
logger.mark("正在尝试删除缓存文件");
|
|
20383
|
+
await Common.removeFile(liveimg.filepath, true);
|
|
20188
20384
|
}
|
|
20189
20385
|
}
|
|
20190
20386
|
const bot = karin$1.getBot(botId);
|
|
@@ -20657,305 +20853,308 @@ var safeScreenshot = async (page, screenshotPath) => {
|
|
|
20657
20853
|
};
|
|
20658
20854
|
const douyinLogin = async (e) => {
|
|
20659
20855
|
const msg_id = [];
|
|
20660
|
-
|
|
20661
|
-
|
|
20662
|
-
|
|
20663
|
-
|
|
20664
|
-
|
|
20665
|
-
|
|
20666
|
-
|
|
20667
|
-
|
|
20668
|
-
|
|
20669
|
-
|
|
20670
|
-
|
|
20671
|
-
|
|
20672
|
-
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
|
|
20677
|
-
|
|
20678
|
-
|
|
20679
|
-
|
|
20680
|
-
|
|
20681
|
-
|
|
20682
|
-
|
|
20683
|
-
|
|
20684
|
-
|
|
20685
|
-
|
|
20686
|
-
|
|
20687
|
-
|
|
20688
|
-
|
|
20689
|
-
|
|
20690
|
-
|
|
20691
|
-
|
|
20692
|
-
|
|
20693
|
-
|
|
20694
|
-
|
|
20695
|
-
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
|
|
20701
|
-
|
|
20702
|
-
const
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
|
|
20856
|
+
const puppeteer = await snapka.launch({
|
|
20857
|
+
headless: "new",
|
|
20858
|
+
protocolTimeout: 6e4,
|
|
20859
|
+
args: [
|
|
20860
|
+
"--disable-blink-features=AutomationControlled",
|
|
20861
|
+
"--mute-audio",
|
|
20862
|
+
"--window-size=800,600",
|
|
20863
|
+
"--disable-gpu",
|
|
20864
|
+
"--no-sandbox",
|
|
20865
|
+
"--disable-setuid-sandbox",
|
|
20866
|
+
"--no-zygote",
|
|
20867
|
+
"--disable-extensions",
|
|
20868
|
+
"--disable-dev-shm-usage",
|
|
20869
|
+
"--disable-background-networking",
|
|
20870
|
+
"--disable-sync",
|
|
20871
|
+
"--disable-crash-reporter",
|
|
20872
|
+
"--disable-translate",
|
|
20873
|
+
"--disable-notifications",
|
|
20874
|
+
"--disable-device-discovery-notifications",
|
|
20875
|
+
"--disable-accelerated-2d-canvas",
|
|
20876
|
+
"--autoplay-policy=user-gesture-required",
|
|
20877
|
+
"--disable-web-security",
|
|
20878
|
+
"--disable-features=IsolateOrigins,site-per-process",
|
|
20879
|
+
"--disable-site-isolation-trials",
|
|
20880
|
+
"--disable-features=VizDisplayCompositor",
|
|
20881
|
+
"--js-flags=--max-old-space-size=128",
|
|
20882
|
+
"--disable-software-rasterizer",
|
|
20883
|
+
"--disable-webgl",
|
|
20884
|
+
"--disable-webgl2",
|
|
20885
|
+
"--disable-3d-apis",
|
|
20886
|
+
"--disable-accelerated-video-decode",
|
|
20887
|
+
"--disable-background-timer-throttling",
|
|
20888
|
+
"--disable-backgrounding-occluded-windows",
|
|
20889
|
+
"--disable-breakpad",
|
|
20890
|
+
"--disable-component-extensions-with-background-pages",
|
|
20891
|
+
"--disable-features=TranslateUI,BlinkGenPropertyTrees",
|
|
20892
|
+
"--disable-ipc-flooding-protection",
|
|
20893
|
+
"--disable-renderer-backgrounding"
|
|
20894
|
+
],
|
|
20895
|
+
ignoreDefaultArgs: ["--enable-automation"]
|
|
20896
|
+
});
|
|
20897
|
+
const getOperatingSystem = () => {
|
|
20898
|
+
const os$1 = platform();
|
|
20899
|
+
if (os$1 === "win32") return "windows";
|
|
20900
|
+
if (os$1 === "darwin") return "macos";
|
|
20901
|
+
return "linux";
|
|
20902
|
+
};
|
|
20903
|
+
const page = await newInjectedPage(puppeteer.browser, { fingerprintOptions: {
|
|
20904
|
+
devices: ["desktop"],
|
|
20905
|
+
operatingSystems: [getOperatingSystem()]
|
|
20906
|
+
} });
|
|
20907
|
+
await page.setRequestInterception(true);
|
|
20908
|
+
page.on("request", async (request) => {
|
|
20909
|
+
const resourceType = request.resourceType();
|
|
20910
|
+
const url = request.url();
|
|
20911
|
+
if (url.includes("passport") || url.includes("login") || url.includes("qrconnect") || url.includes("qrcode")) logger.debug(`[请求] ${resourceType}: ${url}`);
|
|
20912
|
+
if (resourceType === "media" || resourceType === "font" || resourceType === "stylesheet" || /\.(mp4|webm|m3u8|flv|avi|mov|wmv|mkv)(\?|$)/i.test(url) || url.includes("/aweme/") || url.includes("/video/") || url.includes("v.douyin.com") || resourceType === "image" && !url.includes("qrcode") && !url.includes("data:image") && (url.includes(".jpg") || url.includes(".jpeg") || url.includes(".webp"))) {
|
|
20913
|
+
if (url.includes("passport") || url.includes("login") || url.includes("qrconnect")) logger.warn(`[拦截] 登录相关请求被拦截: ${url}`);
|
|
20914
|
+
request.abort();
|
|
20915
|
+
} else request.continue();
|
|
20916
|
+
});
|
|
20917
|
+
await page.evaluateOnNewDocument(() => {
|
|
20918
|
+
HTMLMediaElement.prototype.play = function() {
|
|
20919
|
+
return Promise.reject(/* @__PURE__ */ new Error("Video playback blocked"));
|
|
20707
20920
|
};
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
20711
|
-
|
|
20712
|
-
|
|
20713
|
-
|
|
20714
|
-
|
|
20715
|
-
|
|
20716
|
-
|
|
20717
|
-
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20721
|
-
|
|
20722
|
-
await
|
|
20723
|
-
|
|
20724
|
-
|
|
20725
|
-
|
|
20726
|
-
|
|
20727
|
-
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
};
|
|
20732
|
-
});
|
|
20733
|
-
await page.goto("https://www.douyin.com", {
|
|
20734
|
-
timeout: 12e4,
|
|
20735
|
-
waitUntil: "domcontentloaded"
|
|
20736
|
-
});
|
|
20737
|
-
let qrCodeData;
|
|
20738
|
-
try {
|
|
20739
|
-
logger.mark("开始等待二维码加载...");
|
|
20740
|
-
qrCodeData = await Promise.race([waitQrcode(page), new Promise((_$1, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("QR_CODE_TIMEOUT")), 6e4))]);
|
|
20741
|
-
logger.mark("二维码获取成功");
|
|
20742
|
-
} catch (error) {
|
|
20743
|
-
if (error.message === "QR_CODE_TIMEOUT") {
|
|
20744
|
-
logger.warn("获取二维码超时");
|
|
20745
|
-
await safeScreenshot(page, path.join(karinPathTemp, Root.pluginName, "DouyinLoginQrcodeError.png"));
|
|
20746
|
-
await e.reply("获取二维码超时,请稍后重试", { reply: true });
|
|
20747
|
-
} else {
|
|
20748
|
-
logger.error("获取二维码失败:", error);
|
|
20749
|
-
await e.reply("获取二维码失败,请查看控制台日志", { reply: true });
|
|
20750
|
-
}
|
|
20751
|
-
await puppeteer.browser.close();
|
|
20752
|
-
return true;
|
|
20921
|
+
if (window.MediaSource) window.MediaSource = void 0;
|
|
20922
|
+
window.IntersectionObserver = class {
|
|
20923
|
+
observe() {}
|
|
20924
|
+
unobserve() {}
|
|
20925
|
+
disconnect() {}
|
|
20926
|
+
};
|
|
20927
|
+
});
|
|
20928
|
+
await page.goto("https://www.douyin.com", {
|
|
20929
|
+
timeout: 12e4,
|
|
20930
|
+
waitUntil: "domcontentloaded"
|
|
20931
|
+
});
|
|
20932
|
+
let qrCodeData;
|
|
20933
|
+
try {
|
|
20934
|
+
logger.mark("开始等待二维码加载...");
|
|
20935
|
+
qrCodeData = await Promise.race([waitQrcode(page), new Promise((_$1, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("QR_CODE_TIMEOUT")), 6e4))]);
|
|
20936
|
+
logger.mark("二维码获取成功");
|
|
20937
|
+
} catch (error) {
|
|
20938
|
+
if (error.message === "QR_CODE_TIMEOUT") {
|
|
20939
|
+
logger.warn("获取二维码超时");
|
|
20940
|
+
await safeScreenshot(page, path.join(karinPathTemp, Root.pluginName, "DouyinLoginQrcodeError.png"));
|
|
20941
|
+
await e.reply("获取二维码超时,请稍后重试", { reply: true });
|
|
20942
|
+
} else {
|
|
20943
|
+
logger.error("获取二维码失败:", error);
|
|
20944
|
+
await e.reply("获取二维码失败,请查看控制台日志", { reply: true });
|
|
20753
20945
|
}
|
|
20754
|
-
|
|
20755
|
-
|
|
20756
|
-
|
|
20757
|
-
|
|
20758
|
-
|
|
20759
|
-
|
|
20760
|
-
|
|
20761
|
-
|
|
20762
|
-
|
|
20763
|
-
|
|
20764
|
-
|
|
20765
|
-
|
|
20766
|
-
|
|
20767
|
-
|
|
20768
|
-
|
|
20769
|
-
|
|
20770
|
-
|
|
20771
|
-
|
|
20772
|
-
logger.mark("开始等待用户扫码登录...");
|
|
20773
|
-
const loginResult = await Promise.race([new Promise((resolve$1) => {
|
|
20774
|
-
const timer = setTimeout(async () => {
|
|
20775
|
-
logger.warn("扫码登录超时(2分钟),撤回二维码消息");
|
|
20776
|
-
await Promise.all(msg_id.map(async (id) => {
|
|
20777
|
-
await e.bot.recallMsg(e.contact, id);
|
|
20778
|
-
}));
|
|
20779
|
-
resolve$1(false);
|
|
20780
|
-
}, 120 * 1e3);
|
|
20781
|
-
let secondVerifyHandled = false;
|
|
20782
|
-
let scannedHandled = false;
|
|
20783
|
-
let responseCount = 0;
|
|
20784
|
-
page.on("response", async (response) => {
|
|
20785
|
-
responseCount++;
|
|
20786
|
-
const url = response.url();
|
|
20787
|
-
if (responseCount % 10 === 0) logger.debug(`[心跳] 已收到 ${responseCount} 个响应`);
|
|
20788
|
-
if (url.includes("passport") || url.includes("login") || url.includes("qrconnect") || url.includes("qrcode")) logger.debug(`[响应] 登录相关请求: ${url}, status: ${response.status()}`);
|
|
20946
|
+
await puppeteer.browser.close();
|
|
20947
|
+
return true;
|
|
20948
|
+
}
|
|
20949
|
+
let gcInterval;
|
|
20950
|
+
try {
|
|
20951
|
+
const loginQRcode = await Render("douyin/qrcodeImg", qrCodeData.url ? { share_url: qrCodeData.url } : { qrCodeDataUrl: qrCodeData.originalImage });
|
|
20952
|
+
const base64Data = loginQRcode[0]?.file;
|
|
20953
|
+
if (!base64Data) throw new Error("生成二维码图片失败");
|
|
20954
|
+
const cleanBase64 = base64Data.replace(/^base64:\/\//, "");
|
|
20955
|
+
const buffer = Buffer.from(cleanBase64, "base64");
|
|
20956
|
+
fs.writeFileSync(`${Common.tempDri.default}DouyinLoginQrcode.png`, buffer);
|
|
20957
|
+
const message2 = await e.reply(loginQRcode, { reply: true });
|
|
20958
|
+
logger.debug("二维码图片消息ID:", message2.messageId);
|
|
20959
|
+
msg_id.push(message2.messageId);
|
|
20960
|
+
gcInterval = setInterval(async () => {
|
|
20961
|
+
try {
|
|
20962
|
+
await page.evaluate(() => {
|
|
20963
|
+
if (window.gc) window.gc();
|
|
20789
20964
|
});
|
|
20790
|
-
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
|
|
20794
|
-
|
|
20795
|
-
|
|
20796
|
-
|
|
20797
|
-
|
|
20798
|
-
|
|
20799
|
-
|
|
20800
|
-
|
|
20801
|
-
|
|
20802
|
-
|
|
20803
|
-
|
|
20804
|
-
|
|
20805
|
-
|
|
20806
|
-
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
|
|
20811
|
-
|
|
20812
|
-
|
|
20813
|
-
|
|
20814
|
-
|
|
20815
|
-
|
|
20816
|
-
|
|
20817
|
-
|
|
20818
|
-
|
|
20819
|
-
logger.
|
|
20820
|
-
|
|
20821
|
-
|
|
20822
|
-
|
|
20823
|
-
|
|
20824
|
-
|
|
20825
|
-
|
|
20826
|
-
|
|
20827
|
-
|
|
20828
|
-
|
|
20965
|
+
} catch {}
|
|
20966
|
+
}, 1e4);
|
|
20967
|
+
logger.mark("开始等待用户扫码登录...");
|
|
20968
|
+
const loginResult = await Promise.race([new Promise((resolve$1) => {
|
|
20969
|
+
const timer = setTimeout(async () => {
|
|
20970
|
+
logger.warn("扫码登录超时(2分钟),撤回二维码消息");
|
|
20971
|
+
await Promise.all(msg_id.map(async (id) => {
|
|
20972
|
+
await e.bot.recallMsg(e.contact, id);
|
|
20973
|
+
}));
|
|
20974
|
+
resolve$1(false);
|
|
20975
|
+
}, 120 * 1e3);
|
|
20976
|
+
let secondVerifyHandled = false;
|
|
20977
|
+
let scannedHandled = false;
|
|
20978
|
+
let responseCount = 0;
|
|
20979
|
+
page.on("response", async (response) => {
|
|
20980
|
+
responseCount++;
|
|
20981
|
+
const url = response.url();
|
|
20982
|
+
if (responseCount % 10 === 0) logger.debug(`[心跳] 已收到 ${responseCount} 个响应`);
|
|
20983
|
+
if (url.includes("passport") || url.includes("login") || url.includes("qrconnect") || url.includes("qrcode")) logger.debug(`[响应] 登录相关请求: ${url}, status: ${response.status()}`);
|
|
20984
|
+
});
|
|
20985
|
+
logger.mark("响应监听器已注册");
|
|
20986
|
+
page.on("response", async (response) => {
|
|
20987
|
+
try {
|
|
20988
|
+
if (response.url().includes("check_qrconnect")) {
|
|
20989
|
+
logger.debug(`收到登录轮询响应: ${response.url()}`);
|
|
20990
|
+
const hasSidGuard = (response.headers()["set-cookie"] || "").includes("sid_guard");
|
|
20991
|
+
logger.debug(`响应头包含 sid_guard: ${hasSidGuard}`);
|
|
20992
|
+
if (hasSidGuard) {
|
|
20993
|
+
clearTimeout(timer);
|
|
20994
|
+
logger.mark("检测到 sid_guard,登录成功");
|
|
20995
|
+
logger.debug("开始获取 cookies...");
|
|
20996
|
+
const cookies = await puppeteer.browser.cookies();
|
|
20997
|
+
logger.debug(`获取到 ${cookies.length} 个 cookies`);
|
|
20998
|
+
const cookieString = cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join("; ");
|
|
20999
|
+
const hasSessionidSs = cookies.some((cookie) => cookie.name === "sessionid_ss");
|
|
21000
|
+
const hasTtwid = cookies.some((cookie) => cookie.name === "ttwid");
|
|
21001
|
+
logger.mark(`Cookie 参数检测: sessionid_ss=${hasSessionidSs}, ttwid=${hasTtwid}`);
|
|
21002
|
+
if (!hasSessionidSs || !hasTtwid) {
|
|
21003
|
+
logger.warn("警告:缺少关键 cookie 参数!");
|
|
21004
|
+
if (!hasSessionidSs) logger.warn(" - 缺少 sessionid_ss");
|
|
21005
|
+
if (!hasTtwid) logger.warn(" - 缺少 ttwid");
|
|
20829
21006
|
}
|
|
20830
|
-
|
|
20831
|
-
|
|
20832
|
-
|
|
20833
|
-
|
|
20834
|
-
|
|
20835
|
-
|
|
20836
|
-
|
|
20837
|
-
|
|
20838
|
-
|
|
20839
|
-
|
|
20840
|
-
|
|
20841
|
-
|
|
20842
|
-
|
|
20843
|
-
|
|
20844
|
-
|
|
20845
|
-
|
|
20846
|
-
|
|
20847
|
-
|
|
20848
|
-
|
|
20849
|
-
|
|
20850
|
-
|
|
20851
|
-
|
|
20852
|
-
|
|
20853
|
-
|
|
20854
|
-
|
|
20855
|
-
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
20860
|
-
|
|
20861
|
-
|
|
20862
|
-
|
|
20863
|
-
|
|
20864
|
-
|
|
20865
|
-
|
|
20866
|
-
|
|
20867
|
-
|
|
20868
|
-
|
|
20869
|
-
|
|
20870
|
-
|
|
20871
|
-
|
|
20872
|
-
|
|
20873
|
-
|
|
20874
|
-
|
|
20875
|
-
|
|
20876
|
-
|
|
20877
|
-
|
|
20878
|
-
|
|
20879
|
-
|
|
20880
|
-
|
|
20881
|
-
|
|
20882
|
-
|
|
20883
|
-
|
|
20884
|
-
|
|
20885
|
-
resolveValidate(false);
|
|
20886
|
-
} else if (validateJson.message === "success" || !validateJson.data?.error_code) {
|
|
20887
|
-
logger.mark("验证码验证成功");
|
|
20888
|
-
page.off("response", validateHandler);
|
|
20889
|
-
resolveValidate(true);
|
|
20890
|
-
}
|
|
20891
|
-
} catch (err) {
|
|
20892
|
-
logger.debug("解析验证响应失败:", err);
|
|
20893
|
-
}
|
|
20894
|
-
};
|
|
20895
|
-
page.on("response", validateHandler);
|
|
20896
|
-
setTimeout(() => {
|
|
20897
|
-
page.off("response", validateHandler);
|
|
20898
|
-
resolveValidate(false);
|
|
20899
|
-
}, 5e3);
|
|
20900
|
-
});
|
|
20901
|
-
await page.evaluate(() => {
|
|
20902
|
-
const verifyBtn = Array.from(document.querySelectorAll("*")).find((el) => el.textContent?.trim() === "验证");
|
|
20903
|
-
if (verifyBtn) verifyBtn.click();
|
|
20904
|
-
});
|
|
20905
|
-
logger.mark("已提交验证码,等待验证结果...");
|
|
20906
|
-
verifySuccess = await validatePromise;
|
|
20907
|
-
if (!verifySuccess && verifyAttempts < maxAttempts) {
|
|
20908
|
-
const retryMsg = await e.reply("验证码错误,请重新发送正确的 6 位数验证码(剩余机会:1次)", { reply: true });
|
|
20909
|
-
msg_id.push(retryMsg.messageId);
|
|
20910
|
-
} else if (!verifySuccess && verifyAttempts >= maxAttempts) {
|
|
20911
|
-
logger.warn("验证码错误次数过多,登录失败");
|
|
21007
|
+
logger.debug("开始保存 cookies...");
|
|
21008
|
+
Config.Modify("cookies", "douyin", cookieString);
|
|
21009
|
+
logger.debug("cookies 保存完成");
|
|
21010
|
+
await e.reply("登录成功!用户登录凭证已保存至cookies.yaml", { reply: true });
|
|
21011
|
+
await Promise.all(msg_id.map(async (id) => {
|
|
21012
|
+
await e.bot.recallMsg(e.contact, id);
|
|
21013
|
+
}));
|
|
21014
|
+
logger.mark("关闭浏览器...");
|
|
21015
|
+
await puppeteer.browser.close();
|
|
21016
|
+
logger.mark("浏览器已关闭");
|
|
21017
|
+
resolve$1(true);
|
|
21018
|
+
return;
|
|
21019
|
+
}
|
|
21020
|
+
const responseBody = await response.text();
|
|
21021
|
+
const jsonResponse = JSON.parse(responseBody);
|
|
21022
|
+
logger.debug(`二维码状态:${jsonResponse.data?.status}, error_code: ${jsonResponse.data?.error_code}`);
|
|
21023
|
+
if (jsonResponse.data?.status === "scanned" && !scannedHandled) {
|
|
21024
|
+
scannedHandled = true;
|
|
21025
|
+
logger.mark("检测到二维码已被扫描");
|
|
21026
|
+
await Promise.all(msg_id.map(async (id) => {
|
|
21027
|
+
await e.bot.recallMsg(e.contact, id);
|
|
21028
|
+
}));
|
|
21029
|
+
msg_id.length = 0;
|
|
21030
|
+
const authMsg = await e.reply("此二维码已被扫描,请在手机上授权以登录", { reply: true });
|
|
21031
|
+
msg_id.push(authMsg.messageId);
|
|
21032
|
+
}
|
|
21033
|
+
if (jsonResponse.data?.error_code === 2046 && !secondVerifyHandled) {
|
|
21034
|
+
secondVerifyHandled = true;
|
|
21035
|
+
logger.mark("检测到需要二次验证");
|
|
21036
|
+
clearTimeout(timer);
|
|
21037
|
+
(async () => {
|
|
21038
|
+
try {
|
|
21039
|
+
await page.waitForSelector("#uc-second-verify", { timeout: 5e3 });
|
|
21040
|
+
if (!await page.evaluate(() => {
|
|
21041
|
+
const element = document.evaluate("//text()[contains(., '接收短信验证码')]/ancestor::*[1]", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
|
21042
|
+
if (element) {
|
|
21043
|
+
element.click();
|
|
21044
|
+
return true;
|
|
21045
|
+
}
|
|
21046
|
+
return false;
|
|
21047
|
+
})) logger.warn("未找到\"接收短信验证码\"按钮");
|
|
21048
|
+
await new Promise((resolve$2) => setTimeout(resolve$2, 2e3));
|
|
21049
|
+
const inputSelector = "#uc-second-verify input";
|
|
21050
|
+
await page.waitForSelector(inputSelector, { timeout: 1e4 });
|
|
21051
|
+
const tipMsg = await e.reply("此次验证需要进行 2FA\n6 位数的验证码已发送至扫码设备绑定的手机号\n请在 60 秒内发送此验证码以通过 2FA", { reply: true });
|
|
21052
|
+
msg_id.push(tipMsg.messageId);
|
|
21053
|
+
let verifyAttempts = 0;
|
|
21054
|
+
const maxAttempts = 2;
|
|
21055
|
+
let verifySuccess = false;
|
|
21056
|
+
while (verifyAttempts < maxAttempts && !verifySuccess) {
|
|
21057
|
+
verifyAttempts++;
|
|
21058
|
+
logger.debug(`验证码输入尝试 ${verifyAttempts}/${maxAttempts}`);
|
|
21059
|
+
const ctx = await Promise.race([karin.ctx(e, { reply: true }), new Promise((_$1, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("2FA_TIMEOUT")), 6e4))]).catch(async (error) => {
|
|
21060
|
+
if (error.message === "2FA_TIMEOUT") {
|
|
21061
|
+
logger.warn("2FA验证码输入超时");
|
|
20912
21062
|
clearTimeout(timer);
|
|
20913
21063
|
if (gcInterval) clearInterval(gcInterval);
|
|
20914
21064
|
await puppeteer.browser.close();
|
|
20915
21065
|
await Promise.all(msg_id.map(async (id) => {
|
|
20916
21066
|
await e.bot.recallMsg(e.contact, id);
|
|
20917
21067
|
}));
|
|
20918
|
-
await e.reply("
|
|
21068
|
+
await e.reply("验证码验证码输入超时,登录失败", { reply: true });
|
|
20919
21069
|
resolve$1(true);
|
|
20920
|
-
return;
|
|
20921
21070
|
}
|
|
21071
|
+
throw error;
|
|
21072
|
+
});
|
|
21073
|
+
if (!ctx) return;
|
|
21074
|
+
await page.evaluate((selector) => {
|
|
21075
|
+
const input = document.querySelector(selector);
|
|
21076
|
+
if (input) input.value = "";
|
|
21077
|
+
}, inputSelector);
|
|
21078
|
+
await page.type(inputSelector, ctx.msg);
|
|
21079
|
+
const validatePromise = new Promise((resolveValidate) => {
|
|
21080
|
+
const validateHandler = async (resp) => {
|
|
21081
|
+
if (resp.url().includes("validate_code")) try {
|
|
21082
|
+
const validateBody = await resp.text();
|
|
21083
|
+
const validateJson = JSON.parse(validateBody);
|
|
21084
|
+
logger.debug("验证码验证响应:", validateJson);
|
|
21085
|
+
if (validateJson.data?.error_code === 1202) {
|
|
21086
|
+
logger.warn("验证码错误");
|
|
21087
|
+
page.off("response", validateHandler);
|
|
21088
|
+
resolveValidate(false);
|
|
21089
|
+
} else if (validateJson.message === "success" || !validateJson.data?.error_code) {
|
|
21090
|
+
logger.mark("验证码验证成功");
|
|
21091
|
+
page.off("response", validateHandler);
|
|
21092
|
+
resolveValidate(true);
|
|
21093
|
+
}
|
|
21094
|
+
} catch (err) {
|
|
21095
|
+
logger.debug("解析验证响应失败:", err);
|
|
21096
|
+
}
|
|
21097
|
+
};
|
|
21098
|
+
page.on("response", validateHandler);
|
|
21099
|
+
setTimeout(() => {
|
|
21100
|
+
page.off("response", validateHandler);
|
|
21101
|
+
resolveValidate(false);
|
|
21102
|
+
}, 5e3);
|
|
21103
|
+
});
|
|
21104
|
+
await page.evaluate(() => {
|
|
21105
|
+
const verifyBtn = Array.from(document.querySelectorAll("*")).find((el) => el.textContent?.trim() === "验证");
|
|
21106
|
+
if (verifyBtn) verifyBtn.click();
|
|
21107
|
+
});
|
|
21108
|
+
logger.mark("已提交验证码,等待验证结果...");
|
|
21109
|
+
verifySuccess = await validatePromise;
|
|
21110
|
+
if (!verifySuccess && verifyAttempts < maxAttempts) {
|
|
21111
|
+
const retryMsg = await e.reply("验证码错误,请重新发送正确的 6 位数验证码(剩余机会:1次)", { reply: true });
|
|
21112
|
+
msg_id.push(retryMsg.messageId);
|
|
21113
|
+
} else if (!verifySuccess && verifyAttempts >= maxAttempts) {
|
|
21114
|
+
logger.warn("验证码错误次数过多,登录失败");
|
|
21115
|
+
clearTimeout(timer);
|
|
21116
|
+
if (gcInterval) clearInterval(gcInterval);
|
|
21117
|
+
await puppeteer.browser.close();
|
|
21118
|
+
await Promise.all(msg_id.map(async (id) => {
|
|
21119
|
+
await e.bot.recallMsg(e.contact, id);
|
|
21120
|
+
}));
|
|
21121
|
+
await e.reply("验证码错误,登录失败", { reply: true });
|
|
21122
|
+
resolve$1(true);
|
|
21123
|
+
return;
|
|
20922
21124
|
}
|
|
20923
|
-
if (verifySuccess) logger.mark("2FA验证通过,等待最终登录确认...");
|
|
20924
|
-
} catch (err) {
|
|
20925
|
-
logger.error("二次验证处理失败:", err);
|
|
20926
|
-
clearTimeout(timer);
|
|
20927
|
-
if (gcInterval) clearInterval(gcInterval);
|
|
20928
|
-
await puppeteer.browser.close();
|
|
20929
|
-
await Promise.all(msg_id.map(async (id) => {
|
|
20930
|
-
await e.bot.recallMsg(e.contact, id);
|
|
20931
|
-
}));
|
|
20932
|
-
await e.reply("二次验证处理失败,登录失败", { reply: true });
|
|
20933
|
-
resolve$1(true);
|
|
20934
21125
|
}
|
|
20935
|
-
|
|
20936
|
-
|
|
21126
|
+
if (verifySuccess) logger.mark("2FA验证通过,等待最终登录确认...");
|
|
21127
|
+
} catch (err) {
|
|
21128
|
+
logger.error("二次验证处理失败:", err);
|
|
21129
|
+
clearTimeout(timer);
|
|
21130
|
+
if (gcInterval) clearInterval(gcInterval);
|
|
21131
|
+
await puppeteer.browser.close();
|
|
21132
|
+
await Promise.all(msg_id.map(async (id) => {
|
|
21133
|
+
await e.bot.recallMsg(e.contact, id);
|
|
21134
|
+
}));
|
|
21135
|
+
await e.reply("二次验证处理失败,登录失败", { reply: true });
|
|
21136
|
+
resolve$1(true);
|
|
21137
|
+
}
|
|
21138
|
+
})();
|
|
20937
21139
|
}
|
|
20938
|
-
} catch (error) {
|
|
20939
|
-
logger.error("处理响应时出错:", error);
|
|
20940
21140
|
}
|
|
20941
|
-
})
|
|
20942
|
-
|
|
20943
|
-
|
|
20944
|
-
|
|
20945
|
-
|
|
20946
|
-
|
|
20947
|
-
|
|
20948
|
-
|
|
20949
|
-
}
|
|
20950
|
-
} catch (err) {
|
|
20951
|
-
logger.error("登录流程出错:", err);
|
|
20952
|
-
if (gcInterval) clearInterval(gcInterval);
|
|
21141
|
+
} catch (error) {
|
|
21142
|
+
logger.error("处理响应时出错:", error);
|
|
21143
|
+
}
|
|
21144
|
+
});
|
|
21145
|
+
})]);
|
|
21146
|
+
if (gcInterval) clearInterval(gcInterval);
|
|
21147
|
+
if (!loginResult) {
|
|
21148
|
+
logger.warn("登录超时或失败");
|
|
20953
21149
|
await puppeteer.browser.close();
|
|
20954
|
-
await e.reply("
|
|
21150
|
+
await e.reply("登录超时!二维码已失效!", { reply: true });
|
|
21151
|
+
return true;
|
|
20955
21152
|
}
|
|
20956
|
-
} catch (
|
|
20957
|
-
logger.error(
|
|
20958
|
-
|
|
21153
|
+
} catch (err) {
|
|
21154
|
+
logger.error("登录流程出错:", err);
|
|
21155
|
+
if (gcInterval) clearInterval(gcInterval);
|
|
21156
|
+
await puppeteer.browser.close();
|
|
21157
|
+
await e.reply("登录过程出错,请查看控制台日志", { reply: true });
|
|
20959
21158
|
}
|
|
20960
21159
|
return true;
|
|
20961
21160
|
};
|
|
@@ -21003,55 +21202,52 @@ var waitQrcode = async (page) => {
|
|
|
21003
21202
|
};
|
|
21004
21203
|
await init_module();
|
|
21005
21204
|
await init_Config();
|
|
21006
|
-
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
|
|
21013
|
-
|
|
21014
|
-
}
|
|
21015
|
-
} catch (err) {
|
|
21016
|
-
console.error("删除文件时出错:", err);
|
|
21205
|
+
await init_ErrorHandler();
|
|
21206
|
+
var handleCacheCleanup = wrapWithErrorHandler(async () => {
|
|
21207
|
+
const twoHoursAgo = Date.now() - 7200 * 1e3;
|
|
21208
|
+
const videoDeleted = removeOldFiles(Common.tempDri.video, twoHoursAgo);
|
|
21209
|
+
logger.mark(`${Common.tempDri.video} 目录下已删除 ${videoDeleted} 个文件`);
|
|
21210
|
+
if (Config.upload.imageSendMode === "file") {
|
|
21211
|
+
const imageDeleted = removeOldFiles(Common.tempDri.images, twoHoursAgo);
|
|
21212
|
+
logger.mark(`${Common.tempDri.images} 目录下已删除 ${imageDeleted} 个文件`);
|
|
21017
21213
|
}
|
|
21018
|
-
});
|
|
21019
|
-
const
|
|
21214
|
+
}, { businessName: "缓存自动删除" });
|
|
21215
|
+
const task = Config.app.removeCache && karin$1.task("[kkk-缓存自动删除]", "0 */4 * * *", handleCacheCleanup);
|
|
21216
|
+
var handleBilibiliLogin = wrapWithErrorHandler(async (e) => {
|
|
21020
21217
|
await bilibiliLogin(e);
|
|
21021
21218
|
return true;
|
|
21022
|
-
}, {
|
|
21219
|
+
}, { businessName: "B站登录" });
|
|
21220
|
+
var handleDouyinLogin = wrapWithErrorHandler(async (e) => {
|
|
21221
|
+
await douyinLogin(e);
|
|
21222
|
+
return true;
|
|
21223
|
+
}, { businessName: "抖音登录" });
|
|
21224
|
+
const biLogin = karin$1.command(/^#?(kkk)?\s*B站\s*(扫码)?\s*登录$/i, handleBilibiliLogin, {
|
|
21023
21225
|
perm: Config.bilibili.loginPerm,
|
|
21024
21226
|
name: "kkk-ck管理"
|
|
21025
21227
|
});
|
|
21026
|
-
const dylogin = karin$1.command(/^#?(kkk)?抖音(扫码)?登录$/,
|
|
21027
|
-
await douyinLogin(e);
|
|
21028
|
-
return true;
|
|
21029
|
-
}, {
|
|
21228
|
+
const dylogin = karin$1.command(/^#?(kkk)?抖音(扫码)?登录$/, handleDouyinLogin, {
|
|
21030
21229
|
perm: Config.douyin.loginPerm,
|
|
21031
21230
|
name: "kkk-ck管理"
|
|
21032
21231
|
});
|
|
21033
21232
|
const removeOldFiles = (dir, beforeTimestamp) => {
|
|
21034
21233
|
let deletedCount = 0;
|
|
21035
|
-
|
|
21036
|
-
|
|
21037
|
-
|
|
21038
|
-
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
|
|
21042
|
-
|
|
21043
|
-
|
|
21044
|
-
|
|
21045
|
-
deletedCount++;
|
|
21046
|
-
}
|
|
21234
|
+
const files = fs.readdirSync(dir);
|
|
21235
|
+
for (const file of files) {
|
|
21236
|
+
const filePath = path.join(dir, file);
|
|
21237
|
+
const stats = fs.statSync(filePath);
|
|
21238
|
+
if (stats.isDirectory()) {
|
|
21239
|
+
deletedCount += removeOldFiles(filePath, beforeTimestamp);
|
|
21240
|
+
if (fs.readdirSync(filePath).length === 0) fs.rmdirSync(filePath);
|
|
21241
|
+
} else if (stats.mtimeMs < beforeTimestamp) {
|
|
21242
|
+
fs.unlinkSync(filePath);
|
|
21243
|
+
deletedCount++;
|
|
21047
21244
|
}
|
|
21048
|
-
} catch (err) {
|
|
21049
|
-
logger.error(`处理目录 ${dir} 时出错:`, err);
|
|
21050
21245
|
}
|
|
21051
21246
|
return deletedCount;
|
|
21052
21247
|
};
|
|
21053
21248
|
await init_module();
|
|
21054
21249
|
await init_Config();
|
|
21250
|
+
await init_ErrorHandler();
|
|
21055
21251
|
var HELP_MENU_CONFIG = [
|
|
21056
21252
|
{
|
|
21057
21253
|
title: "常用功能",
|
|
@@ -21160,7 +21356,7 @@ var buildMenuForRole = (role) => {
|
|
|
21160
21356
|
};
|
|
21161
21357
|
}).filter((g) => g.items.length > 0 || g.subGroups && g.subGroups.length > 0);
|
|
21162
21358
|
};
|
|
21163
|
-
|
|
21359
|
+
var handleHelp = wrapWithErrorHandler(async (e) => {
|
|
21164
21360
|
const masters = config.master().filter((id) => id !== "console");
|
|
21165
21361
|
const role = !!e.sender && masters.includes(e.sender.userId) ? "master" : "member";
|
|
21166
21362
|
const menu = buildMenuForRole(role);
|
|
@@ -21182,8 +21378,8 @@ const help = karin$1.command(/^#?kkk帮助$/, async (e) => {
|
|
|
21182
21378
|
});
|
|
21183
21379
|
await e.reply(img$2);
|
|
21184
21380
|
return true;
|
|
21185
|
-
}, {
|
|
21186
|
-
|
|
21381
|
+
}, { businessName: "KKK帮助" });
|
|
21382
|
+
var handleVersion = wrapWithErrorHandler(async (e) => {
|
|
21187
21383
|
const changelogContent = fs.readFileSync(Root.pluginPath + "/CHANGELOG.md", "utf8");
|
|
21188
21384
|
const img$2 = await Render("other/changelog", {
|
|
21189
21385
|
markdown: logs({
|
|
@@ -21197,7 +21393,9 @@ const version = karin$1.command(/^#?kkk(版本|更新日志)$/, async (e) => {
|
|
|
21197
21393
|
});
|
|
21198
21394
|
e.reply(img$2);
|
|
21199
21395
|
return true;
|
|
21200
|
-
}, {
|
|
21396
|
+
}, { businessName: "KKK版本" });
|
|
21397
|
+
const help = karin$1.command(/^#?kkk帮助$/, handleHelp, { name: "kkk-帮助" });
|
|
21398
|
+
const version = karin$1.command(/^#?kkk(版本|更新日志)$/, handleVersion, { name: "kkk-版本" });
|
|
21201
21399
|
await init_date_fns();
|
|
21202
21400
|
await init_module();
|
|
21203
21401
|
await init_db();
|
|
@@ -21430,6 +21628,7 @@ const testDouyinPush = karin$1.command(/^#测试抖音推送\s*(https?:\/\/[^\s]
|
|
|
21430
21628
|
priority: -Infinity
|
|
21431
21629
|
});
|
|
21432
21630
|
await init_Config();
|
|
21631
|
+
await init_ErrorHandler();
|
|
21433
21632
|
await init_Render();
|
|
21434
21633
|
function getLocalIP() {
|
|
21435
21634
|
const interfaces = os.networkInterfaces();
|
|
@@ -21483,7 +21682,7 @@ async function getHostByConfig() {
|
|
|
21483
21682
|
}
|
|
21484
21683
|
return getLocalIP();
|
|
21485
21684
|
}
|
|
21486
|
-
|
|
21685
|
+
var handleQrLogin = wrapWithErrorHandler(async (e) => {
|
|
21487
21686
|
const bot = karin$1.getBot(e.selfId);
|
|
21488
21687
|
const userId = e.userId;
|
|
21489
21688
|
if (e.isGroup) {
|
|
@@ -21500,105 +21699,93 @@ const qrLogin = karin$1.command(/^#?(kkk)?登录$/i, async (e) => {
|
|
|
21500
21699
|
await e.reply("未配置 HTTP_AUTH_KEY 环境变量,无法生成登录二维码");
|
|
21501
21700
|
return true;
|
|
21502
21701
|
}
|
|
21503
|
-
const
|
|
21504
|
-
|
|
21505
|
-
|
|
21506
|
-
|
|
21507
|
-
|
|
21702
|
+
const images = await Render("other/qrlogin", {
|
|
21703
|
+
share_url: JSON.stringify({
|
|
21704
|
+
protocol,
|
|
21705
|
+
host,
|
|
21706
|
+
port,
|
|
21707
|
+
authKey
|
|
21708
|
+
}),
|
|
21709
|
+
serverUrl: `${protocol}://${host}:${port}`
|
|
21508
21710
|
});
|
|
21509
|
-
|
|
21510
|
-
|
|
21511
|
-
const images = await Render("other/qrlogin", {
|
|
21512
|
-
share_url: qrData,
|
|
21513
|
-
serverUrl
|
|
21514
|
-
});
|
|
21515
|
-
await karin$1.sendMaster(e.selfId, userId, images);
|
|
21516
|
-
if (e.isGroup) await e.reply("登录二维码已私聊发送,请查收~");
|
|
21517
|
-
} catch (error) {
|
|
21518
|
-
await e.reply("生成二维码失败: " + (error instanceof Error ? error.message : String(error)));
|
|
21519
|
-
}
|
|
21711
|
+
await karin$1.sendMaster(e.selfId, userId, images);
|
|
21712
|
+
if (e.isGroup) await e.reply("登录二维码已私聊发送,请查收~");
|
|
21520
21713
|
return true;
|
|
21521
|
-
}, {
|
|
21714
|
+
}, { businessName: "APP扫码登录" });
|
|
21715
|
+
const qrLogin = karin$1.command(/^#?(kkk)?登录$/i, handleQrLogin, {
|
|
21522
21716
|
perm: "master",
|
|
21523
21717
|
name: "kkk-APP扫码登录"
|
|
21524
21718
|
});
|
|
21525
21719
|
await init_module();
|
|
21526
21720
|
await init_db();
|
|
21527
|
-
|
|
21528
|
-
|
|
21529
|
-
|
|
21530
|
-
|
|
21531
|
-
|
|
21532
|
-
return true;
|
|
21533
|
-
}
|
|
21534
|
-
let groupName = "";
|
|
21535
|
-
let groupMemberCount;
|
|
21536
|
-
let groupAvatar;
|
|
21537
|
-
try {
|
|
21538
|
-
const groupInfo = await e.bot.getGroupInfo(groupId);
|
|
21539
|
-
groupName = groupInfo?.groupName || "";
|
|
21540
|
-
groupMemberCount = groupInfo?.memberCount;
|
|
21541
|
-
groupAvatar = groupInfo?.avatar;
|
|
21542
|
-
} catch (error) {
|
|
21543
|
-
logger.debug("[统计] 获取群组信息失败:", error);
|
|
21544
|
-
}
|
|
21545
|
-
const statisticsDB$1 = await getStatisticsDB();
|
|
21546
|
-
const groupStats = await statisticsDB$1.getGroupStatistics(groupId);
|
|
21547
|
-
const groupUniqueUsers = await statisticsDB$1.getGroupUniqueUsers(groupId);
|
|
21548
|
-
const globalSummary = await statisticsDB$1.getGlobalSummary();
|
|
21549
|
-
const groupTotalParses = groupStats.reduce((sum, stat) => sum + stat.parseCount, 0);
|
|
21550
|
-
const platformData = {
|
|
21551
|
-
douyin: groupStats.filter((s) => s.platform === "douyin").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21552
|
-
bilibili: groupStats.filter((s) => s.platform === "bilibili").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21553
|
-
kuaishou: groupStats.filter((s) => s.platform === "kuaishou").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21554
|
-
xiaohongshu: groupStats.filter((s) => s.platform === "xiaohongshu").reduce((sum, s) => sum + s.parseCount, 0)
|
|
21555
|
-
};
|
|
21556
|
-
const img$2 = await Render("statistics/group", {
|
|
21557
|
-
groupId,
|
|
21558
|
-
groupName,
|
|
21559
|
-
groupMemberCount,
|
|
21560
|
-
groupAvatar,
|
|
21561
|
-
groupTotalParses,
|
|
21562
|
-
groupUniqueUsers,
|
|
21563
|
-
platformData,
|
|
21564
|
-
globalTotalGroups: globalSummary.totalGroups,
|
|
21565
|
-
globalTotalParses: globalSummary.totalParses
|
|
21566
|
-
});
|
|
21567
|
-
await e.reply(img$2);
|
|
21568
|
-
return true;
|
|
21569
|
-
} catch (error) {
|
|
21570
|
-
await e.reply(`获取解析统计失败:${error}`);
|
|
21721
|
+
await init_ErrorHandler();
|
|
21722
|
+
var handleGroupStatistics = wrapWithErrorHandler(async (e) => {
|
|
21723
|
+
const groupId = e.isGroup ? e.contact?.peer || "" : "";
|
|
21724
|
+
if (!groupId) {
|
|
21725
|
+
await e.reply("此命令仅支持在群聊中使用");
|
|
21571
21726
|
return true;
|
|
21572
21727
|
}
|
|
21573
|
-
|
|
21574
|
-
|
|
21728
|
+
let groupName = "";
|
|
21729
|
+
let groupMemberCount;
|
|
21730
|
+
let groupAvatar;
|
|
21575
21731
|
try {
|
|
21576
|
-
const
|
|
21577
|
-
|
|
21578
|
-
|
|
21579
|
-
|
|
21580
|
-
|
|
21581
|
-
|
|
21582
|
-
|
|
21583
|
-
|
|
21584
|
-
|
|
21585
|
-
|
|
21586
|
-
|
|
21587
|
-
|
|
21588
|
-
|
|
21589
|
-
|
|
21590
|
-
|
|
21591
|
-
|
|
21592
|
-
|
|
21593
|
-
|
|
21732
|
+
const groupInfo = await e.bot.getGroupInfo(groupId);
|
|
21733
|
+
groupName = groupInfo?.groupName || "";
|
|
21734
|
+
groupMemberCount = groupInfo?.memberCount;
|
|
21735
|
+
groupAvatar = groupInfo?.avatar;
|
|
21736
|
+
} catch (error) {
|
|
21737
|
+
logger.debug("[统计] 获取群组信息失败:", error);
|
|
21738
|
+
}
|
|
21739
|
+
const statisticsDB$1 = await getStatisticsDB();
|
|
21740
|
+
const groupStats = await statisticsDB$1.getGroupStatistics(groupId);
|
|
21741
|
+
const groupUniqueUsers = await statisticsDB$1.getGroupUniqueUsers(groupId);
|
|
21742
|
+
const globalSummary = await statisticsDB$1.getGlobalSummary();
|
|
21743
|
+
const groupTotalParses = groupStats.reduce((sum, stat) => sum + stat.parseCount, 0);
|
|
21744
|
+
const platformData = {
|
|
21745
|
+
douyin: groupStats.filter((s) => s.platform === "douyin").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21746
|
+
bilibili: groupStats.filter((s) => s.platform === "bilibili").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21747
|
+
kuaishou: groupStats.filter((s) => s.platform === "kuaishou").reduce((sum, s) => sum + s.parseCount, 0),
|
|
21748
|
+
xiaohongshu: groupStats.filter((s) => s.platform === "xiaohongshu").reduce((sum, s) => sum + s.parseCount, 0)
|
|
21749
|
+
};
|
|
21750
|
+
const img$2 = await Render("statistics/group", {
|
|
21751
|
+
groupId,
|
|
21752
|
+
groupName,
|
|
21753
|
+
groupMemberCount,
|
|
21754
|
+
groupAvatar,
|
|
21755
|
+
groupTotalParses,
|
|
21756
|
+
groupUniqueUsers,
|
|
21757
|
+
platformData,
|
|
21758
|
+
globalTotalGroups: globalSummary.totalGroups,
|
|
21759
|
+
globalTotalParses: globalSummary.totalParses
|
|
21760
|
+
});
|
|
21761
|
+
await e.reply(img$2);
|
|
21762
|
+
return true;
|
|
21763
|
+
}, { businessName: "群组解析统计" });
|
|
21764
|
+
const groupStatistics = karin$1.command(/^#?kkk解析统计$/, handleGroupStatistics, { name: "kkk-解析统计" });
|
|
21765
|
+
var handleGlobalStatistics = wrapWithErrorHandler(async (e) => {
|
|
21766
|
+
const statisticsDB$1 = await getStatisticsDB();
|
|
21767
|
+
const allStats = await statisticsDB$1.getAllStatistics();
|
|
21768
|
+
const historyData = await statisticsDB$1.getRecentHistory(30);
|
|
21769
|
+
const groupIds = [...new Set(allStats.map((s) => s.groupId))];
|
|
21770
|
+
const groupInfoMap = /* @__PURE__ */ new Map();
|
|
21771
|
+
for (const groupId of groupIds) try {
|
|
21772
|
+
const groupInfo = await e.bot.getGroupInfo(groupId);
|
|
21773
|
+
groupInfoMap.set(groupId, {
|
|
21774
|
+
groupName: groupInfo?.groupName,
|
|
21775
|
+
groupAvatar: groupInfo?.avatar
|
|
21594
21776
|
});
|
|
21595
|
-
await e.reply(img$2);
|
|
21596
|
-
return true;
|
|
21597
21777
|
} catch (error) {
|
|
21598
|
-
|
|
21599
|
-
return true;
|
|
21778
|
+
logger.debug(`[统计] 获取群组 ${groupId} 信息失败:`, error);
|
|
21600
21779
|
}
|
|
21601
|
-
|
|
21780
|
+
const img$2 = await Render("statistics/global", {
|
|
21781
|
+
allStats,
|
|
21782
|
+
historyData: historyData.reverse(),
|
|
21783
|
+
groupInfoMap: Object.fromEntries(groupInfoMap)
|
|
21784
|
+
});
|
|
21785
|
+
await e.reply(img$2);
|
|
21786
|
+
return true;
|
|
21787
|
+
}, { businessName: "全局解析统计" });
|
|
21788
|
+
const globalStatistics = karin$1.command(/^#?kkk全局解析统计$/, handleGlobalStatistics, {
|
|
21602
21789
|
name: "kkk-全局解析统计",
|
|
21603
21790
|
perm: "master"
|
|
21604
21791
|
});
|
|
@@ -22216,6 +22403,7 @@ const getChangelogImage = async (props) => {
|
|
|
22216
22403
|
}) || null;
|
|
22217
22404
|
};
|
|
22218
22405
|
await init_module();
|
|
22406
|
+
await init_ErrorHandler();
|
|
22219
22407
|
await init_semver();
|
|
22220
22408
|
var UPDATE_LOCK_KEY = "kkk:update:lock";
|
|
22221
22409
|
var UPDATE_MSGID_KEY = "kkk:update:msgId";
|
|
@@ -22257,30 +22445,29 @@ var Handler = async (e) => {
|
|
|
22257
22445
|
}
|
|
22258
22446
|
return true;
|
|
22259
22447
|
};
|
|
22448
|
+
var handleUpdateHook = wrapWithErrorHandler(async (e) => {
|
|
22449
|
+
e.reply("开始更新 karin-plugin-kkk ...", { reply: true });
|
|
22450
|
+
const upd = await checkPkgUpdate(Root.pluginName, { compare: "semver" });
|
|
22451
|
+
if (upd.status === "yes") {
|
|
22452
|
+
const result = await updatePkg(Root.pluginName);
|
|
22453
|
+
if (result.status === "ok") {
|
|
22454
|
+
if ((await e.reply(`${Root.pluginName} 更新成功!\n${result.local} -> ${result.remote}\n开始执行重启......`)).messageId) try {
|
|
22455
|
+
await db.del(UPDATE_MSGID_KEY);
|
|
22456
|
+
await db.del(UPDATE_LOCK_KEY);
|
|
22457
|
+
} catch {}
|
|
22458
|
+
await restart(e.selfId, e.contact, e.messageId);
|
|
22459
|
+
} else e.reply(`${Root.pluginName} 更新失败: ${result.data ?? "更新执行失败"}`);
|
|
22460
|
+
} else if (upd.status === "no") e.reply("未检测到可更新版本。");
|
|
22461
|
+
else e.reply(`${Root.pluginName} 更新失败: ${upd.error?.message ?? String(upd.error)}`);
|
|
22462
|
+
}, { businessName: "更新Hook" });
|
|
22260
22463
|
const kkkUpdate = hooks.message.friend(async (e, next) => {
|
|
22261
22464
|
if (e.msg.includes("更新")) {
|
|
22262
22465
|
const msgId = await db.get(UPDATE_MSGID_KEY);
|
|
22263
|
-
if (e.replyId === msgId)
|
|
22264
|
-
e.reply("开始更新 karin-plugin-kkk ...", { reply: true });
|
|
22265
|
-
const upd = await checkPkgUpdate(Root.pluginName, { compare: "semver" });
|
|
22266
|
-
if (upd.status === "yes") {
|
|
22267
|
-
const result = await updatePkg(Root.pluginName);
|
|
22268
|
-
if (result.status === "ok") {
|
|
22269
|
-
if ((await e.reply(`${Root.pluginName} 更新成功!\n${result.local} -> ${result.remote}\n开始执行重启......`)).messageId) try {
|
|
22270
|
-
await db.del(UPDATE_MSGID_KEY);
|
|
22271
|
-
await db.del(UPDATE_LOCK_KEY);
|
|
22272
|
-
} catch {}
|
|
22273
|
-
await restart(e.selfId, e.contact, e.messageId);
|
|
22274
|
-
} else e.reply(`${Root.pluginName} 更新失败: ${result.data ?? "更新执行失败"}`);
|
|
22275
|
-
} else if (upd.status === "no") e.reply("未检测到可更新版本。");
|
|
22276
|
-
else e.reply(`${Root.pluginName} 更新失败: ${upd.error?.message ?? String(upd.error)}`);
|
|
22277
|
-
} catch (error) {
|
|
22278
|
-
e.reply(`${Root.pluginName} 更新失败: ${error.message}`);
|
|
22279
|
-
}
|
|
22466
|
+
if (e.replyId === msgId) await handleUpdateHook(e);
|
|
22280
22467
|
}
|
|
22281
22468
|
next();
|
|
22282
22469
|
}, { priority: 100 });
|
|
22283
|
-
|
|
22470
|
+
var handleKkkUpdate = wrapWithErrorHandler(async (e) => {
|
|
22284
22471
|
const upd = await checkPkgUpdate(Root.pluginName, { compare: "semver" });
|
|
22285
22472
|
if (upd.status === "error") {
|
|
22286
22473
|
e.reply(`获取远程版本失败:${upd.error?.message ?? String(upd.error)}`);
|
|
@@ -22302,20 +22489,17 @@ const kkkUpdateCommand = karin$1.command(/^#?kkk更新$/, async (e) => {
|
|
|
22302
22489
|
});
|
|
22303
22490
|
if (ChangeLogImg) e.reply([segment.text(`${Root.pluginName} 的更新日志:`), ...ChangeLogImg], { reply: true });
|
|
22304
22491
|
else e.reply("获取更新日志失败,更新进程继续......", { reply: true });
|
|
22305
|
-
|
|
22306
|
-
|
|
22307
|
-
|
|
22308
|
-
|
|
22309
|
-
|
|
22310
|
-
|
|
22311
|
-
|
|
22312
|
-
|
|
22313
|
-
|
|
22314
|
-
|
|
22315
|
-
|
|
22316
|
-
e.reply(`${Root.pluginName} 更新失败: ${error.message}`);
|
|
22317
|
-
}
|
|
22318
|
-
}, { name: "kkk-更新" });
|
|
22492
|
+
const result = await updatePkg(Root.pluginName);
|
|
22493
|
+
if (result.status === "ok") {
|
|
22494
|
+
const msgResult = await e.reply(`${Root.pluginName} 更新成功!\n${result.local} -> ${result.remote}\n开始执行重启......`);
|
|
22495
|
+
if (msgResult.messageId) try {
|
|
22496
|
+
await db.del(UPDATE_MSGID_KEY);
|
|
22497
|
+
await db.del(UPDATE_LOCK_KEY);
|
|
22498
|
+
} catch {}
|
|
22499
|
+
await restart(e.selfId, e.contact, msgResult.messageId);
|
|
22500
|
+
} else e.reply(`${Root.pluginName} 更新失败: ${result.data ?? "更新执行失败"}`);
|
|
22501
|
+
}, { businessName: "KKK更新" });
|
|
22502
|
+
const kkkUpdateCommand = karin$1.command(/^#?kkk更新$/, handleKkkUpdate, { name: "kkk-更新" });
|
|
22319
22503
|
const update = karin$1.task("kkk-更新检测", "*/5 * * * *", Handler, {
|
|
22320
22504
|
name: "kkk-更新检测",
|
|
22321
22505
|
log: false
|