karin-plugin-kkk 2.18.2 → 2.19.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.
@@ -1,6 +1,6 @@
1
1
  import { n as __esmMin, o as __toESM, r as __export } from "./rolldown-runtime-BMXAG3ag.js";
2
- import { $t as require_express, G as zhCN, J as init_date_fns, Q as differenceInSeconds, W as init_locale, X as formatDistanceToNow, Y as fromUnixTime, Z as format, a as require_lib, an as axios_default, c as Window, cn as init_zod, en as require_protobufjs, i as require_dist, in as init_axios, ln as zod_default, n as require_jsQR, nn as init_source, o as require_qr_code_styling, on as Xhshow, r as require_heic_convert, rn as AxiosError$1, s as init_lib, sn as init_esm, t as require_png, tn as Chalk } from "./vendor-BCUOH1Nn.js";
3
- import { n as init_client, r as reactServerRender } from "./template-BAFMkYza.js";
2
+ import { D as init_locale, O as zhCN, _n as init_zod, a as require_lib, at as format, c as Window, cn as require_express, dn as init_source, fn as AxiosError$1, gn as init_esm, hn as Xhshow, i as require_dist, it as formatDistanceToNow, ln as require_protobufjs, mn as axios_default, n as require_jsQR, nt as init_date_fns, o as require_qr_code_styling, ot as differenceInSeconds, pn as init_axios, r as require_heic_convert, rt as fromUnixTime, s as init_lib, t as require_png, un as Chalk, vn as zod_default } from "./vendor-BsdYKPEs.js";
3
+ import { n as init_client, r as reactServerRender } from "./template-CHNHRIxO.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";
@@ -746,7 +746,7 @@ var init_bilibili$3 = __esmMin(() => {
746
746
  videoDanmaku: "/fetch_danmaku"
747
747
  };
748
748
  });
749
- var DouyinWorkParamsSchema, DouyinCommentParamsSchema, DouyinHotWordsParamsSchema, DouyinSearchParamsSchema, DouyinCommentReplyParamsSchema, DouyinUserParamsSchema, DouyinMusicParamsSchema, DouyinLiveRoomParamsSchema, DouyinQrcodeParamsSchema, DouyinEmojiListParamsSchema, DouyinEmojiProParamsSchema, DouyinDanmakuParamsSchema, DouyinValidationSchemas, DouyinMethodRoutes;
749
+ var DouyinWorkParamsSchema, DouyinCommentParamsSchema, DouyinHotWordsParamsSchema, DouyinSearchParamsSchema, DouyinCommentReplyParamsSchema, DouyinUserParamsSchema, DouyinUserListParamsSchema, DouyinMusicParamsSchema, DouyinLiveRoomParamsSchema, DouyinQrcodeParamsSchema, DouyinEmojiListParamsSchema, DouyinEmojiProParamsSchema, DouyinDanmakuParamsSchema, DouyinValidationSchemas, DouyinMethodRoutes;
750
750
  var init_douyin$3 = __esmMin(() => {
751
751
  init_zod();
752
752
  init_utils$3();
@@ -789,9 +789,19 @@ var init_douyin$3 = __esmMin(() => {
789
789
  cursor: zod_default.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
790
790
  });
791
791
  DouyinUserParamsSchema = zod_default.object({
792
- methodType: zod_default.enum(["userProfile", "userVideoList"], { error: "方法类型必须是指定的枚举值之一" }),
792
+ methodType: zod_default.literal("userProfile", { error: "方法类型必须是\"userProfile\"" }),
793
793
  sec_uid: zod_default.string({ error: "用户ID必须是字符串" }).min(1, { error: "用户ID不能为空" })
794
794
  });
795
+ DouyinUserListParamsSchema = zod_default.object({
796
+ methodType: zod_default.enum([
797
+ "userVideoList",
798
+ "userFavoriteList",
799
+ "userRecommendList"
800
+ ], { error: "方法类型必须是指定的枚举值之一" }),
801
+ sec_uid: zod_default.string({ error: "用户ID必须是字符串" }).min(1, { error: "用户ID不能为空" }),
802
+ number: smartPositiveInteger("获取数量必须是正整数").optional().default(18),
803
+ max_cursor: zod_default.string({ error: "游标必须是字符串" }).optional()
804
+ });
795
805
  DouyinMusicParamsSchema = zod_default.object({
796
806
  methodType: zod_default.literal("musicInfo", { error: "方法类型必须是\"musicInfo\"" }),
797
807
  music_id: zod_default.string({ error: "音乐ID必须是字符串" }).min(1, { error: "音乐ID不能为空" })
@@ -834,7 +844,9 @@ var init_douyin$3 = __esmMin(() => {
834
844
  slidesWork: DouyinWorkParamsSchema,
835
845
  comments: DouyinCommentParamsSchema,
836
846
  userProfile: DouyinUserParamsSchema,
837
- userVideoList: DouyinUserParamsSchema,
847
+ userVideoList: DouyinUserListParamsSchema,
848
+ userFavoriteList: DouyinUserListParamsSchema,
849
+ userRecommendList: DouyinUserListParamsSchema,
838
850
  suggestWords: DouyinHotWordsParamsSchema,
839
851
  search: DouyinSearchParamsSchema,
840
852
  musicInfo: DouyinMusicParamsSchema,
@@ -855,6 +867,8 @@ var init_douyin$3 = __esmMin(() => {
855
867
  commentReplies: "/fetch_video_comment_replies",
856
868
  userProfile: "/fetch_user_info",
857
869
  userVideoList: "/fetch_user_post_videos",
870
+ userFavoriteList: "/fetch_user_favorite_list",
871
+ userRecommendList: "/fetch_user_recommend_list",
858
872
  search: "/fetch_search_info",
859
873
  suggestWords: "/fetch_suggest_words",
860
874
  musicInfo: "/fetch_music_work",
@@ -2354,14 +2368,14 @@ var init_API$1 = __esmMin(() => {
2354
2368
  return `https://www.douyin.com/aweme/v1/web/aweme/post/?${buildQueryString({
2355
2369
  ...this.getBaseParams(),
2356
2370
  sec_user_id: data$1.sec_uid,
2357
- max_cursor: "0",
2371
+ max_cursor: data$1.max_cursor ?? "0",
2358
2372
  locate_query: "false",
2359
2373
  show_live_replay_strategy: "1",
2360
2374
  need_time_list: "1",
2361
2375
  time_list_query: "0",
2362
2376
  whale_cut_token: "",
2363
2377
  cut_version: "1",
2364
- count: "18",
2378
+ count: data$1.number ?? 18,
2365
2379
  publish_video_strategy_type: "2",
2366
2380
  version_code: "170400",
2367
2381
  version_name: "17.4.0",
@@ -2371,6 +2385,70 @@ var init_API$1 = __esmMin(() => {
2371
2385
  webid: "7338423850134226495"
2372
2386
  })}`;
2373
2387
  }
2388
+ getUserFavoriteList(data$1) {
2389
+ return `https://www-hj.douyin.com/aweme/v1/web/aweme/favorite/?${buildQueryString({
2390
+ ...this.getBaseParams(),
2391
+ sec_user_id: data$1.sec_uid,
2392
+ max_cursor: data$1.max_cursor ?? "0",
2393
+ min_cursor: "0",
2394
+ whale_cut_token: "",
2395
+ cut_version: "1",
2396
+ count: data$1.number ?? 18,
2397
+ publish_video_strategy_type: "2",
2398
+ update_version_code: "170400",
2399
+ pc_libra_divert: "Windows",
2400
+ support_h265: "1",
2401
+ support_dash: "1",
2402
+ version_code: "170400",
2403
+ version_name: "17.4.0",
2404
+ screen_width: "2328",
2405
+ screen_height: "1310",
2406
+ round_trip_time: "0",
2407
+ webid: "7487210762873685515"
2408
+ })}`;
2409
+ }
2410
+ getUserRecommendList(data$1) {
2411
+ return `https://www.douyin.com/aweme/v1/web/familiar/recommend/feed/?${buildQueryString({
2412
+ device_platform: "",
2413
+ aid: "6383",
2414
+ channel: "channel_pc_web",
2415
+ sec_user_id: data$1.sec_uid,
2416
+ max_cursor: data$1.max_cursor ?? "0",
2417
+ min_cursor: "0",
2418
+ whale_cut_token: "",
2419
+ count: data$1.number ?? 18,
2420
+ from: "1",
2421
+ update_version_code: "170400",
2422
+ pc_client_type: "1",
2423
+ pc_libra_divert: "Windows",
2424
+ support_h265: "1",
2425
+ support_dash: "1",
2426
+ cpu_core_num: "16",
2427
+ version_code: "170400",
2428
+ version_name: "17.4.0",
2429
+ cookie_enabled: "true",
2430
+ screen_width: "2328",
2431
+ screen_height: "1310",
2432
+ browser_language: "zh-CN",
2433
+ browser_platform: "Win32",
2434
+ browser_name: "Edge",
2435
+ browser_version: this.browserVersion,
2436
+ browser_online: "true",
2437
+ engine_name: "Blink",
2438
+ engine_version: this.browserVersion,
2439
+ os_name: "Windows",
2440
+ os_version: "10",
2441
+ device_memory: "8",
2442
+ platform: "PC",
2443
+ downlink: "10",
2444
+ effective_type: "4g",
2445
+ round_trip_time: "50",
2446
+ webid: "7487210762873685515",
2447
+ msToken: douyinSign.Mstoken(184),
2448
+ verifyFp: fp,
2449
+ fp
2450
+ })}`;
2451
+ }
2374
2452
  getUserProfile(data$1) {
2375
2453
  return `https://www.douyin.com/aweme/v1/web/user/profile/other/?${buildQueryString({
2376
2454
  ...this.getBaseParams(),
@@ -2737,17 +2815,93 @@ var init_getdata$3 = __esmMin(() => {
2737
2815
  });
2738
2816
  }
2739
2817
  case "userVideoList": {
2740
- const url = douyinApiUrls$1.getUserVideoList({ sec_uid: data$1.sec_uid });
2741
- const customConfig = {
2742
- ...baseRequestConfig,
2743
- headers: {
2744
- ...baseRequestConfig.headers,
2745
- ...(!requestConfig?.headers || !("Referer" in requestConfig.headers)) && { Referer: `https://www.douyin.com/user/${data$1.sec_uid}` }
2746
- }
2747
- };
2748
- return await GlobalGetData$3(data$1.methodType, {
2749
- ...customConfig,
2750
- url: buildSignedUrl(url, signType, userAgent)
2818
+ const urlGenerator = (params) => douyinApiUrls$1.getUserVideoList(params);
2819
+ return await fetchPaginatedData({
2820
+ type: data$1.methodType,
2821
+ apiUrlGenerator: urlGenerator,
2822
+ params: {
2823
+ ...data$1,
2824
+ max_cursor: data$1.max_cursor
2825
+ },
2826
+ maxPageSize: 18,
2827
+ requestConfig: {
2828
+ ...baseRequestConfig,
2829
+ headers: {
2830
+ ...baseRequestConfig.headers,
2831
+ ...(!requestConfig?.headers || !("Referer" in requestConfig.headers)) && { Referer: `https://www.douyin.com/user/${data$1.sec_uid}` }
2832
+ }
2833
+ },
2834
+ signType,
2835
+ extractList: (resp) => resp.aweme_list ?? [],
2836
+ updateParams: (params, resp) => ({
2837
+ ...params,
2838
+ max_cursor: resp.max_cursor?.toString() ?? "0"
2839
+ }),
2840
+ hasMore: (resp) => resp.has_more === 1,
2841
+ formatFinalResponse: (resp, list) => ({
2842
+ ...resp,
2843
+ aweme_list: list
2844
+ })
2845
+ });
2846
+ }
2847
+ case "userFavoriteList": {
2848
+ const urlGenerator = (params) => douyinApiUrls$1.getUserFavoriteList(params);
2849
+ return await fetchPaginatedData({
2850
+ type: data$1.methodType,
2851
+ apiUrlGenerator: urlGenerator,
2852
+ params: {
2853
+ ...data$1,
2854
+ max_cursor: data$1.max_cursor
2855
+ },
2856
+ maxPageSize: 18,
2857
+ requestConfig: {
2858
+ ...baseRequestConfig,
2859
+ headers: {
2860
+ ...baseRequestConfig.headers,
2861
+ ...(!requestConfig?.headers || !("Referer" in requestConfig.headers)) && { Referer: `https://www.douyin.com/user/${data$1.sec_uid}` }
2862
+ }
2863
+ },
2864
+ signType,
2865
+ extractList: (resp) => resp.aweme_list ?? [],
2866
+ updateParams: (params, resp) => ({
2867
+ ...params,
2868
+ max_cursor: resp.max_cursor?.toString() ?? "0"
2869
+ }),
2870
+ hasMore: (resp) => resp.has_more === 1,
2871
+ formatFinalResponse: (resp, list) => ({
2872
+ ...resp,
2873
+ aweme_list: list
2874
+ })
2875
+ });
2876
+ }
2877
+ case "userRecommendList": {
2878
+ const urlGenerator = (params) => douyinApiUrls$1.getUserRecommendList(params);
2879
+ return await fetchPaginatedData({
2880
+ type: data$1.methodType,
2881
+ apiUrlGenerator: urlGenerator,
2882
+ params: {
2883
+ ...data$1,
2884
+ max_cursor: data$1.max_cursor
2885
+ },
2886
+ maxPageSize: 18,
2887
+ requestConfig: {
2888
+ ...baseRequestConfig,
2889
+ headers: {
2890
+ ...baseRequestConfig.headers,
2891
+ ...(!requestConfig?.headers || !("Referer" in requestConfig.headers)) && { Referer: `https://www.douyin.com/user/${data$1.sec_uid}` }
2892
+ }
2893
+ },
2894
+ signType,
2895
+ extractList: (resp) => resp.aweme_list ?? [],
2896
+ updateParams: (params, resp) => ({
2897
+ ...params,
2898
+ max_cursor: resp.max_cursor?.toString() ?? "0"
2899
+ }),
2900
+ hasMore: (resp) => resp.has_more === 1,
2901
+ formatFinalResponse: (resp, list) => ({
2902
+ ...resp,
2903
+ aweme_list: list
2904
+ })
2751
2905
  });
2752
2906
  }
2753
2907
  case "suggestWords": {
@@ -3240,6 +3394,18 @@ async function fetchUserVideoList(options, cookie, requestConfig) {
3240
3394
  requestConfig
3241
3395
  });
3242
3396
  }
3397
+ async function fetchUserFavoriteList(options, cookie, requestConfig) {
3398
+ return fetchDouyinInternal("userFavoriteList", options, {
3399
+ cookie,
3400
+ requestConfig
3401
+ });
3402
+ }
3403
+ async function fetchUserRecommendList(options, cookie, requestConfig) {
3404
+ return fetchDouyinInternal("userRecommendList", options, {
3405
+ cookie,
3406
+ requestConfig
3407
+ });
3408
+ }
3243
3409
  var init_user$1 = __esmMin(() => {
3244
3410
  init_internal$2();
3245
3411
  });
@@ -3294,6 +3460,8 @@ function createBoundDouyinFetcher(cookie, requestConfig) {
3294
3460
  fetchCommentReplies: (options, reqConfig) => fetchCommentReplies(options, cookie, reqConfig ?? requestConfig),
3295
3461
  fetchUserProfile: (options, reqConfig) => fetchUserProfile$1(options, cookie, reqConfig ?? requestConfig),
3296
3462
  fetchUserVideoList: (options, reqConfig) => fetchUserVideoList(options, cookie, reqConfig ?? requestConfig),
3463
+ fetchUserFavoriteList: (options, reqConfig) => fetchUserFavoriteList(options, cookie, reqConfig ?? requestConfig),
3464
+ fetchUserRecommendList: (options, reqConfig) => fetchUserRecommendList(options, cookie, reqConfig ?? requestConfig),
3297
3465
  searchContent: (options, reqConfig) => searchContent(options, cookie, reqConfig ?? requestConfig),
3298
3466
  fetchSuggestWords: (options, reqConfig) => fetchSuggestWords(options, cookie, reqConfig ?? requestConfig),
3299
3467
  fetchMusicInfo: (options, reqConfig) => fetchMusicInfo(options, cookie, reqConfig ?? requestConfig),
@@ -3334,6 +3502,8 @@ var init_douyin$2 = __esmMin(() => {
3334
3502
  fetchCommentReplies,
3335
3503
  fetchUserProfile: fetchUserProfile$1,
3336
3504
  fetchUserVideoList,
3505
+ fetchUserFavoriteList,
3506
+ fetchUserRecommendList,
3337
3507
  searchContent,
3338
3508
  fetchSuggestWords,
3339
3509
  fetchMusicInfo,
@@ -7519,7 +7689,9 @@ var init_Network$1 = __esmMin(() => {
7519
7689
  }
7520
7690
  return response;
7521
7691
  }
7522
- async getLongLink(url = "") {
7692
+ async getLongLink(url = "", depth = 0) {
7693
+ const MAX_REDIRECTS = 10;
7694
+ if (depth > MAX_REDIRECTS) throw new Error(`重定向次数超过限制 (${MAX_REDIRECTS})`);
7523
7695
  const targetUrl = this.url || url;
7524
7696
  try {
7525
7697
  new URL(targetUrl);
@@ -7544,10 +7716,17 @@ var init_Network$1 = __esmMin(() => {
7544
7716
  return response.request?.res?.responseUrl ?? response.config?.url ?? targetUrl;
7545
7717
  } catch (error) {
7546
7718
  const axiosError = error;
7547
- if (axiosError.response?.status === 302 && axiosError.response.headers?.location) {
7548
- const redirectUrl = axiosError.response.headers.location;
7549
- logger.info(`检测到302重定向,目标地址: ${redirectUrl}`);
7550
- return await this.getLongLink(redirectUrl);
7719
+ if (axiosError.response?.status && [
7720
+ 301,
7721
+ 302,
7722
+ 303,
7723
+ 307,
7724
+ 308
7725
+ ].includes(axiosError.response.status) && axiosError.response.headers?.location) {
7726
+ const location = axiosError.response.headers.location;
7727
+ const redirectUrl = location.startsWith("http") ? location : new URL(location, targetUrl).href;
7728
+ logger.info(`检测到${axiosError.response.status}重定向 (深度: ${depth + 1}), 目标: ${redirectUrl}`);
7729
+ return await this.getLongLink(redirectUrl, depth + 1);
7551
7730
  }
7552
7731
  if (method === "head") {
7553
7732
  logger.debug(`HEAD 请求失败 (${axiosError.code || axiosError.message}),尝试 GET 请求`);
@@ -8390,6 +8569,7 @@ var init_douyin = __esmMin(async () => {
8390
8569
  await fs.promises.mkdir(path.dirname(this.dbPath), { recursive: true });
8391
8570
  this.db = new sqlite3.Database(this.dbPath);
8392
8571
  await this.createTables();
8572
+ await this.migrate();
8393
8573
  logger.debug("[DouyinDB] 数据库模型同步成功");
8394
8574
  logger.debug("[DouyinDB] 正在同步配置订阅...");
8395
8575
  logger.debug("[DouyinDB] 配置项数量:", Config.pushlist.douyin?.length || 0);
@@ -8402,15 +8582,33 @@ var init_douyin = __esmMin(async () => {
8402
8582
  }
8403
8583
  return this;
8404
8584
  }
8585
+ async migrate() {
8586
+ try {
8587
+ try {
8588
+ await this.runQuery("SELECT pushType FROM AwemeCaches LIMIT 1");
8589
+ } catch {
8590
+ logger.info("[DouyinDB] 检测到 AwemeCaches 表缺少 pushType 字段,开始执行迁移...");
8591
+ await this.runQuery("ALTER TABLE AwemeCaches ADD COLUMN pushType TEXT DEFAULT 'post'");
8592
+ await this.runQuery("ALTER TABLE AwemeCaches RENAME TO AwemeCaches_old");
8593
+ await this.runQuery(`\n CREATE TABLE IF NOT EXISTS AwemeCaches (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n aweme_id TEXT NOT NULL,\n sec_uid TEXT NOT NULL,\n groupId TEXT NOT NULL,\n pushType TEXT DEFAULT 'post',\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid),\n FOREIGN KEY (groupId) REFERENCES Groups(id),\n UNIQUE(aweme_id, sec_uid, groupId, pushType)\n )\n `);
8594
+ await this.runQuery(`\n INSERT INTO AwemeCaches (id, aweme_id, sec_uid, groupId, pushType, createdAt, updatedAt)\n SELECT id, aweme_id, sec_uid, groupId, pushType, createdAt, updatedAt\n FROM AwemeCaches_old\n `);
8595
+ await this.runQuery("DROP TABLE AwemeCaches_old");
8596
+ logger.info("[DouyinDB] AwemeCaches 表迁移完成");
8597
+ }
8598
+ } catch (error) {
8599
+ logger.error("[DouyinDB] 数据库迁移失败:", error);
8600
+ }
8601
+ }
8405
8602
  async createTables() {
8406
8603
  for (const query of [
8407
8604
  `CREATE TABLE IF NOT EXISTS Bots (\n id TEXT PRIMARY KEY,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n )`,
8408
8605
  `CREATE TABLE IF NOT EXISTS Groups (\n id TEXT PRIMARY KEY,\n botId TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (botId) REFERENCES Bots(id)\n )`,
8409
8606
  `CREATE TABLE IF NOT EXISTS DouyinUsers (\n sec_uid TEXT PRIMARY KEY,\n short_id TEXT,\n remark TEXT,\n living INTEGER DEFAULT 0,\n filterMode TEXT DEFAULT 'blacklist',\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n )`,
8410
8607
  `CREATE TABLE IF NOT EXISTS GroupUserSubscriptions (\n groupId TEXT,\n sec_uid TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (groupId, sec_uid),\n FOREIGN KEY (groupId) REFERENCES Groups(id),\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid)\n )`,
8411
- `CREATE TABLE IF NOT EXISTS AwemeCaches (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n aweme_id TEXT NOT NULL,\n sec_uid TEXT NOT NULL,\n groupId TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid),\n FOREIGN KEY (groupId) REFERENCES Groups(id),\n UNIQUE(aweme_id, sec_uid, groupId)\n )`,
8608
+ `CREATE TABLE IF NOT EXISTS AwemeCaches (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n aweme_id TEXT NOT NULL,\n sec_uid TEXT NOT NULL,\n groupId TEXT NOT NULL,\n pushType TEXT DEFAULT 'post',\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid),\n FOREIGN KEY (groupId) REFERENCES Groups(id),\n UNIQUE(aweme_id, sec_uid, groupId, pushType)\n )`,
8412
8609
  `CREATE TABLE IF NOT EXISTS FilterWords (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n sec_uid TEXT NOT NULL,\n word TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid),\n UNIQUE(sec_uid, word)\n )`,
8413
- `CREATE TABLE IF NOT EXISTS FilterTags (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n sec_uid TEXT NOT NULL,\n tag TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid),\n UNIQUE(sec_uid, tag)\n )`
8610
+ `CREATE TABLE IF NOT EXISTS FilterTags (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n sec_uid TEXT NOT NULL,\n tag TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid),\n UNIQUE(sec_uid, tag)\n )`,
8611
+ `CREATE TABLE IF NOT EXISTS ListSnapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n sec_uid TEXT NOT NULL,\n pushType TEXT NOT NULL,\n aweme_id TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (sec_uid) REFERENCES DouyinUsers(sec_uid),\n UNIQUE(sec_uid, pushType, aweme_id)\n )`
8414
8612
  ]) await this.runQuery(query);
8415
8613
  }
8416
8614
  runQuery(sql, params = []) {
@@ -8552,36 +8750,47 @@ var init_douyin = __esmMin(async () => {
8552
8750
  await this.runQuery("DELETE FROM AwemeCaches WHERE groupId = ? AND sec_uid = ?", [groupId, sec_uid]);
8553
8751
  return result.changes > 0;
8554
8752
  }
8555
- async addAwemeCache(aweme_id, sec_uid, groupId) {
8556
- let cache = await this.getQuery("SELECT * FROM AwemeCaches WHERE aweme_id = ? AND sec_uid = ? AND groupId = ?", [
8753
+ async addAwemeCache(aweme_id, sec_uid, groupId, pushType = "post") {
8754
+ let cache = await this.getQuery("SELECT * FROM AwemeCaches WHERE aweme_id = ? AND sec_uid = ? AND groupId = ? AND pushType = ?", [
8557
8755
  aweme_id,
8558
8756
  sec_uid,
8559
- groupId
8757
+ groupId,
8758
+ pushType
8560
8759
  ]);
8561
8760
  if (!cache) {
8562
8761
  const now = (/* @__PURE__ */ new Date()).toISOString();
8563
8762
  cache = {
8564
- id: (await this.runQuery("INSERT INTO AwemeCaches (aweme_id, sec_uid, groupId, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)", [
8763
+ id: (await this.runQuery("INSERT INTO AwemeCaches (aweme_id, sec_uid, groupId, pushType, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?)", [
8565
8764
  aweme_id,
8566
8765
  sec_uid,
8567
8766
  groupId,
8767
+ pushType,
8568
8768
  now,
8569
8769
  now
8570
8770
  ])).lastID,
8571
8771
  aweme_id,
8572
8772
  sec_uid,
8573
8773
  groupId,
8774
+ pushType,
8574
8775
  createdAt: now,
8575
8776
  updatedAt: now
8576
8777
  };
8577
8778
  }
8578
8779
  return cache;
8579
8780
  }
8580
- async isAwemePushed(aweme_id, sec_uid, groupId) {
8581
- return ((await this.getQuery("SELECT COUNT(*) as count FROM AwemeCaches WHERE aweme_id = ? AND sec_uid = ? AND groupId = ?", [
8781
+ async isAwemePushed(aweme_id, sec_uid, groupId, pushType = "post") {
8782
+ return ((await this.getQuery("SELECT COUNT(*) as count FROM AwemeCaches WHERE aweme_id = ? AND sec_uid = ? AND groupId = ? AND pushType = ?", [
8582
8783
  aweme_id,
8583
8784
  sec_uid,
8584
- groupId
8785
+ groupId,
8786
+ pushType
8787
+ ]))?.count || 0) > 0;
8788
+ }
8789
+ async hasHistory(sec_uid, groupId, pushType) {
8790
+ return ((await this.getQuery("SELECT COUNT(*) as count FROM AwemeCaches WHERE sec_uid = ? AND groupId = ? AND pushType = ? LIMIT 1", [
8791
+ sec_uid,
8792
+ groupId,
8793
+ pushType
8585
8794
  ]))?.count || 0) > 0;
8586
8795
  }
8587
8796
  async getBotGroups(botId) {
@@ -8862,6 +9071,24 @@ var init_douyin = __esmMin(async () => {
8862
9071
  }
8863
9072
  };
8864
9073
  }
9074
+ async isAwemeInList(aweme_id, sec_uid, pushType) {
9075
+ return ((await this.getQuery("SELECT COUNT(*) as count FROM ListSnapshots WHERE aweme_id = ? AND sec_uid = ? AND pushType = ?", [
9076
+ aweme_id,
9077
+ sec_uid,
9078
+ pushType
9079
+ ]))?.count || 0) > 0;
9080
+ }
9081
+ async updateListSnapshot(sec_uid, pushType, aweme_ids) {
9082
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9083
+ await this.runQuery("DELETE FROM ListSnapshots WHERE sec_uid = ? AND pushType = ?", [sec_uid, pushType]);
9084
+ for (const aweme_id of aweme_ids) await this.runQuery("INSERT OR IGNORE INTO ListSnapshots (sec_uid, pushType, aweme_id, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)", [
9085
+ sec_uid,
9086
+ pushType,
9087
+ aweme_id,
9088
+ now,
9089
+ now
9090
+ ]);
9091
+ }
8865
9092
  };
8866
9093
  });
8867
9094
  var db_exports = __export({
@@ -14049,6 +14276,38 @@ const webConfig = defineConfig({
14049
14276
  isRequired: false,
14050
14277
  description: "博主的抖音名称"
14051
14278
  }),
14279
+ components.divider.create("push:douyin:divider-pushTypes", {
14280
+ description: "推送类型配置",
14281
+ descPosition: 20
14282
+ }),
14283
+ components.checkbox.group("pushTypes", {
14284
+ label: "推送类型",
14285
+ description: "选择要推送的内容类型,可多选",
14286
+ orientation: "horizontal",
14287
+ color: "warning",
14288
+ checkbox: [
14289
+ components.checkbox.create("pushTypes:checkbox:post", {
14290
+ label: "作品列表",
14291
+ description: "推送博主发布的作品",
14292
+ value: "post"
14293
+ }),
14294
+ components.checkbox.create("pushTypes:checkbox:favorite", {
14295
+ label: "喜欢列表",
14296
+ description: "推送博主喜欢的作品",
14297
+ value: "favorite"
14298
+ }),
14299
+ components.checkbox.create("pushTypes:checkbox:recommend", {
14300
+ label: "推荐列表",
14301
+ description: "推送博主的推荐作品",
14302
+ value: "recommend"
14303
+ }),
14304
+ components.checkbox.create("pushTypes:checkbox:live", {
14305
+ label: "直播",
14306
+ description: "推送博主开播通知",
14307
+ value: "live"
14308
+ })
14309
+ ]
14310
+ }),
14052
14311
  components.divider.create("push:douyin:divider-1", {
14053
14312
  description: "过滤系统",
14054
14313
  descPosition: 20
@@ -14319,6 +14578,7 @@ var hasNestedStructure = (obj, path$1) => {
14319
14578
  };
14320
14579
  await init_src();
14321
14580
  await init_date_fns();
14581
+ await init_locale();
14322
14582
  await init_utils$1();
14323
14583
  await init_amagiClient();
14324
14584
  await init_Config();
@@ -14616,7 +14876,7 @@ var Bilibili = class extends Base {
14616
14876
  dianzan: Count(dynamicInfo.data.data.item.modules.module_stat.like.count),
14617
14877
  pinglun: Count(dynamicInfo.data.data.item.modules.module_stat.comment.count),
14618
14878
  share: Count(dynamicInfo.data.data.item.modules.module_stat.forward.count),
14619
- create_time: dynamicInfo.data.data.item.modules.module_author.pub_time,
14879
+ create_time: TimeFormatter.toRelative(dynamicInfo.data.data.item.modules.module_author.pub_ts),
14620
14880
  avatar_url: dynamicInfo.data.data.item.modules.module_author.face,
14621
14881
  frame: dynamicInfo.data.data.item.modules.module_author.pendant.image,
14622
14882
  share_url: "https://t.bilibili.com/" + dynamicInfo.data.data.item.id_str,
@@ -14626,7 +14886,7 @@ var Bilibili = class extends Base {
14626
14886
  total_favorited: Count(userProfileData.data.data.like_num),
14627
14887
  following_count: Count(userProfileData.data.data.card.attention),
14628
14888
  decoration_card: generateDecorationCard(dynamicInfo.data.data.item.modules.module_author.decoration_card),
14629
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
14889
+ render_time: TimeFormatter.now(),
14630
14890
  dynamicTYPE: "图文动态",
14631
14891
  imageLayout: Config.bilibili.imageLayout,
14632
14892
  additional: parseAdditionalCard(dynamicInfo.data.data.item.modules.module_dynamic.additional)
@@ -14650,7 +14910,7 @@ var Bilibili = class extends Base {
14650
14910
  dianzan: Count(dynamicInfo.data.data.item.modules.module_stat.like.count),
14651
14911
  pinglun: Count(dynamicInfo.data.data.item.modules.module_stat.comment.count),
14652
14912
  share: Count(dynamicInfo.data.data.item.modules.module_stat.forward.count),
14653
- create_time: dynamicInfo.data.data.item.modules.module_author.pub_time,
14913
+ create_time: TimeFormatter.toRelative(dynamicInfo.data.data.item.modules.module_author.pub_ts),
14654
14914
  avatar_url: dynamicInfo.data.data.item.modules.module_author.face,
14655
14915
  frame: dynamicInfo.data.data.item.modules.module_author.pendant.image,
14656
14916
  share_url: "https://t.bilibili.com/" + dynamicInfo.data.data.item.id_str,
@@ -14660,7 +14920,7 @@ var Bilibili = class extends Base {
14660
14920
  total_favorited: Count(userProfileData.data.data.like_num),
14661
14921
  following_count: Count(userProfileData.data.data.card.attention),
14662
14922
  decoration_card: generateDecorationCard(dynamicInfo.data.data.item.modules.module_author.decoration_card),
14663
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
14923
+ render_time: TimeFormatter.now(),
14664
14924
  dynamicTYPE: "纯文动态",
14665
14925
  additional: parseAdditionalCard(dynamicInfo.data.data.item.modules.module_dynamic.additional)
14666
14926
  }));
@@ -14683,7 +14943,7 @@ var Bilibili = class extends Base {
14683
14943
  view: dynamicInfo.data.data.item.orig.modules.module_dynamic.major.archive.stat.view,
14684
14944
  play: dynamicInfo.data.data.item.orig.modules.module_dynamic.major.archive.stat.play,
14685
14945
  cover: dynamicInfo.data.data.item.orig.modules.module_dynamic.major.archive.cover,
14686
- create_time: format(fromUnixTime(dynamicInfo.data.data.item.orig.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
14946
+ create_time: TimeFormatter.toDateTime(dynamicInfo.data.data.item.orig.modules.module_author.pub_ts),
14687
14947
  decoration_card: generateDecorationCard(dynamicInfo.data.data.item.orig.modules.module_author.decoration_card),
14688
14948
  frame: dynamicInfo.data.data.item.orig.modules.module_author.pendant.image
14689
14949
  };
@@ -14697,7 +14957,7 @@ var Bilibili = class extends Base {
14697
14957
  data$1 = {
14698
14958
  title: dynamicInfo.data.data.item.orig.modules.module_dynamic.major?.opus?.title ?? null,
14699
14959
  username: checkvip$2(dynamicInfo.data.data.item.orig.modules.module_author),
14700
- create_time: format(fromUnixTime(dynamicInfo.data.data.item.orig.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
14960
+ create_time: TimeFormatter.toDateTime(dynamicInfo.data.data.item.orig.modules.module_author.pub_ts),
14701
14961
  avatar_url: dynamicInfo.data.data.item.orig.modules.module_author.face,
14702
14962
  text: replacetext(br$3(dynamicInfo.data.data.item.orig.modules.module_dynamic.major.opus.summary.text), dynamicInfo.data.data.item.orig.modules.module_dynamic.major.opus.summary.rich_text_nodes),
14703
14963
  image_url: cardData.item.pictures && cover(cardData.item.pictures),
@@ -14709,7 +14969,7 @@ var Bilibili = class extends Base {
14709
14969
  case DynamicType.WORD:
14710
14970
  data$1 = {
14711
14971
  username: checkvip$2(dynamicInfo.data.data.item.orig.modules.module_author),
14712
- create_time: format(fromUnixTime(dynamicInfo.data.data.item.orig.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
14972
+ create_time: TimeFormatter.toDateTime(dynamicInfo.data.data.item.orig.modules.module_author.pub_ts),
14713
14973
  avatar_url: dynamicInfo.data.data.item.orig.modules.module_author.face,
14714
14974
  text: replacetext(br$3(dynamicInfo.data.data.item.orig.modules.module_dynamic.major.opus.summary.text), dynamicInfo.data.data.item.orig.modules.module_dynamic.major.opus.summary.rich_text_nodes),
14715
14975
  decoration_card: generateDecorationCard(dynamicInfo.data.data.item.orig.modules.module_author.decoration_card),
@@ -14720,7 +14980,7 @@ var Bilibili = class extends Base {
14720
14980
  const liveData = JSON.parse(dynamicInfo.data.data.item.orig.modules.module_dynamic.major.live_rcmd.content);
14721
14981
  data$1 = {
14722
14982
  username: checkvip$2(dynamicInfo.data.data.item.orig.modules.module_author),
14723
- create_time: format(fromUnixTime(dynamicInfo.data.data.item.orig.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
14983
+ create_time: TimeFormatter.toDateTime(dynamicInfo.data.data.item.orig.modules.module_author.pub_ts),
14724
14984
  avatar_url: dynamicInfo.data.data.item.orig.modules.module_author.face,
14725
14985
  decoration_card: generateDecorationCard(dynamicInfo.data.data.item.orig.modules.module_author.decoration_card),
14726
14986
  frame: dynamicInfo.data.data.item.orig.modules.module_author.pendant.image,
@@ -14743,7 +15003,7 @@ var Bilibili = class extends Base {
14743
15003
  dianzan: Count(dynamicInfo.data.data.item.modules.module_stat.like.count),
14744
15004
  pinglun: Count(dynamicInfo.data.data.item.modules.module_stat.comment.count),
14745
15005
  share: Count(dynamicInfo.data.data.item.modules.module_stat.forward.count),
14746
- create_time: dynamicInfo.data.data.item.modules.module_author.pub_time,
15006
+ create_time: TimeFormatter.toRelative(dynamicInfo.data.data.item.modules.module_author.pub_ts),
14747
15007
  avatar_url: dynamicInfo.data.data.item.modules.module_author.face,
14748
15008
  frame: dynamicInfo.data.data.item.modules.module_author.pendant.image,
14749
15009
  share_url: "https://t.bilibili.com/" + dynamicInfo.data.data.item.id_str,
@@ -14754,7 +15014,7 @@ var Bilibili = class extends Base {
14754
15014
  following_count: Count(userProfileData.data.data.card.attention),
14755
15015
  dynamicTYPE: "转发动态解析",
14756
15016
  decoration_card: generateDecorationCard(dynamicInfo.data.data.item.modules.module_author.decorate),
14757
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
15017
+ render_time: TimeFormatter.now(),
14758
15018
  original_content: { [dynamicInfo.data.data.item.orig.type]: data$1 }
14759
15019
  }));
14760
15020
  break;
@@ -14786,7 +15046,7 @@ var Bilibili = class extends Base {
14786
15046
  view: Count(dycrad.stat.view),
14787
15047
  coin: Count(dycrad.stat.coin),
14788
15048
  duration_text: dynamicInfo.data.data.item.modules.module_dynamic.major.archive.duration_text,
14789
- create_time: format(fromUnixTime(INFODATA.data.data.ctime), "yyyy-MM-dd HH:mm"),
15049
+ create_time: TimeFormatter.toDateTime(INFODATA.data.data.ctime),
14790
15050
  avatar_url: INFODATA.data.data.owner.face,
14791
15051
  frame: dynamicInfo.data.data.item.modules.module_author.pendant.image,
14792
15052
  share_url: "https://www.bilibili.com/video/" + bvid,
@@ -14795,7 +15055,7 @@ var Bilibili = class extends Base {
14795
15055
  user_shortid: userProfileData.data.data.card.mid,
14796
15056
  total_favorited: Count(userProfileData.data.data.like_num),
14797
15057
  following_count: Count(userProfileData.data.data.card.attention),
14798
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
15058
+ render_time: TimeFormatter.now(),
14799
15059
  dynamicTYPE: "视频动态",
14800
15060
  dynamic_id: dynamicInfo.data.data.item.id_str
14801
15061
  });
@@ -14815,8 +15075,8 @@ var Bilibili = class extends Base {
14815
15075
  avatar_url: userINFO.data.data.card.face,
14816
15076
  frame: dynamicInfo.data.data.item.modules.module_author.pendant.image,
14817
15077
  fans: Count(userINFO.data.data.follower),
14818
- create_time: format(fromUnixTime(dynamicInfo.data.data.item.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
14819
- now_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
15078
+ create_time: TimeFormatter.toDateTime(dynamicInfo.data.data.item.modules.module_author.pub_ts),
15079
+ now_time: TimeFormatter.now(),
14820
15080
  share_url: "https://live.bilibili.com/" + dynamicCARD.live_play_info.room_id,
14821
15081
  dynamicTYPE: "直播动态"
14822
15082
  });
@@ -14851,7 +15111,7 @@ var Bilibili = class extends Base {
14851
15111
  username: checkvip$2(userProfileData.data.data.card),
14852
15112
  avatar_url: userProfileData.data.data.card.face,
14853
15113
  frame: dynamicInfo.data.data.item.modules.module_author.pendant.image,
14854
- create_time: format(fromUnixTime(dynamicInfo.data.data.item.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
15114
+ create_time: TimeFormatter.toDateTime(dynamicInfo.data.data.item.modules.module_author.pub_ts),
14855
15115
  title: articleData.title,
14856
15116
  summary: articleData.summary,
14857
15117
  banner_url: articleData.banner_url || articleData.image_urls && articleData.image_urls[0] || "",
@@ -14860,7 +15120,7 @@ var Bilibili = class extends Base {
14860
15120
  opus: articleContent.opus || void 0,
14861
15121
  content: articleContent.content || void 0,
14862
15122
  stats: articleData.stats,
14863
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
15123
+ render_time: TimeFormatter.now(),
14864
15124
  share_url: articleContent.dyn_id_str ? `https://www.bilibili.com/opus/${articleContent.dyn_id_str}` : `https://www.bilibili.com/read/cv${articleContent.id}`,
14865
15125
  dynamicTYPE: "专栏动态解析",
14866
15126
  user_shortid: userProfileData.data.data.card.mid,
@@ -14905,7 +15165,7 @@ var Bilibili = class extends Base {
14905
15165
  frame: userProfileData.data.data.card.pendant.image,
14906
15166
  fans: Count(userProfileData.data.data.card.fans),
14907
15167
  create_time: liveInfo.data.data.live_time === "-62170012800" ? "获取失败" : liveInfo.data.data.live_time,
14908
- now_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
15168
+ now_time: TimeFormatter.now(),
14909
15169
  share_url: "https://live.bilibili.com/" + liveInfo.data.data.room_id,
14910
15170
  dynamicTYPE: "直播"
14911
15171
  });
@@ -15017,6 +15277,35 @@ var Bilibili = class extends Base {
15017
15277
  };
15018
15278
  var checkvip$2 = (member) => member.vip.status === 1 ? `<span style="color: ${member.vip.nickname_color ?? "#FB7299"}; font-weight: 700;">${member.name}</span>` : `<span style="color: ${Common.useDarkTheme() ? "#e9e9e9" : "#313131"}; font-weight: 700;">${member.name}</span>`;
15019
15279
  var br$3 = (data$1) => data$1 = data$1.replace(/\n/g, "<br>");
15280
+ const TimeFormatter = {
15281
+ toRelative: (timestamp) => {
15282
+ try {
15283
+ return formatDistanceToNow(fromUnixTime(timestamp), {
15284
+ addSuffix: true,
15285
+ locale: zhCN
15286
+ });
15287
+ } catch (error) {
15288
+ logger.warn("相对时间格式化失败:", error);
15289
+ return TimeFormatter.toDateTime(timestamp);
15290
+ }
15291
+ },
15292
+ toDateTime: (timestamp) => {
15293
+ try {
15294
+ return format(fromUnixTime(timestamp), "yyyy-MM-dd HH:mm");
15295
+ } catch (error) {
15296
+ logger.warn("日期时间格式化失败:", error);
15297
+ return "时间格式错误";
15298
+ }
15299
+ },
15300
+ now: () => {
15301
+ try {
15302
+ return format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss");
15303
+ } catch (error) {
15304
+ logger.warn("当前时间格式化失败:", error);
15305
+ return (/* @__PURE__ */ new Date()).toISOString();
15306
+ }
15307
+ }
15308
+ };
15020
15309
  const replacetext = (text, rich_text_nodes) => {
15021
15310
  for (const tag of rich_text_nodes) {
15022
15311
  const escapedText = tag.orig_text.replace(/([.*+?^${}()|[\]\\])/g, "\\$1").replace(/\n/g, "\\n");
@@ -15736,7 +16025,6 @@ const bilibiliLogin = async (e) => {
15736
16025
  }
15737
16026
  };
15738
16027
  await init_src();
15739
- await init_date_fns();
15740
16028
  await init_module();
15741
16029
  await init_amagiClient();
15742
16030
  await init_Config();
@@ -15831,7 +16119,7 @@ var Bilibilipush = class extends Base {
15831
16119
  dianzan: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.like.count),
15832
16120
  pinglun: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.comment.count),
15833
16121
  share: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.forward.count),
15834
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
16122
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts),
15835
16123
  avatar_url: data$1[dynamicId].Dynamic_Data.modules.module_author.face,
15836
16124
  frame: data$1[dynamicId].Dynamic_Data.modules.module_author.pendant.image,
15837
16125
  share_url: "https://t.bilibili.com/" + data$1[dynamicId].Dynamic_Data.id_str,
@@ -15841,7 +16129,7 @@ var Bilibilipush = class extends Base {
15841
16129
  total_favorited: Count(userINFO.data.data.like_num),
15842
16130
  following_count: Count(userINFO.data.data.card.attention),
15843
16131
  decoration_card: generateDecorationCard(data$1[dynamicId].Dynamic_Data.modules.module_author.decoration_card),
15844
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
16132
+ render_time: TimeFormatter.now(),
15845
16133
  imageLayout: Config.bilibili.imageLayout,
15846
16134
  additional: parseAdditionalCard(data$1[dynamicId].Dynamic_Data.modules.module_dynamic.additional),
15847
16135
  dynamicTYPE: "图文动态推送"
@@ -15863,7 +16151,7 @@ var Bilibilipush = class extends Base {
15863
16151
  dianzan: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.like.count),
15864
16152
  pinglun: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.comment.count),
15865
16153
  share: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.forward.count),
15866
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
16154
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts),
15867
16155
  avatar_url: data$1[dynamicId].Dynamic_Data.modules.module_author.face,
15868
16156
  frame: data$1[dynamicId].Dynamic_Data.modules.module_author.pendant.image,
15869
16157
  share_url: "https://t.bilibili.com/" + data$1[dynamicId].Dynamic_Data.id_str,
@@ -15873,7 +16161,7 @@ var Bilibilipush = class extends Base {
15873
16161
  total_favorited: Count(userINFO.data.data.like_num),
15874
16162
  following_count: Count(userINFO.data.data.card.attention),
15875
16163
  decoration_card: generateDecorationCard(data$1[dynamicId].Dynamic_Data.modules.module_author.decoration_card),
15876
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
16164
+ render_time: TimeFormatter.now(),
15877
16165
  additional: parseAdditionalCard(data$1[dynamicId].Dynamic_Data.modules.module_dynamic.additional),
15878
16166
  dynamicTYPE: "纯文动态推送"
15879
16167
  });
@@ -15899,7 +16187,7 @@ var Bilibilipush = class extends Base {
15899
16187
  view: Count(dycrad.stat.view),
15900
16188
  coin: Count(dycrad.stat.coin),
15901
16189
  duration_text: data$1[dynamicId].Dynamic_Data.modules.module_dynamic.major?.archive?.duration_text ?? "0:00",
15902
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
16190
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts),
15903
16191
  avatar_url: INFODATA.data.data.owner.face,
15904
16192
  frame: data$1[dynamicId].Dynamic_Data.modules.module_author.pendant.image,
15905
16193
  share_url: "https://www.bilibili.com/video/" + bvid,
@@ -15908,7 +16196,7 @@ var Bilibilipush = class extends Base {
15908
16196
  user_shortid: data$1[dynamicId].host_mid,
15909
16197
  total_favorited: Count(userINFO.data.data.like_num),
15910
16198
  following_count: Count(userINFO.data.data.card.attention),
15911
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
16199
+ render_time: TimeFormatter.now(),
15912
16200
  dynamicTYPE: "视频动态推送",
15913
16201
  dynamic_id: dynamicId
15914
16202
  });
@@ -15923,8 +16211,8 @@ var Bilibilipush = class extends Base {
15923
16211
  avatar_url: userINFO.data.data.card.face,
15924
16212
  frame: data$1[dynamicId].Dynamic_Data.modules.module_author.pendant.image,
15925
16213
  fans: Count(userINFO.data.data.follower),
15926
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
15927
- now_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
16214
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts),
16215
+ now_time: TimeFormatter.now(),
15928
16216
  share_url: "https://live.bilibili.com/" + dycrad.live_play_info.room_id,
15929
16217
  dynamicTYPE: "直播动态推送"
15930
16218
  });
@@ -15947,7 +16235,7 @@ var Bilibilipush = class extends Base {
15947
16235
  danmaku: data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major.archive?.stat.danmaku,
15948
16236
  play: data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major.archive?.stat.play,
15949
16237
  cover: data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major.archive?.cover,
15950
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
16238
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pub_ts),
15951
16239
  decoration_card: generateDecorationCard(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.decoration_card),
15952
16240
  frame: data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pendant.image
15953
16241
  };
@@ -15961,7 +16249,7 @@ var Bilibilipush = class extends Base {
15961
16249
  param = {
15962
16250
  title: data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major?.opus?.title ?? null,
15963
16251
  username: checkvip(data$1[dynamicId].Dynamic_Data.orig.modules.module_author),
15964
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
16252
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pub_ts),
15965
16253
  avatar_url: data$1[dynamicId].Dynamic_Data.orig.modules.module_author.face,
15966
16254
  text: replacetext(br$1(data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major.opus.summary.text), data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major.opus.summary.rich_text_nodes),
15967
16255
  image_url: cardData.item.pictures && cover(cardData.item.pictures),
@@ -15973,7 +16261,7 @@ var Bilibilipush = class extends Base {
15973
16261
  case DynamicType.WORD:
15974
16262
  param = {
15975
16263
  username: checkvip(data$1[dynamicId].Dynamic_Data.orig.modules.module_author),
15976
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
16264
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pub_ts),
15977
16265
  avatar_url: data$1[dynamicId].Dynamic_Data.orig.modules.module_author.face,
15978
16266
  text: replacetext(br$1(data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major.opus.summary.text), data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major.opus.summary.rich_text_nodes),
15979
16267
  decoration_card: generateDecorationCard(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.decoration_card),
@@ -15984,7 +16272,7 @@ var Bilibilipush = class extends Base {
15984
16272
  const liveData = JSON.parse(data$1[dynamicId].Dynamic_Data.orig.modules.module_dynamic.major.live_rcmd.content);
15985
16273
  param = {
15986
16274
  username: checkvip(data$1[dynamicId].Dynamic_Data.orig.modules.module_author),
15987
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
16275
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pub_ts),
15988
16276
  avatar_url: data$1[dynamicId].Dynamic_Data.orig.modules.module_author.face,
15989
16277
  decoration_card: generateDecorationCard(data$1[dynamicId].Dynamic_Data.orig.modules.module_author.decoration_card),
15990
16278
  frame: data$1[dynamicId].Dynamic_Data.orig.modules.module_author.pendant.image,
@@ -16006,7 +16294,7 @@ var Bilibilipush = class extends Base {
16006
16294
  dianzan: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.like.count),
16007
16295
  pinglun: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.comment.count),
16008
16296
  share: Count(data$1[dynamicId].Dynamic_Data.modules.module_stat.forward.count),
16009
- create_time: data$1[dynamicId].Dynamic_Data.modules.module_author.pub_time,
16297
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts),
16010
16298
  avatar_url: data$1[dynamicId].Dynamic_Data.modules.module_author.face,
16011
16299
  frame: data$1[dynamicId].Dynamic_Data.modules.module_author.pendant.image,
16012
16300
  share_url: "https://t.bilibili.com/" + data$1[dynamicId].Dynamic_Data.id_str,
@@ -16017,7 +16305,7 @@ var Bilibilipush = class extends Base {
16017
16305
  following_count: Count(userINFO.data.data.card.attention),
16018
16306
  dynamicTYPE: "转发动态推送",
16019
16307
  decoration_card: generateDecorationCard(data$1[dynamicId].Dynamic_Data.modules.module_author.decorate),
16020
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
16308
+ render_time: TimeFormatter.now(),
16021
16309
  original_content: { [data$1[dynamicId].Dynamic_Data.orig.type]: param },
16022
16310
  imgList: imgList.length > 0 ? imgList : null
16023
16311
  });
@@ -16038,7 +16326,7 @@ var Bilibilipush = class extends Base {
16038
16326
  username: checkvip(data$1[dynamicId].Dynamic_Data.modules.module_author),
16039
16327
  avatar_url: data$1[dynamicId].Dynamic_Data.modules.module_author.face,
16040
16328
  frame: data$1[dynamicId].Dynamic_Data.modules.module_author.pendant.image,
16041
- create_time: format(fromUnixTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts), "yyyy-MM-dd HH:mm"),
16329
+ create_time: TimeFormatter.toDateTime(data$1[dynamicId].Dynamic_Data.modules.module_author.pub_ts),
16042
16330
  user_shortid: data$1[dynamicId].host_mid,
16043
16331
  fans: Count(userINFO.data.data.follower),
16044
16332
  total_favorited: Count(userINFO.data.data.like_num),
@@ -16051,7 +16339,7 @@ var Bilibilipush = class extends Base {
16051
16339
  opus: articleContent.opus || void 0,
16052
16340
  content: articleContent.content || void 0,
16053
16341
  stats: articleData.stats,
16054
- render_time: format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mm:ss"),
16342
+ render_time: TimeFormatter.now(),
16055
16343
  share_url: articleContent.dyn_id_str ? `https://www.bilibili.com/opus/${articleContent.dyn_id_str}` : `https://www.bilibili.com/read/cv${articleContent.id}`,
16056
16344
  dynamicTYPE: "专栏动态推送"
16057
16345
  });
@@ -16203,7 +16491,7 @@ var Bilibilipush = class extends Base {
16203
16491
  const is_top = dynamic.modules.module_tag?.text === "置顶";
16204
16492
  let shouldPush = false;
16205
16493
  const timeDiffHours = Math.round(timeDifference / 3600 * 100) / 100;
16206
- logger.trace(`\n 前期获取该动态基本信息:\n UP主:${dynamic.modules.module_author.name}\n 动态ID:${dynamic.id_str}\n 发布时间:${format(fromUnixTime(createTime), "yyyy-MM-dd HH:mm")}\n 发布时间戳(s):${createTime}\n 当前时间戳(s):${nowSeconds}\n 时间差(s):${timeDifference}s (${timeDiffHours}h)\n 是否置顶:${is_top}\n 是否在一天内:${timeDifference < 86400 ? logger.green("true") : logger.red("false")}\n `);
16494
+ logger.trace(`\n 前期获取该动态基本信息:\n UP主:${dynamic.modules.module_author.name}\n 动态ID:${dynamic.id_str}\n 发布时间:${TimeFormatter.toDateTime(createTime)}\n 发布时间戳(s):${createTime}\n 当前时间戳(s):${nowSeconds}\n 时间差(s):${timeDifference}s (${timeDiffHours}h)\n 是否置顶:${is_top}\n 是否在一天内:${timeDifference < 86400 ? logger.green("true") : logger.red("false")}\n `);
16207
16495
  if (is_top && timeDifference < 86400 || timeDifference < 86400) {
16208
16496
  shouldPush = true;
16209
16497
  logger.trace(logger.green(`根据以上判断,shoulPush 为 true,将对该动态纳入当天推送列表:https://t.bilibili.com/${dynamic.id_str}\n`));
@@ -16586,6 +16874,7 @@ var DouYin = class extends Base {
16586
16874
  is_mp4;
16587
16875
  is_slides;
16588
16876
  forceBurnDanmaku;
16877
+ hasProcessedLiveImage;
16589
16878
  get botadapter() {
16590
16879
  return this.e.bot?.adapter?.name;
16591
16880
  }
@@ -16596,6 +16885,7 @@ var DouYin = class extends Base {
16596
16885
  this.is_mp4 = iddata?.is_mp4;
16597
16886
  this.is_slides = false;
16598
16887
  this.forceBurnDanmaku = options?.forceBurnDanmaku ?? false;
16888
+ this.hasProcessedLiveImage = false;
16599
16889
  }
16600
16890
  async DouyinHandler(data$1) {
16601
16891
  if (Config.app.EmojiReply && !this.e.isPrivate) try {
@@ -16626,36 +16916,121 @@ var DouYin = class extends Base {
16626
16916
  const imageres = [];
16627
16917
  let image_url = "";
16628
16918
  const images = VideoData.data.aweme_detail.images ?? [];
16629
- for (const [index, imageItem] of images.entries()) {
16630
- image_url = imageItem.url_list[2] || imageItem.url_list[1];
16919
+ if (images.some((item) => item.clip_type !== 2)) {
16920
+ const processedImages = [];
16921
+ const temp = [];
16631
16922
  g_title = VideoData.data.aweme_detail.preview_title.substring(0, 50).replace(/[\\/:*?"<>|\r\n]/g, " ");
16632
- imageres.push(segment.image(image_url));
16633
- imagenum++;
16634
- if (Config.app.removeCache === false) {
16635
- mkdirSync(`${Common.tempDri.images}${g_title}`);
16636
- const path$1 = `${Common.tempDri.images}${g_title}/${index + 1}.png`;
16637
- await new Network({
16638
- url: image_url,
16639
- type: "arraybuffer"
16640
- }).getData().then((data$2) => fs.promises.writeFile(path$1, Buffer.from(data$2)));
16923
+ let mp3Path = "";
16924
+ if (VideoData.data.aweme_detail.music.play_url.uri === "") mp3Path = JSON.parse(VideoData.data.aweme_detail.music.extra).original_song_url;
16925
+ else mp3Path = VideoData.data.aweme_detail.music.play_url.uri;
16926
+ const liveimgbgm = await downloadFile(mp3Path, {
16927
+ title: `Douyin_tmp_A_${Date.now()}.mp3`,
16928
+ headers: this.headers
16929
+ });
16930
+ temp.push(liveimgbgm);
16931
+ const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
16932
+ let bgmContext = null;
16933
+ if (mergeMode === "continuous") bgmContext = await createLiveImageContext(liveimgbgm.filepath);
16934
+ for (const [index, imageItem] of images.entries()) {
16935
+ imagenum++;
16936
+ if (imageItem.clip_type === 2) {
16937
+ image_url = imageItem.url_list[2] || imageItem.url_list[1];
16938
+ processedImages.push(segment.image(image_url));
16939
+ if (Config.app.removeCache === false) {
16940
+ mkdirSync(`${Common.tempDri.images}${g_title}`);
16941
+ const path$1 = `${Common.tempDri.images}${g_title}/${index + 1}.png`;
16942
+ await new Network({
16943
+ url: image_url,
16944
+ type: "arraybuffer"
16945
+ }).getData().then((data$2) => fs.promises.writeFile(path$1, Buffer.from(data$2)));
16946
+ }
16947
+ continue;
16948
+ }
16949
+ const liveimg = await downloadFile(`https://aweme.snssdk.com/aweme/v1/play/?video_id=${imageItem.video.play_addr_h264.uri}&ratio=1080p&line=0`, {
16950
+ title: `Douyin_tmp_V_${Date.now()}.mp4`,
16951
+ headers: this.headers
16952
+ });
16953
+ if (liveimg.filepath) {
16954
+ const outputPath = Common.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
16955
+ let success;
16956
+ const loopCount = imageItem.clip_type === 4 ? 1 : 3;
16957
+ if (mergeMode === "continuous" && bgmContext) {
16958
+ const result = await mergeLiveImageContinuous({
16959
+ videoPath: liveimg.filepath,
16960
+ outputPath,
16961
+ loopCount
16962
+ }, bgmContext);
16963
+ success = result.success;
16964
+ bgmContext = result.context;
16965
+ } else success = await mergeLiveImageIndependent({
16966
+ videoPath: liveimg.filepath,
16967
+ outputPath,
16968
+ loopCount
16969
+ }, liveimgbgm.filepath);
16970
+ if (success) {
16971
+ const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
16972
+ fs.renameSync(outputPath, filePath);
16973
+ logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
16974
+ logger.mark("正在尝试删除缓存文件");
16975
+ await Common.removeFile(liveimg.filepath, true);
16976
+ temp.push({
16977
+ filepath: filePath,
16978
+ totalBytes: 0
16979
+ });
16980
+ processedImages.push(segment.video("file://" + filePath));
16981
+ if (imageItem.clip_type === 5 && imageItem.url_list?.[0]) processedImages.push(segment.image(imageItem.url_list[0]));
16982
+ } else await Common.removeFile(liveimg.filepath, true);
16983
+ }
16641
16984
  }
16985
+ const Element = common.makeForward(processedImages, this.e.sender.userId, this.e.sender.nick);
16986
+ try {
16987
+ await this.e.bot.sendForwardMsg(this.e.contact, Element, {
16988
+ source: "图集内容",
16989
+ summary: `查看${Element.length}张图片/视频消息`,
16990
+ prompt: "抖音图集解析结果",
16991
+ news: [{ text: "点击查看解析结果" }]
16992
+ });
16993
+ } catch (error) {
16994
+ await this.e.reply(JSON.stringify(error, null, 2));
16995
+ } finally {
16996
+ for (const item of temp) await Common.removeFile(item.filepath, true);
16997
+ }
16998
+ this.hasProcessedLiveImage = true;
16999
+ } else {
17000
+ for (const [index, imageItem] of images.entries()) {
17001
+ image_url = imageItem.url_list[2] || imageItem.url_list[1];
17002
+ g_title = VideoData.data.aweme_detail.preview_title.substring(0, 50).replace(/[\\/:*?"<>|\r\n]/g, " ");
17003
+ imageres.push(segment.image(image_url));
17004
+ imagenum++;
17005
+ if (Config.app.removeCache === false) {
17006
+ mkdirSync(`${Common.tempDri.images}${g_title}`);
17007
+ const path$1 = `${Common.tempDri.images}${g_title}/${index + 1}.png`;
17008
+ await new Network({
17009
+ url: image_url,
17010
+ type: "arraybuffer"
17011
+ }).getData().then((data$2) => fs.promises.writeFile(path$1, Buffer.from(data$2)));
17012
+ }
17013
+ }
17014
+ const res = common.makeForward(imageres, this.e.sender.userId, this.e.sender.nick);
17015
+ image_data.push(res);
17016
+ image_res.push(image_data);
17017
+ if (imageres.length === 1) await this.e.reply(segment.image(image_url));
17018
+ else await this.e.bot.sendForwardMsg(this.e.contact, res, {
17019
+ source: "图片合集",
17020
+ summary: `查看${res.length}张图片消息`,
17021
+ prompt: "抖音图集解析结果",
17022
+ news: [{ text: "点击查看解析结果" }]
17023
+ });
16642
17024
  }
16643
- const res = common.makeForward(imageres, this.e.sender.userId, this.e.sender.nick);
16644
- image_data.push(res);
16645
- image_res.push(image_data);
16646
- if (imageres.length === 1) await this.e.reply(segment.image(image_url));
16647
- else await this.e.bot.sendForwardMsg(this.e.contact, res, {
16648
- source: "图片合集",
16649
- summary: `查看${res.length}张图片消息`,
16650
- prompt: "抖音图集解析结果",
16651
- news: [{ text: "点击查看解析结果" }]
16652
- });
16653
17025
  break;
16654
17026
  }
16655
17027
  case VideoData.data.aweme_detail.is_slides === true && VideoData.data.aweme_detail.images !== null: {
16656
17028
  const images = [];
16657
17029
  const temp = [];
16658
- const liveimgbgm = await downloadFile(VideoData.data.aweme_detail.music.play_url.uri, {
17030
+ let mp3Path = "";
17031
+ if (VideoData.data.aweme_detail.music.play_url.uri === "") mp3Path = JSON.parse(VideoData.data.aweme_detail.music.extra).original_song_url;
17032
+ else mp3Path = VideoData.data.aweme_detail.music.play_url.uri;
17033
+ const liveimgbgm = await downloadFile(mp3Path, {
16659
17034
  title: `Douyin_tmp_A_${Date.now()}.mp3`,
16660
17035
  headers: this.headers
16661
17036
  });
@@ -16678,18 +17053,19 @@ var DouYin = class extends Base {
16678
17053
  if (liveimg.filepath) {
16679
17054
  const outputPath = Common.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
16680
17055
  let success;
17056
+ const loopCount = item.clip_type === 4 ? 1 : 3;
16681
17057
  if (mergeMode === "continuous" && bgmContext) {
16682
17058
  const result = await mergeLiveImageContinuous({
16683
17059
  videoPath: liveimg.filepath,
16684
17060
  outputPath,
16685
- loopCount: 3
17061
+ loopCount
16686
17062
  }, bgmContext);
16687
17063
  success = result.success;
16688
17064
  bgmContext = result.context;
16689
17065
  } else success = await mergeLiveImageIndependent({
16690
17066
  videoPath: liveimg.filepath,
16691
17067
  outputPath,
16692
- loopCount: 3
17068
+ loopCount
16693
17069
  }, liveimgbgm.filepath);
16694
17070
  if (success) {
16695
17071
  const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
@@ -16702,6 +17078,7 @@ var DouYin = class extends Base {
16702
17078
  totalBytes: 0
16703
17079
  });
16704
17080
  images.push(segment.video("file://" + filePath));
17081
+ if (item.clip_type === 5 && item.url_list?.[0]) images.push(segment.image(item.url_list[0]));
16705
17082
  } else await Common.removeFile(liveimg.filepath, true);
16706
17083
  }
16707
17084
  }
@@ -16722,7 +17099,10 @@ var DouYin = class extends Base {
16722
17099
  }
16723
17100
  }
16724
17101
  if (VideoData.data.aweme_detail.music) {
16725
- const music_url = VideoData.data.aweme_detail.music.play_url.uri;
17102
+ const music = VideoData.data.aweme_detail.music;
17103
+ let music_url = "";
17104
+ if (music.play_url.uri === "") music_url = JSON.parse(music.extra).original_song_url;
17105
+ else music_url = music.play_url.uri;
16726
17106
  if (this.is_mp4 === false && Config.app.removeCache === false && music_url !== void 0) try {
16727
17107
  const path$1 = Common.tempDri.images + `${g_title}/BGM.mp3`;
16728
17108
  await new Network({
@@ -16732,7 +17112,7 @@ var DouYin = class extends Base {
16732
17112
  } catch (error) {
16733
17113
  console.log(error);
16734
17114
  }
16735
- music_url && this.is_mp4 === false && music_url !== void 0 && await this.e.reply(segment.record(music_url, false));
17115
+ music_url && this.is_mp4 === false && music_url !== void 0 && !this.hasProcessedLiveImage && await this.e.reply(segment.record(music_url, false));
16736
17116
  }
16737
17117
  let FPS;
16738
17118
  let video = null;
@@ -17227,6 +17607,197 @@ const getDouyinID = async (event, url, log = true) => {
17227
17607
  log && console.log(result);
17228
17608
  return result;
17229
17609
  };
17610
+ await init_module();
17611
+ await init_amagiClient();
17612
+ async function processFavoriteList(contentList, sec_uid, userinfo, item, targets, force = false) {
17613
+ const pushType = "favorite";
17614
+ const listName = "喜欢列表";
17615
+ const result = [];
17616
+ const groupHistoryStatus = /* @__PURE__ */ new Map();
17617
+ for (const target of targets) {
17618
+ const hasHistory = await douyinDBInstance.hasHistory(sec_uid, target.groupId, pushType);
17619
+ groupHistoryStatus.set(target.groupId, hasHistory);
17620
+ }
17621
+ for (const [index, aweme] of contentList.entries()) {
17622
+ const validTargets = [];
17623
+ for (const target of targets) if (!await douyinDBInstance.isAwemePushed(aweme.aweme_id, sec_uid, target.groupId, pushType)) {
17624
+ const hasHistory = groupHistoryStatus.get(target.groupId);
17625
+ if (force || hasHistory || index === 0) validTargets.push(target);
17626
+ else {
17627
+ await douyinDBInstance.addAwemeCache(aweme.aweme_id, sec_uid, target.groupId, pushType);
17628
+ logger.debug(`新订阅群组 ${target.groupId} 跳过旧作品 ${aweme.aweme_id} 并已标记为已读`);
17629
+ }
17630
+ }
17631
+ if (validTargets.length === 0) continue;
17632
+ let authorUserInfo;
17633
+ try {
17634
+ if (aweme.author?.sec_uid) {
17635
+ authorUserInfo = await douyinFetcher.fetchUserProfile({
17636
+ sec_uid: aweme.author.sec_uid,
17637
+ typeMode: "strict"
17638
+ });
17639
+ logger.debug(`获取作品作者 ${aweme.author.nickname} 的用户信息成功`);
17640
+ }
17641
+ } catch (error) {
17642
+ logger.warn(`获取作品作者用户信息失败: ${error}`);
17643
+ }
17644
+ result.push({
17645
+ remark: item.remark,
17646
+ sec_uid,
17647
+ create_time: aweme.create_time,
17648
+ targets: validTargets,
17649
+ pushType,
17650
+ Detail_Data: {
17651
+ ...aweme,
17652
+ user_info: userinfo,
17653
+ author_user_info: authorUserInfo
17654
+ },
17655
+ avatar_img: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + userinfo.data.user.avatar_larger.uri,
17656
+ living: false
17657
+ });
17658
+ logger.debug(`发现新${listName}作品:${aweme.aweme_id}`);
17659
+ }
17660
+ await douyinDBInstance.updateListSnapshot(sec_uid, pushType, contentList.map((a) => a.aweme_id));
17661
+ return result;
17662
+ }
17663
+ await init_module();
17664
+ async function processLiveStream(sec_uid, userinfo, item, targets, amagi) {
17665
+ const pushType = "live";
17666
+ const liveStatus = await douyinDBInstance.getLiveStatus(sec_uid);
17667
+ if (userinfo.data.user.live_status === 1) {
17668
+ const UserInfoData = await amagi.douyin.fetcher.fetchUserProfile({
17669
+ sec_uid: userinfo.data.user.sec_uid,
17670
+ typeMode: "strict"
17671
+ });
17672
+ if (!UserInfoData.data.user?.live_status || UserInfoData.data.user.live_status !== 1) {
17673
+ logger.error((UserInfoData?.data?.user?.nickname ?? "用户") + "当前未在直播");
17674
+ return null;
17675
+ }
17676
+ if (!UserInfoData.data.user.room_data) {
17677
+ logger.error("未获取到直播间信息!");
17678
+ return null;
17679
+ }
17680
+ const room_data = JSON.parse(UserInfoData.data.user.room_data);
17681
+ const liveInfo = await amagi.douyin.fetcher.fetchLiveRoomInfo({
17682
+ room_id: UserInfoData.data.user.room_id_str,
17683
+ web_rid: room_data.owner.web_rid,
17684
+ typeMode: "strict"
17685
+ });
17686
+ if (!liveStatus.living) {
17687
+ await douyinDBInstance.updateLiveStatus(sec_uid, true);
17688
+ logger.info(`用户 ${item.remark ?? sec_uid} 开播了`);
17689
+ return {
17690
+ remark: item.remark,
17691
+ sec_uid,
17692
+ create_time: Date.now(),
17693
+ targets,
17694
+ pushType,
17695
+ Detail_Data: {
17696
+ user_info: userinfo,
17697
+ room_data: JSON.parse(userinfo.data.user.room_data),
17698
+ live_data: liveInfo,
17699
+ liveStatus: {
17700
+ liveStatus: "open",
17701
+ isChanged: true,
17702
+ isliving: true
17703
+ }
17704
+ },
17705
+ avatar_img: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + userinfo.data.user.avatar_larger.uri,
17706
+ living: true
17707
+ };
17708
+ }
17709
+ } else if (liveStatus.living) {
17710
+ await douyinDBInstance.updateLiveStatus(sec_uid, false);
17711
+ logger.info(`用户 ${item.remark ?? sec_uid} 已关播,更新直播状态`);
17712
+ }
17713
+ return null;
17714
+ }
17715
+ await init_date_fns();
17716
+ await init_module();
17717
+ async function processPostList(contentList, sec_uid, userinfo, item, targets) {
17718
+ const pushType = "post";
17719
+ const listName = "作品列表";
17720
+ const result = [];
17721
+ for (const aweme of contentList) {
17722
+ const nowSeconds = Math.floor(Date.now() / 1e3);
17723
+ const createTime = aweme.create_time;
17724
+ const timeDifference = nowSeconds - createTime;
17725
+ const is_top = aweme.is_top === 1;
17726
+ const timeDiffHours = Math.round(timeDifference / 3600 * 100) / 100;
17727
+ logger.trace(`\n 前期获取该作品基本信息:\n 推送类型:${pushType}(${listName})\n 作者:${aweme.author.nickname}\n 作品ID:${aweme.aweme_id}\n 发布时间:${format(fromUnixTime(aweme.create_time), "yyyy-MM-dd HH:mm")}\n 发布时间戳(s):${createTime}\n 当前时间戳(s):${nowSeconds}\n 时间差(s):${timeDifference}s (${timeDiffHours}h)\n 是否置顶:${is_top}\n 是否在一天内:${timeDifference < 86400 ? logger.green("true") : logger.red("false")}\n `);
17728
+ if (is_top && timeDifference < 86400 || timeDifference < 86400 && !is_top) {
17729
+ const validTargets = [];
17730
+ for (const target of targets) if (!await douyinDBInstance.isAwemePushed(aweme.aweme_id, sec_uid, target.groupId, pushType)) validTargets.push(target);
17731
+ if (validTargets.length > 0) result.push({
17732
+ remark: item.remark,
17733
+ sec_uid,
17734
+ create_time: aweme.create_time,
17735
+ targets: validTargets,
17736
+ pushType,
17737
+ Detail_Data: {
17738
+ ...aweme,
17739
+ user_info: userinfo
17740
+ },
17741
+ avatar_img: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + userinfo.data.user.avatar_larger.uri,
17742
+ living: false
17743
+ });
17744
+ }
17745
+ }
17746
+ return result;
17747
+ }
17748
+ await init_module();
17749
+ await init_amagiClient();
17750
+ async function processRecommendList(contentList, sec_uid, userinfo, item, targets, force = false) {
17751
+ const pushType = "recommend";
17752
+ const listName = "推荐列表";
17753
+ const result = [];
17754
+ const groupHistoryStatus = /* @__PURE__ */ new Map();
17755
+ for (const target of targets) {
17756
+ const hasHistory = await douyinDBInstance.hasHistory(sec_uid, target.groupId, pushType);
17757
+ groupHistoryStatus.set(target.groupId, hasHistory);
17758
+ }
17759
+ for (const [index, aweme] of contentList.entries()) {
17760
+ const validTargets = [];
17761
+ for (const target of targets) if (!await douyinDBInstance.isAwemePushed(aweme.aweme_id, sec_uid, target.groupId, pushType)) {
17762
+ const hasHistory = groupHistoryStatus.get(target.groupId);
17763
+ if (force || hasHistory || index === 0) validTargets.push(target);
17764
+ else {
17765
+ await douyinDBInstance.addAwemeCache(aweme.aweme_id, sec_uid, target.groupId, pushType);
17766
+ logger.debug(`新订阅群组 ${target.groupId} 跳过旧作品 ${aweme.aweme_id} 并已标记为已读`);
17767
+ }
17768
+ }
17769
+ if (validTargets.length === 0) continue;
17770
+ let authorUserInfo;
17771
+ try {
17772
+ if (aweme.author?.sec_uid) {
17773
+ authorUserInfo = await douyinFetcher.fetchUserProfile({
17774
+ sec_uid: aweme.author.sec_uid,
17775
+ typeMode: "strict"
17776
+ });
17777
+ logger.debug(`获取作品作者 ${aweme.author.nickname} 的用户信息成功`);
17778
+ }
17779
+ } catch (error) {
17780
+ logger.warn(`获取作品作者用户信息失败: ${error}`);
17781
+ }
17782
+ result.push({
17783
+ remark: item.remark,
17784
+ sec_uid,
17785
+ create_time: aweme.create_time,
17786
+ targets: validTargets,
17787
+ pushType,
17788
+ Detail_Data: {
17789
+ ...aweme,
17790
+ user_info: userinfo,
17791
+ author_user_info: authorUserInfo
17792
+ },
17793
+ avatar_img: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + userinfo.data.user.avatar_larger.uri,
17794
+ living: false
17795
+ });
17796
+ logger.debug(`发现新${listName}作品:${aweme.aweme_id}`);
17797
+ }
17798
+ await douyinDBInstance.updateListSnapshot(sec_uid, pushType, contentList.map((a) => a.aweme_id));
17799
+ return result;
17800
+ }
17230
17801
  await init_date_fns();
17231
17802
  await init_module();
17232
17803
  await init_Config();
@@ -17252,6 +17823,7 @@ var DouYinpush = class extends Base {
17252
17823
  const deletedCount = await cleanOldDynamicCache("douyin");
17253
17824
  if (deletedCount > 0) logger.info(`已清理 ${deletedCount} 条过期的抖音作品缓存记录`);
17254
17825
  if (await this.checkremark()) return true;
17826
+ this.ensureConfigFields(Config.pushlist.douyin);
17255
17827
  const registeredBotIds = karin$1.getAllBotID();
17256
17828
  const filteredPushList = this.filterPushListByRegisteredBots(Config.pushlist.douyin, registeredBotIds);
17257
17829
  if (filteredPushList.length === 0) {
@@ -17263,6 +17835,30 @@ var DouYinpush = class extends Base {
17263
17835
  if (this.force) return await this.forcepush(data$1);
17264
17836
  else return await this.getdata(data$1);
17265
17837
  }
17838
+ ensureConfigFields(pushList) {
17839
+ if (!pushList || pushList.length === 0) return;
17840
+ let hasChanges = false;
17841
+ for (const item of pushList) {
17842
+ if (!item.pushTypes || item.pushTypes.length === 0) {
17843
+ item.pushTypes = [
17844
+ "post",
17845
+ "live",
17846
+ "favorite",
17847
+ "recommend"
17848
+ ];
17849
+ hasChanges = true;
17850
+ logger.info(`为用户 ${item.remark ?? item.sec_uid} 自动补全推送类型:作品列表、直播、收藏、推荐`);
17851
+ }
17852
+ if (item.switch === void 0) {
17853
+ item.switch = true;
17854
+ hasChanges = true;
17855
+ }
17856
+ }
17857
+ if (hasChanges) {
17858
+ Config.Modify("pushlist", "douyin", pushList);
17859
+ logger.info("已自动补全配置文件中缺失的字段并保存");
17860
+ }
17861
+ }
17266
17862
  filterPushListByRegisteredBots(pushList, registeredBotIds) {
17267
17863
  if (!pushList || pushList.length === 0) return [];
17268
17864
  const registeredSet = new Set(registeredBotIds);
@@ -17289,18 +17885,20 @@ var DouYinpush = class extends Base {
17289
17885
  async getdata(data$1) {
17290
17886
  if (Object.keys(data$1).length === 0) return true;
17291
17887
  for (const awemeId in data$1) {
17292
- logger.mark(`\n ${logger.blue("开始处理并渲染抖音动态图片")}\n ${logger.blue("博主")}: ${logger.green(data$1[awemeId].remark)} \n ${logger.cyan("作品id")}:${logger.yellow(awemeId)}\n ${logger.cyan("访问地址")}:${logger.green("https://www.douyin.com/video/" + awemeId)}`);
17293
17888
  const pushItem = data$1[awemeId];
17889
+ const actualAwemeId = awemeId.replace(/^(post|favorite|recommend|live)_/, "");
17890
+ const pushTypeLabel = pushItem.pushType === "post" ? "作品列表" : pushItem.pushType === "favorite" ? "喜欢列表" : pushItem.pushType === "recommend" ? "推荐列表" : "直播";
17891
+ logger.mark(`\n ${logger.blue("开始处理并渲染抖音动态图片")}\n ${logger.blue("博主")}: ${logger.green(pushItem.remark)} \n ${logger.blue("推送类型")}: ${logger.magenta(pushTypeLabel)}\n ${logger.cyan("作品id")}:${logger.yellow(actualAwemeId)}\n ${logger.cyan("访问地址")}:${logger.green("https://www.douyin.com/video/" + actualAwemeId)}`);
17294
17892
  const Detail_Data = pushItem.Detail_Data;
17295
17893
  const skip = await skipDynamic(pushItem);
17296
- skip && logger.warn(`作品 https://www.douyin.com/video/${awemeId} 已被处理,跳过`);
17894
+ skip && logger.warn(`作品 https://www.douyin.com/video/${actualAwemeId} 已被处理,跳过`);
17297
17895
  let img$2 = [];
17298
17896
  let iddata = {
17299
17897
  is_mp4: true,
17300
17898
  type: "one_work"
17301
17899
  };
17302
17900
  if (!skip) iddata = await getDouyinID(this.e, Detail_Data.share_url ?? "https://live.douyin.com/" + Detail_Data.room_data?.owner.web_rid, false);
17303
- if (!skip) if (pushItem.living && "room_data" in pushItem.Detail_Data && Detail_Data.live_data) img$2 = await Render("douyin/live", {
17901
+ if (!skip) if (pushItem.pushType === "live" && "room_data" in pushItem.Detail_Data && Detail_Data.live_data) img$2 = await Render("douyin/live", {
17304
17902
  image_url: Detail_Data.live_data.data.data.data[0]?.cover?.url_list[0] ?? Detail_Data.live_data.data.data.qrcode_url,
17305
17903
  text: Detail_Data.live_data.data.data.data[0]?.title ?? "",
17306
17904
  liveinf: `${Detail_Data.live_data.data.data.partition_road_map?.partition?.title ?? Detail_Data.live_data.data.data.data[0]?.title ?? "获取失败"} | 房间号: ${Detail_Data.room_data.owner.web_rid}`,
@@ -17322,7 +17920,45 @@ var DouYinpush = class extends Base {
17322
17920
  Connection: "keep-alive"
17323
17921
  }
17324
17922
  }).getLocation();
17325
- img$2 = await Render("douyin/dynamic", {
17923
+ if (pushItem.pushType === "favorite") {
17924
+ const authorUserInfo = "author_user_info" in Detail_Data ? Detail_Data.author_user_info : void 0;
17925
+ img$2 = await Render("douyin/favorite-list", {
17926
+ image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover.url_list[0] : Detail_Data.images[0].url_list[0],
17927
+ desc: this.desc(Detail_Data, Detail_Data.desc),
17928
+ dianzan: this.count(Detail_Data.statistics.digg_count),
17929
+ pinglun: this.count(Detail_Data.statistics.comment_count),
17930
+ share: this.count(Detail_Data.statistics.share_count),
17931
+ shouchang: this.count(Detail_Data.statistics.collect_count),
17932
+ tuijian: this.count(Detail_Data.statistics.recommend_count),
17933
+ create_time: format(fromUnixTime(pushItem.create_time), "yyyy-MM-dd HH:mm"),
17934
+ liker_username: pushItem.remark,
17935
+ liker_avatar: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + Detail_Data.user_info.data.user.avatar_larger.uri,
17936
+ liker_douyin_id: Detail_Data.user_info.data.user.unique_id === "" ? Detail_Data.user_info.data.user.short_id : Detail_Data.user_info.data.user.unique_id,
17937
+ author_username: Detail_Data.author.nickname,
17938
+ author_avatar: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + authorUserInfo.data.user.avatar_larger.uri,
17939
+ author_douyin_id: authorUserInfo.data.user.unique_id === "" ? authorUserInfo.data.user.short_id : authorUserInfo.data.user.unique_id,
17940
+ share_url: Config.douyin.push.shareType === "web" ? realUrl : `https://aweme.snssdk.com/aweme/v1/play/?video_id=${Detail_Data.video.play_addr.uri}&ratio=1080p&line=0`
17941
+ });
17942
+ } else if (pushItem.pushType === "recommend") {
17943
+ const authorUserInfo = "author_user_info" in Detail_Data ? Detail_Data.author_user_info : void 0;
17944
+ img$2 = await Render("douyin/recommend-list", {
17945
+ image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover.url_list[0] : Detail_Data.images[0].url_list[0],
17946
+ desc: this.desc(Detail_Data, Detail_Data.desc),
17947
+ dianzan: this.count(Detail_Data.statistics.digg_count),
17948
+ pinglun: this.count(Detail_Data.statistics.comment_count),
17949
+ share: this.count(Detail_Data.statistics.share_count),
17950
+ shouchang: this.count(Detail_Data.statistics.collect_count),
17951
+ tuijian: this.count(Detail_Data.statistics.recommend_count),
17952
+ create_time: format(fromUnixTime(pushItem.create_time), "yyyy-MM-dd HH:mm"),
17953
+ recommender_username: pushItem.remark,
17954
+ recommender_avatar: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + Detail_Data.user_info.data.user.avatar_larger.uri,
17955
+ recommender_douyin_id: Detail_Data.user_info.data.user.unique_id === "" ? Detail_Data.user_info.data.user.short_id : Detail_Data.user_info.data.user.unique_id,
17956
+ author_username: Detail_Data.author.nickname,
17957
+ author_avatar: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + authorUserInfo.data.user.avatar_larger.uri,
17958
+ author_douyin_id: authorUserInfo.data.user.unique_id === "" ? authorUserInfo.data.user.short_id : authorUserInfo.data.user.unique_id,
17959
+ share_url: Config.douyin.push.shareType === "web" ? realUrl : `https://aweme.snssdk.com/aweme/v1/play/?video_id=${Detail_Data.video.play_addr.uri}&ratio=1080p&line=0`
17960
+ });
17961
+ } else img$2 = await Render("douyin/dynamic", {
17326
17962
  image_url: iddata.is_mp4 ? Detail_Data.video.animated_cover?.url_list[0] ?? Detail_Data.video.cover.url_list[0] : Detail_Data.images[0].url_list[0],
17327
17963
  desc: this.desc(Detail_Data, Detail_Data.desc),
17328
17964
  dianzan: this.count(Detail_Data.statistics.digg_count),
@@ -17337,6 +17973,7 @@ var DouYinpush = class extends Base {
17337
17973
  "粉丝": this.count(Detail_Data.user_info.data.user.follower_count),
17338
17974
  "获赞": this.count(Detail_Data.user_info.data.user.total_favorited),
17339
17975
  "关注": this.count(Detail_Data.user_info.data.user.following_count),
17976
+ dynamicTYPE: "作品动态推送",
17340
17977
  cooperation_info: (() => {
17341
17978
  const raw = Detail_Data.cooperation_info;
17342
17979
  if (!raw) return void 0;
@@ -17367,13 +18004,16 @@ var DouYinpush = class extends Base {
17367
18004
  if (!skip) {
17368
18005
  const Contact = karin$1.contactGroup(groupId);
17369
18006
  status = await karin$1.sendMsg(botId, Contact, img$2 ? [...img$2] : []);
17370
- if (pushItem.living && "room_data" in pushItem.Detail_Data && status.message_id) await douyinDBInstance.updateLiveStatus(pushItem.sec_uid, true);
18007
+ if (pushItem.pushType === "live" && "room_data" in pushItem.Detail_Data && status.message_id) await douyinDBInstance.updateLiveStatus(pushItem.sec_uid, true);
17371
18008
  if (Config.douyin.push.parsedynamic && status.message_id) {
18009
+ logger.debug(`开始解析作品,类型为:${iddata.is_mp4 ? "视频" : "图集"}`);
17372
18010
  if (iddata.is_mp4) try {
17373
18011
  let downloadUrl = `https://aweme.snssdk.com/aweme/v1/play/?video_id=${Detail_Data.video.play_addr.uri}&ratio=1080p&line=0`;
17374
18012
  logger.debug(`开始排除不符合条件的视频分辨率;\n\n 共拥有${logger.yellow(Detail_Data.video.bit_rate.length)}个视频源\n\n 视频ID:${logger.green(Detail_Data.aweme_id)}\n\n 分享链接:${logger.green(Detail_Data.share_url)}\n `);
18013
+ const videoObj = douyinProcessVideos(Detail_Data.video.bit_rate, Config.douyin.videoQuality);
18014
+ logger.debug("获取精确下载地址");
17375
18015
  downloadUrl = await new Network({
17376
- url: douyinProcessVideos(Detail_Data.video.bit_rate, Config.douyin.videoQuality)[0].play_addr.url_list[0],
18016
+ url: videoObj[0].play_addr.url_list[0],
17377
18017
  headers: douyinBaseHeaders
17378
18018
  }).getLongLink();
17379
18019
  await downloadVideo(this.e, {
@@ -17393,19 +18033,186 @@ var DouYinpush = class extends Base {
17393
18033
  throw new Error(`下载视频失败: ${error}`);
17394
18034
  }
17395
18035
  else if (!iddata.is_mp4 && iddata.type === "one_work") {
17396
- const imageres = [];
17397
- let image_url;
17398
- for (const item of Detail_Data.images) {
17399
- image_url = item.url_list[2] ?? item.url_list[1];
17400
- imageres.push(segment.image(image_url));
18036
+ if (Detail_Data.is_slides === true && Detail_Data.images) {
18037
+ const images = [];
18038
+ const temp = [];
18039
+ let mp3Path = "";
18040
+ if (Detail_Data.music.play_url.uri === "") mp3Path = JSON.parse(Detail_Data.music.extra).original_song_url;
18041
+ else mp3Path = Detail_Data.music.play_url.uri;
18042
+ const liveimgbgm = await downloadFile(mp3Path, {
18043
+ title: `Douyin_tmp_A_${Date.now()}.mp3`,
18044
+ headers: douyinBaseHeaders
18045
+ });
18046
+ temp.push(liveimgbgm);
18047
+ const images1 = Detail_Data.images ?? [];
18048
+ if (!images1.length) logger.debug("未获取到合辑的图片数据");
18049
+ const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
18050
+ let bgmContext = null;
18051
+ if (mergeMode === "continuous") {
18052
+ const { createLiveImageContext: createLiveImageContext$1 } = await init_utils$1().then(() => utils_exports);
18053
+ bgmContext = await createLiveImageContext$1(liveimgbgm.filepath);
18054
+ }
18055
+ for (const item of images1) {
18056
+ if (item.clip_type === 2) {
18057
+ images.push(segment.image(item.url_list[0]));
18058
+ continue;
18059
+ }
18060
+ const liveimg = await downloadFile(`https://aweme.snssdk.com/aweme/v1/play/?video_id=${item.video.play_addr_h264.uri}&ratio=1080p&line=0`, {
18061
+ title: `Douyin_tmp_V_${Date.now()}.mp4`,
18062
+ headers: douyinBaseHeaders
18063
+ });
18064
+ if (liveimg.filepath) {
18065
+ const { Common: Common$1, mergeLiveImageContinuous: mergeLiveImageContinuous$1, mergeLiveImageIndependent: mergeLiveImageIndependent$1 } = await init_utils$1().then(() => utils_exports);
18066
+ const outputPath = Common$1.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
18067
+ let success;
18068
+ const loopCount = item.clip_type === 4 ? 1 : 3;
18069
+ if (mergeMode === "continuous" && bgmContext) {
18070
+ const result = await mergeLiveImageContinuous$1({
18071
+ videoPath: liveimg.filepath,
18072
+ outputPath,
18073
+ loopCount
18074
+ }, bgmContext);
18075
+ success = result.success;
18076
+ bgmContext = result.context;
18077
+ } else success = await mergeLiveImageIndependent$1({
18078
+ videoPath: liveimg.filepath,
18079
+ outputPath,
18080
+ loopCount
18081
+ }, liveimgbgm.filepath);
18082
+ if (success) {
18083
+ const fs$1 = await import("node:fs");
18084
+ const filePath = Common$1.tempDri.video + `tmp_${Date.now()}.mp4`;
18085
+ fs$1.default.renameSync(outputPath, filePath);
18086
+ logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
18087
+ logger.mark("正在尝试删除缓存文件");
18088
+ await Common$1.removeFile(liveimg.filepath, true);
18089
+ temp.push({
18090
+ filepath: filePath,
18091
+ totalBytes: 0
18092
+ });
18093
+ images.push(segment.video("file://" + filePath));
18094
+ if (item.clip_type === 5 && item.url_list?.[0]) images.push(segment.image(item.url_list[0]));
18095
+ } else await Common$1.removeFile(liveimg.filepath, true);
18096
+ }
18097
+ }
18098
+ const bot = karin$1.getBot(botId);
18099
+ const Element = common.makeForward(images, botId, bot.account.name);
18100
+ try {
18101
+ await bot.sendForwardMsg(Contact, Element, {
18102
+ source: "合辑内容",
18103
+ summary: `查看${Element.length}张图片/视频消息`,
18104
+ prompt: "抖音合辑解析结果",
18105
+ news: [{ text: "点击查看解析结果" }]
18106
+ });
18107
+ } catch (error) {
18108
+ logger.error(`发送合辑失败: ${error}`);
18109
+ } finally {
18110
+ for (const item of temp) {
18111
+ const { Common: Common$1 } = await init_utils$1().then(() => utils_exports);
18112
+ await Common$1.removeFile(item.filepath, true);
18113
+ }
18114
+ }
18115
+ } else if (Detail_Data.images) if (Detail_Data.images.some((item) => item.clip_type !== 2)) {
18116
+ const processedImages = [];
18117
+ const temp = [];
18118
+ let mp3Path = "";
18119
+ if (Detail_Data.music.play_url.uri === "") mp3Path = JSON.parse(Detail_Data.music.extra).original_song_url;
18120
+ else mp3Path = Detail_Data.music.play_url.uri;
18121
+ const liveimgbgm = await downloadFile(mp3Path, {
18122
+ title: `Douyin_tmp_A_${Date.now()}.mp3`,
18123
+ headers: douyinBaseHeaders
18124
+ });
18125
+ temp.push(liveimgbgm);
18126
+ const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
18127
+ let bgmContext = null;
18128
+ if (mergeMode === "continuous") {
18129
+ const { createLiveImageContext: createLiveImageContext$1 } = await init_utils$1().then(() => utils_exports);
18130
+ bgmContext = await createLiveImageContext$1(liveimgbgm.filepath);
18131
+ }
18132
+ for (const item of Detail_Data.images) {
18133
+ if (item.clip_type === 2) {
18134
+ const image_url = item.url_list[2] ?? item.url_list[1];
18135
+ processedImages.push(segment.image(image_url));
18136
+ continue;
18137
+ }
18138
+ const liveimg = await downloadFile(`https://aweme.snssdk.com/aweme/v1/play/?video_id=${item.video.play_addr_h264.uri}&ratio=1080p&line=0`, {
18139
+ title: `Douyin_tmp_V_${Date.now()}.mp4`,
18140
+ headers: douyinBaseHeaders
18141
+ });
18142
+ if (liveimg.filepath) {
18143
+ const { Common: Common$1, mergeLiveImageContinuous: mergeLiveImageContinuous$1, mergeLiveImageIndependent: mergeLiveImageIndependent$1 } = await init_utils$1().then(() => utils_exports);
18144
+ const outputPath = Common$1.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
18145
+ let success;
18146
+ const loopCount = item.clip_type === 4 ? 1 : 3;
18147
+ if (mergeMode === "continuous" && bgmContext) {
18148
+ const result = await mergeLiveImageContinuous$1({
18149
+ videoPath: liveimg.filepath,
18150
+ outputPath,
18151
+ loopCount
18152
+ }, bgmContext);
18153
+ success = result.success;
18154
+ bgmContext = result.context;
18155
+ } else success = await mergeLiveImageIndependent$1({
18156
+ videoPath: liveimg.filepath,
18157
+ outputPath,
18158
+ loopCount
18159
+ }, liveimgbgm.filepath);
18160
+ if (success) {
18161
+ const fs$1 = await import("node:fs");
18162
+ const filePath = Common$1.tempDri.video + `tmp_${Date.now()}.mp4`;
18163
+ fs$1.default.renameSync(outputPath, filePath);
18164
+ logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
18165
+ logger.mark("正在尝试删除缓存文件");
18166
+ await Common$1.removeFile(liveimg.filepath, true);
18167
+ temp.push({
18168
+ filepath: filePath,
18169
+ totalBytes: 0
18170
+ });
18171
+ processedImages.push(segment.video("file://" + filePath));
18172
+ if (item.clip_type === 5 && item.url_list?.[0]) processedImages.push(segment.image(item.url_list[0]));
18173
+ } else await Common$1.removeFile(liveimg.filepath, true);
18174
+ }
18175
+ }
18176
+ const bot = karin$1.getBot(botId);
18177
+ const Element = common.makeForward(processedImages, botId, bot.account.name);
18178
+ try {
18179
+ await bot.sendForwardMsg(Contact, Element, {
18180
+ source: "图集内容",
18181
+ summary: `查看${Element.length}张图片/视频消息`,
18182
+ prompt: "抖音图集解析结果",
18183
+ news: [{ text: "点击查看解析结果" }]
18184
+ });
18185
+ } catch (error) {
18186
+ logger.error(`发送图集失败: ${error}`);
18187
+ } finally {
18188
+ for (const item of temp) {
18189
+ const { Common: Common$1 } = await init_utils$1().then(() => utils_exports);
18190
+ await Common$1.removeFile(item.filepath, true);
18191
+ }
18192
+ }
18193
+ } else {
18194
+ const imageres = [];
18195
+ let image_url;
18196
+ for (const item of Detail_Data.images) {
18197
+ image_url = item.url_list[2] ?? item.url_list[1];
18198
+ imageres.push(segment.image(image_url));
18199
+ }
18200
+ const bot = karin$1.getBot(botId);
18201
+ if (imageres.length === 1) await bot.sendMsg(Contact, [segment.image(image_url)]);
18202
+ else {
18203
+ const forwardMsg = common.makeForward(imageres, botId, bot.account.name);
18204
+ await bot.sendForwardMsg(Contact, forwardMsg, {
18205
+ source: "图片合集",
18206
+ summary: `查看${forwardMsg.length}张图片消息`,
18207
+ prompt: "抖音图集解析结果",
18208
+ news: [{ text: "点击查看解析结果" }]
18209
+ });
18210
+ }
17401
18211
  }
17402
- const bot = karin$1.getBot(botId);
17403
- const forwardMsg = common.makeForward(imageres, botId, bot.account.name);
17404
- await bot.sendForwardMsg(Contact, forwardMsg);
17405
18212
  }
17406
18213
  }
17407
18214
  }
17408
- if (skip || !pushItem.living && status.message_id) await douyinDBInstance.addAwemeCache(awemeId, pushItem.sec_uid, groupId);
18215
+ if (skip || pushItem.pushType !== "live" && status.message_id) await douyinDBInstance.addAwemeCache(actualAwemeId, pushItem.sec_uid, groupId, pushItem.pushType);
17409
18216
  } catch (error) {
17410
18217
  throw new Error(`${error}`);
17411
18218
  }
@@ -17419,11 +18226,8 @@ var DouYinpush = class extends Base {
17419
18226
  for (const item of filteredUserList) {
17420
18227
  await common.sleep(2e3);
17421
18228
  const sec_uid = item.sec_uid;
17422
- logger.debug(`开始获取用户:${item.remark}(${sec_uid})的主页作品列表`);
17423
- const videolist = await this.amagi.douyin.fetcher.fetchUserVideoList({
17424
- sec_uid,
17425
- typeMode: "strict"
17426
- });
18229
+ const pushTypes = item.pushTypes || ["post"];
18230
+ logger.debug(`开始获取用户:${item.remark}(${sec_uid})的内容,推送类型:${pushTypes.join(", ")}`);
17427
18231
  const userinfo = await this.amagi.douyin.fetcher.fetchUserProfile({
17428
18232
  sec_uid,
17429
18233
  typeMode: "strict"
@@ -17440,74 +18244,73 @@ var DouYinpush = class extends Base {
17440
18244
  logger.warn(`${item.remark}(${sec_uid})${userinfo.data.user.special_state_info.title}`);
17441
18245
  continue;
17442
18246
  }
17443
- if (videolist.data.aweme_list.length > 0) for (const aweme of videolist.data.aweme_list) {
17444
- const nowSeconds = Math.floor(Date.now() / 1e3);
17445
- const createTime = aweme.create_time;
17446
- const timeDifference = nowSeconds - createTime;
17447
- const is_top = aweme.is_top === 1;
17448
- let shouldPush = false;
17449
- const timeDiffHours = Math.round(timeDifference / 3600 * 100) / 100;
17450
- logger.trace(`\n 前期获取该作品基本信息:\n 作者:${aweme.author.nickname}\n 作品ID:${aweme.aweme_id}\n 发布时间:${format(fromUnixTime(aweme.create_time), "yyyy-MM-dd HH:mm")}\n 发布时间戳(s):${createTime}\n 当前时间戳(s):${nowSeconds}\n 时间差(s):${timeDifference}s (${timeDiffHours}h)\n 是否置顶:${is_top}\n 是否处于开播:${userinfo.data.user?.live_status === 1 ? logger.green("true") : logger.red("false")}\n 是否在一天内:${timeDifference < 86400 ? logger.green("true") : logger.red("false")}\n `);
17451
- if (is_top && timeDifference < 86400 || timeDifference < 86400 && !is_top) {
17452
- if (!await this.checkIfAlreadyPushed(aweme.aweme_id, sec_uid, targets.map((t) => t.groupId))) shouldPush = true;
18247
+ for (const pushType of pushTypes) {
18248
+ await common.sleep(1e3);
18249
+ if (pushType === "live") {
18250
+ const liveItem = await processLiveStream(sec_uid, userinfo, item, targets, this.amagi);
18251
+ if (liveItem) willbepushlist[`live_${sec_uid}`] = liveItem;
18252
+ continue;
18253
+ }
18254
+ let contentList = [];
18255
+ let listName = "";
18256
+ switch (pushType) {
18257
+ case "post":
18258
+ listName = "作品列表";
18259
+ contentList = (await this.amagi.douyin.fetcher.fetchUserVideoList({
18260
+ sec_uid,
18261
+ number: 5,
18262
+ typeMode: "strict"
18263
+ })).data.aweme_list || [];
18264
+ break;
18265
+ case "favorite":
18266
+ listName = "喜欢列表";
18267
+ const favoritelist = await this.amagi.douyin.fetcher.fetchUserFavoriteList({
18268
+ sec_uid,
18269
+ number: 5,
18270
+ typeMode: "strict"
18271
+ });
18272
+ if (favoritelist.data.aweme_list.length === 0) logger.warn(`${item.remark}(${item.short_id}) 获取到的喜欢列表数量为零!此博主可能未公开他/她的喜欢列表`);
18273
+ contentList = favoritelist.data.aweme_list || [];
18274
+ break;
18275
+ case "recommend":
18276
+ listName = "推荐列表";
18277
+ const recommendlist = await this.amagi.douyin.fetcher.fetchUserRecommendList({
18278
+ sec_uid,
18279
+ number: 5,
18280
+ typeMode: "strict"
18281
+ });
18282
+ if (recommendlist.data.aweme_list.length === 0) logger.warn(`${item.remark}(${item.short_id}) 获取到的推荐列表数量为零!此博主可能未公开他/她的推荐列表`);
18283
+ contentList = recommendlist.data.aweme_list || [];
18284
+ break;
18285
+ }
18286
+ logger.debug(`获取到 ${item.remark} 的${listName},共 ${contentList.length} 条`);
18287
+ if (contentList.length > 0) {
18288
+ let pushItems = [];
18289
+ switch (pushType) {
18290
+ case "post":
18291
+ pushItems = await processPostList(contentList, sec_uid, userinfo, item, targets);
18292
+ break;
18293
+ case "favorite":
18294
+ pushItems = await processFavoriteList(contentList, sec_uid, userinfo, item, targets, this.force);
18295
+ break;
18296
+ case "recommend":
18297
+ pushItems = await processRecommendList(contentList, sec_uid, userinfo, item, targets, this.force);
18298
+ break;
18299
+ }
18300
+ for (const pushItem of pushItems) {
18301
+ const key = `${pushType}_${pushItem.Detail_Data.aweme_id}`;
18302
+ willbepushlist[key] = pushItem;
18303
+ }
17453
18304
  }
17454
- if (shouldPush) willbepushlist[aweme.aweme_id] = {
17455
- remark: item.remark,
17456
- sec_uid,
17457
- create_time: aweme.create_time,
17458
- targets,
17459
- Detail_Data: {
17460
- ...aweme,
17461
- user_info: userinfo
17462
- },
17463
- avatar_img: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + userinfo.data.user.avatar_larger.uri,
17464
- living: false
17465
- };
17466
- }
17467
- const liveStatus = await douyinDBInstance.getLiveStatus(sec_uid);
17468
- if (userinfo.data.user.live_status === 1) {
17469
- const UserInfoData = await this.amagi.douyin.fetcher.fetchUserProfile({
17470
- sec_uid: userinfo.data.user.sec_uid,
17471
- typeMode: "strict"
17472
- });
17473
- if (!UserInfoData.data.user?.live_status || UserInfoData.data.user.live_status !== 1) logger.error((UserInfoData?.data?.user?.nickname ?? "用户") + "当前未在直播");
17474
- if (!UserInfoData.data.user.room_data) logger.error("未获取到直播间信息!");
17475
- const room_data = JSON.parse(UserInfoData.data.user.room_data);
17476
- const liveInfo = await this.amagi.douyin.fetcher.fetchLiveRoomInfo({
17477
- room_id: UserInfoData.data.user.room_id_str,
17478
- web_rid: room_data.owner.web_rid,
17479
- typeMode: "strict"
17480
- });
17481
- if (!liveStatus.living) willbepushlist[`live_${sec_uid}`] = {
17482
- remark: item.remark,
17483
- sec_uid,
17484
- create_time: Date.now(),
17485
- targets,
17486
- Detail_Data: {
17487
- user_info: userinfo,
17488
- room_data: JSON.parse(userinfo.data.user.room_data),
17489
- live_data: liveInfo,
17490
- liveStatus: {
17491
- liveStatus: "open",
17492
- isChanged: true,
17493
- isliving: true
17494
- }
17495
- },
17496
- avatar_img: "https://p3-pc.douyinpic.com/aweme/1080x1080/" + userinfo.data.user.avatar_larger.uri,
17497
- living: true
17498
- };
17499
- } else if (liveStatus.living) {
17500
- await douyinDBInstance.updateLiveStatus(sec_uid, false);
17501
- logger.info(`用户 ${item.remark ?? sec_uid} 已关播,更新直播状态`);
17502
18305
  }
17503
18306
  }
17504
18307
  } catch (error) {
17505
- throw new Error(`获取抖音用户主页作品列表失败: ${error}`);
18308
+ throw new Error(`获取抖音用户内容列表失败: ${error}`);
17506
18309
  }
17507
18310
  return willbepushlist;
17508
18311
  }
17509
- async checkIfAlreadyPushed(aweme_id, sec_uid, groupIds) {
17510
- for (const groupId of groupIds) if (!await douyinDBInstance.isAwemePushed(aweme_id, sec_uid, groupId)) return false;
18312
+ async checkIfAlreadyPushed(aweme_id, sec_uid, groupIds, pushType = "post") {
18313
+ for (const groupId of groupIds) if (!await douyinDBInstance.isAwemePushed(aweme_id, sec_uid, groupId, pushType)) return false;
17511
18314
  return true;
17512
18315
  }
17513
18316
  async setting(data$1) {
@@ -17552,6 +18355,12 @@ var DouYinpush = class extends Base {
17552
18355
  }
17553
18356
  } else {
17554
18357
  existingItem.group_id.push(`${groupId}:${botId}`);
18358
+ if (!existingItem.pushTypes || existingItem.pushTypes.length === 0) existingItem.pushTypes = [
18359
+ "post",
18360
+ "live",
18361
+ "favorite",
18362
+ "recommend"
18363
+ ];
17555
18364
  if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, UserInfoData.data.user.nickname);
17556
18365
  await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}`);
17557
18366
  if (Config.douyin.push.switch === false) await this.e.reply("请发送「#设置抖音推送开启」以进行推送");
@@ -17563,7 +18372,13 @@ var DouYinpush = class extends Base {
17563
18372
  sec_uid,
17564
18373
  group_id: [`${groupId}:${botId}`],
17565
18374
  remark: UserInfoData.data.user.nickname,
17566
- short_id: user_shortid
18375
+ short_id: user_shortid,
18376
+ pushTypes: [
18377
+ "post",
18378
+ "live",
18379
+ "favorite",
18380
+ "recommend"
18381
+ ]
17567
18382
  });
17568
18383
  if (!isSubscribed) await douyinDBInstance.subscribeDouyinUser(groupId, botId, sec_uid, user_shortid, UserInfoData.data.user.nickname);
17569
18384
  await this.e.reply(`群:${groupInfo.groupName}(${groupId})\n添加成功!${UserInfoData.data.user.nickname}\n抖音号:${user_shortid}`);
@@ -17591,7 +18406,9 @@ var DouYinpush = class extends Base {
17591
18406
  sec_uid,
17592
18407
  typeMode: "strict"
17593
18408
  });
17594
- const switchStatus = (Config.pushlist.douyin?.find((item) => item.sec_uid === sec_uid))?.switch !== false;
18409
+ const configItem = Config.pushlist.douyin?.find((item) => item.sec_uid === sec_uid);
18410
+ const switchStatus = configItem?.switch !== false;
18411
+ const pushTypes = configItem?.pushTypes || ["post"];
17595
18412
  renderOpt.push({
17596
18413
  avatar_img: userInfo.data.user.avatar_larger.url_list[0],
17597
18414
  username: userInfo.data.user.nickname,
@@ -17599,7 +18416,8 @@ var DouYinpush = class extends Base {
17599
18416
  fans: this.count(userInfo.data.user.follower_count),
17600
18417
  total_favorited: this.count(userInfo.data.user.total_favorited),
17601
18418
  following_count: this.count(userInfo.data.user.following_count),
17602
- switch: switchStatus
18419
+ switch: switchStatus,
18420
+ pushTypes
17603
18421
  });
17604
18422
  }
17605
18423
  const img$2 = await Render("douyin/userlist", {