karin-plugin-kkk 2.20.1 → 2.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [2.20.2](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.20.1...v2.20.2) (2026-02-25)
6
+
7
+
8
+ ### 🐛 错误修复
9
+
10
+ * **抖音:** 没有bgm导致解析错误 ([b8af209](https://github.com/ikenxuan/karin-plugin-kkk/commit/b8af2096e658c9ecca7122062cd6df8b9ea12e74))
11
+
12
+
13
+ ### 🧰 其他更新
14
+
15
+ * 移除未使用依赖 ([b79194b](https://github.com/ikenxuan/karin-plugin-kkk/commit/b79194b5d57240a408d1e70937d4cf1e5094d6ea))
16
+
17
+
18
+ ### 🗃️ 数据库迁移
19
+
20
+ * 优化删除逻辑 ([8208e66](https://github.com/ikenxuan/karin-plugin-kkk/commit/8208e66f345d4edb9fe4f945f7dea2fc2bfe752f))
21
+
22
+
23
+ ### 💯 细节优化
24
+
25
+ * 表情回应功能占位 ([c96377e](https://github.com/ikenxuan/karin-plugin-kkk/commit/c96377e9aeed57285f273300e9a1566bf1ebbf18))
26
+
5
27
  ## [2.20.1](https://github.com/ikenxuan/karin-plugin-kkk/compare/v2.20.0...v2.20.1) (2026-02-23)
6
28
 
7
29
 
package/lib/apps/admin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import { C as removeAllFiles, E as task, S as dylogin, T as setdyck, w as setbilick, x as biLogin } from "../core_chunk/main-C6bm6hYZ.js";
2
+ import { C as removeAllFiles, E as task, S as dylogin, T as setdyck, w as setbilick, x as biLogin } from "../core_chunk/main-Du8yBcGG.js";
3
3
  import "../core_chunk/vendor-B3KhGHI_.js";
4
4
  import "../core_chunk/template-CQ-u6h09.js";
5
5
  export { biLogin, dylogin, removeAllFiles, setbilick, setdyck, task };
package/lib/apps/help.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import { b as version, y as help } from "../core_chunk/main-C6bm6hYZ.js";
2
+ import { b as version, y as help } from "../core_chunk/main-Du8yBcGG.js";
3
3
  import "../core_chunk/vendor-B3KhGHI_.js";
4
4
  import "../core_chunk/template-CQ-u6h09.js";
5
5
  export { help, version };
package/lib/apps/push.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import { _ as setdyPush, d as bilibiliPushList, f as changeBotID, g as setbiliPush, h as forcePush, m as douyinPushList, p as douyinPush, u as bilibiliPush, v as testDouyinPush } from "../core_chunk/main-C6bm6hYZ.js";
2
+ import { _ as setdyPush, d as bilibiliPushList, f as changeBotID, g as setbiliPush, h as forcePush, m as douyinPushList, p as douyinPush, u as bilibiliPush, v as testDouyinPush } from "../core_chunk/main-Du8yBcGG.js";
3
3
  import "../core_chunk/vendor-B3KhGHI_.js";
4
4
  import "../core_chunk/template-CQ-u6h09.js";
5
5
  export { bilibiliPush, bilibiliPushList, changeBotID, douyinPush, douyinPushList, forcePush, setbiliPush, setdyPush, testDouyinPush };
@@ -1,5 +1,5 @@
1
1
  import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import { l as qrLogin } from "../core_chunk/main-C6bm6hYZ.js";
2
+ import { l as qrLogin } from "../core_chunk/main-Du8yBcGG.js";
3
3
  import "../core_chunk/vendor-B3KhGHI_.js";
4
4
  import "../core_chunk/template-CQ-u6h09.js";
5
5
  export { qrLogin };
package/lib/apps/tools.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import { a as douyinAPP, c as xiaohongshuAPP, i as bilibiliAPP, o as kuaishouAPP, s as prefix } from "../core_chunk/main-C6bm6hYZ.js";
2
+ import { a as douyinAPP, c as xiaohongshuAPP, i as bilibiliAPP, o as kuaishouAPP, s as prefix } from "../core_chunk/main-Du8yBcGG.js";
3
3
  import "../core_chunk/vendor-B3KhGHI_.js";
4
4
  import "../core_chunk/template-CQ-u6h09.js";
5
5
  export { bilibiliAPP, douyinAPP, kuaishouAPP, prefix, xiaohongshuAPP };
@@ -1,5 +1,5 @@
1
1
  import "../core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import { n as kkkUpdateCommand, r as update, t as kkkUpdate } from "../core_chunk/main-C6bm6hYZ.js";
2
+ import { n as kkkUpdateCommand, r as update, t as kkkUpdate } from "../core_chunk/main-Du8yBcGG.js";
3
3
  import "../core_chunk/vendor-B3KhGHI_.js";
4
4
  import "../core_chunk/template-CQ-u6h09.js";
5
5
  export { kkkUpdate, kkkUpdateCommand, update };
@@ -1,10 +1,10 @@
1
1
  {
2
- "version": "2.20.1",
3
- "buildTime": "2026-02-23T16:01:34.942Z",
4
- "buildTimestamp": 1771862494942,
2
+ "version": "2.20.2",
3
+ "buildTime": "2026-02-25T09:50:43.940Z",
4
+ "buildTimestamp": 1772013043941,
5
5
  "name": "karin-plugin-kkk",
6
6
  "description": "Karin 的「抖音」「B 站」视频解析/动态推送插件",
7
7
  "homepage": "https://github.com/ikenxuan/karin-plugin-kkk",
8
- "commitHash": "182d64bef47a9e02ded26f9bc17270cab8993411",
9
- "shortCommitHash": "182d64be"
8
+ "commitHash": "b8eb543fcf5da28726b4fd35fdb94e6d5167f9c6",
9
+ "shortCommitHash": "b8eb543f"
10
10
  }
@@ -6149,7 +6149,7 @@ var init_Config = __esmMin(() => {
6149
6149
  return getConfigInstance()[prop];
6150
6150
  } });
6151
6151
  });
6152
- var Base, statBotId$1, Count, uploadFile, downloadVideo, downloadFile, processFilename;
6152
+ var Base, Count, uploadFile, downloadVideo, downloadFile, processFilename;
6153
6153
  var init_Base = __esmMin(() => {
6154
6154
  init_utils$1();
6155
6155
  init_Config();
@@ -6163,50 +6163,6 @@ var init_Base = __esmMin(() => {
6163
6163
  this.headers = BASE_HEADERS;
6164
6164
  }
6165
6165
  };
6166
- statBotId$1 = (pushList) => {
6167
- const platformBotCount = {
6168
- douyin: /* @__PURE__ */ new Map(),
6169
- bilibili: /* @__PURE__ */ new Map()
6170
- };
6171
- pushList.douyin.forEach((item) => {
6172
- item.group_id.forEach((gid) => {
6173
- const botId = gid.split(":")[1];
6174
- platformBotCount.douyin.set(botId, (platformBotCount.douyin.get(botId) ?? 0) + 1);
6175
- });
6176
- });
6177
- pushList.bilibili.forEach((item) => {
6178
- item.group_id.forEach((gid) => {
6179
- const botId = gid.split(":")[1];
6180
- platformBotCount.bilibili.set(botId, (platformBotCount.bilibili.get(botId) ?? 0) + 1);
6181
- });
6182
- });
6183
- let douyinMaxCount = 0;
6184
- let douyinMostFrequentBot = "";
6185
- platformBotCount.douyin.forEach((count, botId) => {
6186
- if (count > douyinMaxCount) {
6187
- douyinMaxCount = count;
6188
- douyinMostFrequentBot = botId;
6189
- }
6190
- });
6191
- let biliMaxCount = 0;
6192
- let biliMostFrequentBot = "";
6193
- platformBotCount.bilibili.forEach((count, botId) => {
6194
- if (count > biliMaxCount) {
6195
- biliMaxCount = count;
6196
- biliMostFrequentBot = botId;
6197
- }
6198
- });
6199
- return {
6200
- douyin: {
6201
- botId: douyinMostFrequentBot,
6202
- count: douyinMaxCount
6203
- },
6204
- bilibili: {
6205
- botId: biliMostFrequentBot,
6206
- count: biliMaxCount
6207
- }
6208
- };
6209
- };
6210
6166
  Count = (count) => {
6211
6167
  if (count >= 1e8) return (count / 1e8).toFixed(1) + "亿";
6212
6168
  else if (count >= 1e4) return (count / 1e4).toFixed(1) + "万";
@@ -6810,6 +6766,9 @@ var init_Common = __esmMin(async () => {
6810
6766
  };
6811
6767
  Common = new Tools();
6812
6768
  });
6769
+ var init_EmojiReaction = __esmMin(() => {
6770
+ init_Config();
6771
+ });
6813
6772
  async function detectEncoder$1(codec) {
6814
6773
  if (cachedEncoders$1[codec]) return cachedEncoders$1[codec];
6815
6774
  logger.debug(`[BiliDanmaku] 开始检测 ${codec.toUpperCase()} 编码器...`);
@@ -7513,6 +7472,16 @@ async function getMediaDuration(path$1) {
7513
7472
  const { stdout } = await ffprobe(`-v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${path$1}"`);
7514
7473
  return parseFloat(parseFloat(stdout.trim()).toFixed(2));
7515
7474
  }
7475
+ async function loopVideo(inputPath, outputPath, loopCount) {
7476
+ if (loopCount <= 1) {
7477
+ fs.copyFileSync(inputPath, outputPath);
7478
+ return true;
7479
+ }
7480
+ const result = await ffmpeg(`-y -stream_loop ${loopCount - 1} -i "${inputPath}" -c copy "${outputPath}"`);
7481
+ if (result.status) logger.mark(`视频重放成功: ${outputPath}`);
7482
+ else logger.error("视频重放失败", result);
7483
+ return result.status;
7484
+ }
7516
7485
  async function mergeVideoAudio(videoPath, audioPath, resultPath) {
7517
7486
  const result = await ffmpeg(`-y -i "${videoPath}" -i "${audioPath}" -c copy "${resultPath}"`);
7518
7487
  if (result.status) logger.mark(`视频合成成功: ${resultPath}`);
@@ -7566,38 +7535,6 @@ async function mergeLiveImageContinuous(options, context) {
7566
7535
  }
7567
7536
  };
7568
7537
  }
7569
- async function batchMergeLiveImages(videos, bgmPath, outputDir, mode = "independent", loopCount = 3) {
7570
- const results = [];
7571
- if (mode === "independent") for (const video of videos) {
7572
- const outputPath = `${outputDir}${video.outputName}`;
7573
- const success = await mergeLiveImageIndependent({
7574
- videoPath: video.path,
7575
- outputPath,
7576
- loopCount
7577
- }, bgmPath);
7578
- results.push({
7579
- success,
7580
- outputPath
7581
- });
7582
- }
7583
- else {
7584
- let context = await createLiveImageContext(bgmPath);
7585
- for (const video of videos) {
7586
- const outputPath = `${outputDir}${video.outputName}`;
7587
- const result = await mergeLiveImageContinuous({
7588
- videoPath: video.path,
7589
- outputPath,
7590
- loopCount
7591
- }, context);
7592
- context = result.context;
7593
- results.push({
7594
- success: result.success,
7595
- outputPath
7596
- });
7597
- }
7598
- }
7599
- return results;
7600
- }
7601
7538
  var init_FFmpeg = __esmMin(async () => {
7602
7539
  await init_utils$1();
7603
7540
  await init_danmaku$1();
@@ -8142,12 +8079,12 @@ var init_Network$1 = __esmMin(() => {
8142
8079
  };
8143
8080
  });
8144
8081
  var init_Network = __esmMin(() => {
8145
- init_constants();
8146
8082
  init_Downloader();
8147
8083
  init_helpers();
8148
8084
  init_Network$1();
8149
8085
  init_ThrottleStream();
8150
8086
  init_types();
8087
+ init_constants();
8151
8088
  });
8152
8089
  var init_Networks = __esmMin(() => {
8153
8090
  init_Network();
@@ -8332,48 +8269,12 @@ var init_Render = __esmMin(async () => {
8332
8269
  return ret;
8333
8270
  };
8334
8271
  });
8335
- var utils_exports = __export({
8336
- BASE_HEADERS: () => BASE_HEADERS,
8337
- Base: () => Base,
8338
- Common: () => Common,
8339
- Count: () => Count,
8340
- DEFAULT_THROTTLE_CONFIG: () => DEFAULT_THROTTLE_CONFIG,
8341
- Downloader: () => Downloader,
8342
- Network: () => Network,
8343
- Networks: () => Network,
8344
- QRCodeScanner: () => QRCodeScanner,
8345
- Render: () => Render,
8346
- Root: () => Root,
8347
- ThrottleStream: () => ThrottleStream,
8348
- baseHeaders: () => BASE_HEADERS,
8349
- batchMergeLiveImages: () => batchMergeLiveImages,
8350
- burnDanmakuToVideo: () => burnBiliDanmaku,
8351
- burnDouyinDanmaku: () => burnDouyinDanmaku,
8352
- compressVideo: () => compressVideo,
8353
- createLiveImageContext: () => createLiveImageContext,
8354
- danmakuToASS: () => generateBiliASS,
8355
- downloadFile: () => downloadFile,
8356
- downloadVideo: () => downloadVideo,
8357
- formatBuildTime: () => formatBuildTime,
8358
- formatBytes: () => formatBytes,
8359
- getBuildMetadata: () => getBuildMetadata,
8360
- getErrorDescription: () => getErrorDescription,
8361
- getMediaDuration: () => getMediaDuration,
8362
- isRecoverableNetworkError: () => isRecoverableNetworkError,
8363
- isThrottlingError: () => isThrottlingError,
8364
- mergeAndBurnDanmaku: () => mergeAndBurnBili,
8365
- mergeLiveImageContinuous: () => mergeLiveImageContinuous,
8366
- mergeLiveImageIndependent: () => mergeLiveImageIndependent,
8367
- mergeVideoAudio: () => mergeVideoAudio,
8368
- sanitizeHeaders: () => sanitizeHeaders,
8369
- statBotId: () => statBotId$1,
8370
- uploadFile: () => uploadFile
8371
- }, 1);
8372
8272
  var init_utils$1 = __esmMin(async () => {
8373
8273
  init_root();
8374
8274
  init_Base();
8375
8275
  init_build_metadata();
8376
8276
  init_Common();
8277
+ init_EmojiReaction();
8377
8278
  init_FFmpeg();
8378
8279
  init_Networks();
8379
8280
  init_QRCodeScanner();
@@ -8541,6 +8442,14 @@ var init_bilibili = __esmMin(async () => {
8541
8442
  async unsubscribeBilibiliUser(groupId, host_mid) {
8542
8443
  const result = await this.runQuery("DELETE FROM GroupUserSubscriptions WHERE groupId = ? AND host_mid = ?", [groupId, host_mid]);
8543
8444
  await this.runQuery("DELETE FROM DynamicCaches WHERE groupId = ? AND host_mid = ?", [groupId, host_mid]);
8445
+ const remainingSubscriptions = await this.getQuery("SELECT COUNT(*) as count FROM GroupUserSubscriptions WHERE host_mid = ?", [host_mid]);
8446
+ if (remainingSubscriptions && remainingSubscriptions.count === 0) {
8447
+ logger.info(`[BilibiliDB] 用户 ${host_mid} 已无任何群组订阅,清理相关数据`);
8448
+ await this.runQuery("DELETE FROM BilibiliUsers WHERE host_mid = ?", [host_mid]);
8449
+ await this.runQuery("DELETE FROM FilterWords WHERE host_mid = ?", [host_mid]);
8450
+ await this.runQuery("DELETE FROM FilterTags WHERE host_mid = ?", [host_mid]);
8451
+ await this.runQuery("DELETE FROM DynamicCaches WHERE host_mid = ?", [host_mid]);
8452
+ }
8544
8453
  return result.changes > 0;
8545
8454
  }
8546
8455
  async addDynamicCache(dynamic_id, host_mid, groupId, dynamic_type) {
@@ -8919,11 +8828,24 @@ var init_douyin = __esmMin(async () => {
8919
8828
  logger.info("[DouyinDB] 检测到 AwemeCaches 表缺少 pushType 字段,开始执行迁移...");
8920
8829
  await this.runQuery("ALTER TABLE AwemeCaches ADD COLUMN pushType TEXT DEFAULT 'post'");
8921
8830
  await this.runQuery("ALTER TABLE AwemeCaches RENAME TO AwemeCaches_old");
8922
- 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 `);
8831
+ 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 UNIQUE(aweme_id, sec_uid, groupId, pushType)\n )\n `);
8923
8832
  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 `);
8924
8833
  await this.runQuery("DROP TABLE AwemeCaches_old");
8925
8834
  logger.info("[DouyinDB] AwemeCaches 表迁移完成");
8926
8835
  }
8836
+ try {
8837
+ const tableInfo = await this.allQuery("SELECT sql FROM sqlite_master WHERE type='table' AND name='AwemeCaches'");
8838
+ if (tableInfo.length > 0 && tableInfo[0].sql.includes("FOREIGN KEY (groupId) REFERENCES Groups(id)")) {
8839
+ logger.info("[DouyinDB] 检测到 AwemeCaches 表存在错误的外键约束,开始修复...");
8840
+ await this.runQuery("ALTER TABLE AwemeCaches RENAME TO AwemeCaches_old");
8841
+ 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 UNIQUE(aweme_id, sec_uid, groupId, pushType)\n )\n `);
8842
+ 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 `);
8843
+ await this.runQuery("DROP TABLE AwemeCaches_old");
8844
+ logger.info("[DouyinDB] AwemeCaches 表外键约束修复完成");
8845
+ }
8846
+ } catch (error) {
8847
+ logger.debug("[DouyinDB] 外键约束检查/修复跳过:", error);
8848
+ }
8927
8849
  } catch (error) {
8928
8850
  logger.error("[DouyinDB] 数据库迁移失败:", error);
8929
8851
  }
@@ -8934,7 +8856,7 @@ var init_douyin = __esmMin(async () => {
8934
8856
  `CREATE TABLE IF NOT EXISTS Groups (\n id TEXT NOT NULL,\n botId TEXT NOT NULL,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (id, botId),\n FOREIGN KEY (botId) REFERENCES Bots(id)\n )`,
8935
8857
  `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 )`,
8936
8858
  `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 )`,
8937
- `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 )`,
8859
+ `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 UNIQUE(aweme_id, sec_uid, groupId, pushType)\n )`,
8938
8860
  `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 )`,
8939
8861
  `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 )`,
8940
8862
  `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 )`
@@ -9077,6 +8999,14 @@ var init_douyin = __esmMin(async () => {
9077
8999
  async unsubscribeDouyinUser(groupId, sec_uid) {
9078
9000
  const result = await this.runQuery("DELETE FROM GroupUserSubscriptions WHERE groupId = ? AND sec_uid = ?", [groupId, sec_uid]);
9079
9001
  await this.runQuery("DELETE FROM AwemeCaches WHERE groupId = ? AND sec_uid = ?", [groupId, sec_uid]);
9002
+ const remainingSubscriptions = await this.getQuery("SELECT COUNT(*) as count FROM GroupUserSubscriptions WHERE sec_uid = ?", [sec_uid]);
9003
+ if (remainingSubscriptions && remainingSubscriptions.count === 0) {
9004
+ logger.info(`[DouyinDB] 用户 ${sec_uid} 已无任何群组订阅,清理相关数据`);
9005
+ await this.runQuery("DELETE FROM DouyinUsers WHERE sec_uid = ?", [sec_uid]);
9006
+ await this.runQuery("DELETE FROM FilterWords WHERE sec_uid = ?", [sec_uid]);
9007
+ await this.runQuery("DELETE FROM FilterTags WHERE sec_uid = ?", [sec_uid]);
9008
+ await this.runQuery("DELETE FROM AwemeCaches WHERE sec_uid = ?", [sec_uid]);
9009
+ }
9080
9010
  return result.changes > 0;
9081
9011
  }
9082
9012
  async addAwemeCache(aweme_id, sec_uid, groupId, pushType = "post") {
@@ -17260,17 +17190,20 @@ var DouYin = class extends Base {
17260
17190
  const processedImages = [];
17261
17191
  const temp = [];
17262
17192
  g_title = VideoData.data.aweme_detail.preview_title.substring(0, 50).replace(/[\\/:*?"<>|\r\n]/g, " ");
17263
- let mp3Path = "";
17264
- if (VideoData.data.aweme_detail.music.play_url.uri === "") mp3Path = JSON.parse(VideoData.data.aweme_detail.music.extra).original_song_url;
17265
- else mp3Path = VideoData.data.aweme_detail.music.play_url.uri;
17266
- const liveimgbgm = await downloadFile(mp3Path, {
17267
- title: `Douyin_tmp_A_${Date.now()}.mp3`,
17268
- headers: this.headers
17269
- });
17270
- temp.push(liveimgbgm);
17271
- const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
17193
+ let liveimgbgm = null;
17272
17194
  let bgmContext = null;
17273
- if (mergeMode === "continuous") bgmContext = await createLiveImageContext(liveimgbgm.filepath);
17195
+ const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
17196
+ if (VideoData.data.aweme_detail.music) {
17197
+ let mp3Path = "";
17198
+ if (VideoData.data.aweme_detail.music.play_url.uri === "") mp3Path = JSON.parse(VideoData.data.aweme_detail.music.extra).original_song_url;
17199
+ else mp3Path = VideoData.data.aweme_detail.music.play_url.uri;
17200
+ liveimgbgm = await downloadFile(mp3Path, {
17201
+ title: `Douyin_tmp_A_${Date.now()}.mp3`,
17202
+ headers: this.headers
17203
+ });
17204
+ temp.push(liveimgbgm);
17205
+ if (mergeMode === "continuous") bgmContext = await createLiveImageContext(liveimgbgm.filepath);
17206
+ }
17274
17207
  for (const [index, imageItem] of images.entries()) {
17275
17208
  imagenum++;
17276
17209
  if (imageItem.clip_type === 2 || imageItem.clip_type === void 0) {
@@ -17294,7 +17227,12 @@ var DouYin = class extends Base {
17294
17227
  const outputPath = Common.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
17295
17228
  let success;
17296
17229
  const loopCount = imageItem.clip_type === 4 ? 1 : 3;
17297
- if (mergeMode === "continuous" && bgmContext) {
17230
+ if (!liveimgbgm) if (loopCount > 1) success = await loopVideo(liveimg.filepath, outputPath, loopCount);
17231
+ else {
17232
+ fs.renameSync(liveimg.filepath, outputPath);
17233
+ success = true;
17234
+ }
17235
+ else if (mergeMode === "continuous" && bgmContext) {
17298
17236
  const result = await mergeLiveImageContinuous({
17299
17237
  videoPath: liveimg.filepath,
17300
17238
  outputPath,
@@ -17367,22 +17305,25 @@ var DouYin = class extends Base {
17367
17305
  case VideoData.data.aweme_detail.is_slides === true && VideoData.data.aweme_detail.images !== null: {
17368
17306
  const images = [];
17369
17307
  const temp = [];
17370
- let mp3Path = "";
17371
- if (VideoData.data.aweme_detail.music.play_url.uri === "") mp3Path = JSON.parse(VideoData.data.aweme_detail.music.extra).original_song_url;
17372
- else mp3Path = VideoData.data.aweme_detail.music.play_url.uri;
17373
- const liveimgbgm = await downloadFile(mp3Path, {
17374
- title: `Douyin_tmp_A_${Date.now()}.mp3`,
17375
- headers: this.headers
17376
- });
17377
- temp.push(liveimgbgm);
17308
+ let liveimgbgm = null;
17309
+ let bgmContext = null;
17310
+ const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
17311
+ if (VideoData.data.aweme_detail.music) {
17312
+ let mp3Path = "";
17313
+ if (VideoData.data.aweme_detail.music.play_url.uri === "") mp3Path = JSON.parse(VideoData.data.aweme_detail.music.extra).original_song_url;
17314
+ else mp3Path = VideoData.data.aweme_detail.music.play_url.uri;
17315
+ liveimgbgm = await downloadFile(mp3Path, {
17316
+ title: `Douyin_tmp_A_${Date.now()}.mp3`,
17317
+ headers: this.headers
17318
+ });
17319
+ temp.push(liveimgbgm);
17320
+ if (mergeMode === "continuous") bgmContext = await createLiveImageContext(liveimgbgm.filepath);
17321
+ }
17378
17322
  const images1 = VideoData.data.aweme_detail.images ?? [];
17379
17323
  if (!images1.length) logger.debug("未获取到合辑的图片数据");
17380
- const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
17381
- let bgmContext = null;
17382
- if (mergeMode === "continuous") bgmContext = await createLiveImageContext(liveimgbgm.filepath);
17383
17324
  for (const item of images1) {
17384
17325
  imagenum++;
17385
- if (item.clip_type === 2) {
17326
+ if (item.clip_type === 2 || item.clip_type === void 0) {
17386
17327
  images.push(segment.image(item.url_list[0]));
17387
17328
  continue;
17388
17329
  }
@@ -17394,7 +17335,12 @@ var DouYin = class extends Base {
17394
17335
  const outputPath = Common.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
17395
17336
  let success;
17396
17337
  const loopCount = item.clip_type === 4 ? 1 : 3;
17397
- if (mergeMode === "continuous" && bgmContext) {
17338
+ if (!liveimgbgm) if (loopCount > 1) success = await loopVideo(liveimg.filepath, outputPath, loopCount);
17339
+ else {
17340
+ fs.renameSync(liveimg.filepath, outputPath);
17341
+ success = true;
17342
+ }
17343
+ else if (mergeMode === "continuous" && bgmContext) {
17398
17344
  const result = await mergeLiveImageContinuous({
17399
17345
  videoPath: liveimg.filepath,
17400
17346
  outputPath,
@@ -17609,13 +17555,12 @@ var DouYin = class extends Base {
17609
17555
  await Common.removeFile(videoFile.filepath, true);
17610
17556
  const stats = fs.statSync(filePath);
17611
17557
  const fileSizeInMB = Number((stats.size / (1024 * 1024)).toFixed(2));
17612
- const { uploadFile: uploadFile$1 } = await init_utils$1().then(() => utils_exports);
17613
- if (fileSizeInMB > Config.upload.groupfilevalue) await uploadFile$1(this.e, {
17558
+ if (fileSizeInMB > Config.upload.groupfilevalue) await uploadFile(this.e, {
17614
17559
  filepath: filePath,
17615
17560
  totalBytes: fileSizeInMB,
17616
17561
  originTitle: g_title || ""
17617
17562
  }, "", { useGroupFile: true });
17618
- else await uploadFile$1(this.e, {
17563
+ else await uploadFile(this.e, {
17619
17564
  filepath: filePath,
17620
17565
  totalBytes: fileSizeInMB,
17621
17566
  originTitle: g_title || ""
@@ -18338,7 +18283,7 @@ var DouYinpush = class extends Base {
18338
18283
  })()
18339
18284
  });
18340
18285
  }
18341
- for (const target of pushItem.targets) try {
18286
+ for (const target of pushItem.targets) {
18342
18287
  let status = { message_id: "" };
18343
18288
  const { groupId, botId } = target;
18344
18289
  if (!skip) {
@@ -18376,22 +18321,22 @@ var DouYinpush = class extends Base {
18376
18321
  if (Detail_Data.is_slides === true && Detail_Data.images) {
18377
18322
  const images = [];
18378
18323
  const temp = [];
18379
- let mp3Path = "";
18380
- if (Detail_Data.music.play_url.uri === "") mp3Path = JSON.parse(Detail_Data.music.extra).original_song_url;
18381
- else mp3Path = Detail_Data.music.play_url.uri;
18382
- const liveimgbgm = await downloadFile(mp3Path, {
18383
- title: `Douyin_tmp_A_${Date.now()}.mp3`,
18384
- headers: douyinBaseHeaders
18385
- });
18386
- temp.push(liveimgbgm);
18387
- const images1 = Detail_Data.images ?? [];
18388
- if (!images1.length) logger.debug("未获取到合辑的图片数据");
18389
- const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
18324
+ let liveimgbgm = null;
18390
18325
  let bgmContext = null;
18391
- if (mergeMode === "continuous") {
18392
- const { createLiveImageContext: createLiveImageContext$1 } = await init_utils$1().then(() => utils_exports);
18393
- bgmContext = await createLiveImageContext$1(liveimgbgm.filepath);
18326
+ const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
18327
+ if (Detail_Data.music) {
18328
+ let mp3Path = "";
18329
+ if (Detail_Data.music.play_url.uri === "") mp3Path = JSON.parse(Detail_Data.music.extra).original_song_url;
18330
+ else mp3Path = Detail_Data.music.play_url.uri;
18331
+ liveimgbgm = await downloadFile(mp3Path, {
18332
+ title: `Douyin_tmp_A_${Date.now()}.mp3`,
18333
+ headers: douyinBaseHeaders
18334
+ });
18335
+ temp.push(liveimgbgm);
18336
+ if (mergeMode === "continuous") bgmContext = await createLiveImageContext(liveimgbgm.filepath);
18394
18337
  }
18338
+ const images1 = Detail_Data.images ?? [];
18339
+ if (!images1.length) logger.debug("未获取到合辑的图片数据");
18395
18340
  for (const item of images1) {
18396
18341
  if (item.clip_type === 2 || item.clip_type === void 0) {
18397
18342
  images.push(segment.image(item.url_list[0]));
@@ -18402,37 +18347,40 @@ var DouYinpush = class extends Base {
18402
18347
  headers: douyinBaseHeaders
18403
18348
  });
18404
18349
  if (liveimg.filepath) {
18405
- const { Common: Common$1, mergeLiveImageContinuous: mergeLiveImageContinuous$1, mergeLiveImageIndependent: mergeLiveImageIndependent$1 } = await init_utils$1().then(() => utils_exports);
18406
- const outputPath = Common$1.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
18350
+ const outputPath = Common.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
18407
18351
  let success;
18408
18352
  const loopCount = item.clip_type === 4 ? 1 : 3;
18409
- if (mergeMode === "continuous" && bgmContext) {
18410
- const result = await mergeLiveImageContinuous$1({
18353
+ if (!liveimgbgm) if (loopCount > 1) success = await loopVideo(liveimg.filepath, outputPath, loopCount);
18354
+ else {
18355
+ fs.renameSync(liveimg.filepath, outputPath);
18356
+ success = true;
18357
+ }
18358
+ else if (mergeMode === "continuous" && bgmContext) {
18359
+ const result = await mergeLiveImageContinuous({
18411
18360
  videoPath: liveimg.filepath,
18412
18361
  outputPath,
18413
18362
  loopCount
18414
18363
  }, bgmContext);
18415
18364
  success = result.success;
18416
18365
  bgmContext = result.context;
18417
- } else success = await mergeLiveImageIndependent$1({
18366
+ } else success = await mergeLiveImageIndependent({
18418
18367
  videoPath: liveimg.filepath,
18419
18368
  outputPath,
18420
18369
  loopCount
18421
18370
  }, liveimgbgm.filepath);
18422
18371
  if (success) {
18423
- const fs$1 = await import("node:fs");
18424
- const filePath = Common$1.tempDri.video + `tmp_${Date.now()}.mp4`;
18425
- fs$1.default.renameSync(outputPath, filePath);
18372
+ const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
18373
+ fs.renameSync(outputPath, filePath);
18426
18374
  logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
18427
18375
  logger.mark("正在尝试删除缓存文件");
18428
- await Common$1.removeFile(liveimg.filepath, true);
18376
+ await Common.removeFile(liveimg.filepath, true);
18429
18377
  temp.push({
18430
18378
  filepath: filePath,
18431
18379
  totalBytes: 0
18432
18380
  });
18433
18381
  images.push(segment.video("file://" + filePath));
18434
18382
  if (item.clip_type === 5 && item.url_list?.[0]) images.push(segment.image(item.url_list[0]));
18435
- } else await Common$1.removeFile(liveimg.filepath, true);
18383
+ } else await Common.removeFile(liveimg.filepath, true);
18436
18384
  }
18437
18385
  }
18438
18386
  const bot = karin$1.getBot(botId);
@@ -18447,30 +18395,27 @@ var DouYinpush = class extends Base {
18447
18395
  } catch (error) {
18448
18396
  logger.error(`发送合辑失败: ${error}`);
18449
18397
  } finally {
18450
- for (const item of temp) {
18451
- const { Common: Common$1 } = await init_utils$1().then(() => utils_exports);
18452
- await Common$1.removeFile(item.filepath, true);
18453
- }
18398
+ for (const item of temp) await Common.removeFile(item.filepath, true);
18454
18399
  }
18455
- } else if (Detail_Data.images) if (Detail_Data.images.some((item) => item.clip_type !== 2)) {
18400
+ } else if (Detail_Data.images) if (Detail_Data.images.some((item) => item.clip_type !== 2 && item.clip_type !== void 0)) {
18456
18401
  const processedImages = [];
18457
18402
  const temp = [];
18458
- let mp3Path = "";
18459
- if (Detail_Data.music.play_url.uri === "") mp3Path = JSON.parse(Detail_Data.music.extra).original_song_url;
18460
- else mp3Path = Detail_Data.music.play_url.uri;
18461
- const liveimgbgm = await downloadFile(mp3Path, {
18462
- title: `Douyin_tmp_A_${Date.now()}.mp3`,
18463
- headers: douyinBaseHeaders
18464
- });
18465
- temp.push(liveimgbgm);
18466
- const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
18403
+ let liveimgbgm = null;
18467
18404
  let bgmContext = null;
18468
- if (mergeMode === "continuous") {
18469
- const { createLiveImageContext: createLiveImageContext$1 } = await init_utils$1().then(() => utils_exports);
18470
- bgmContext = await createLiveImageContext$1(liveimgbgm.filepath);
18405
+ const mergeMode = Config.douyin.liveImageMergeMode ?? "independent";
18406
+ if (Detail_Data.music) {
18407
+ let mp3Path = "";
18408
+ if (Detail_Data.music.play_url.uri === "") mp3Path = JSON.parse(Detail_Data.music.extra).original_song_url;
18409
+ else mp3Path = Detail_Data.music.play_url.uri;
18410
+ liveimgbgm = await downloadFile(mp3Path, {
18411
+ title: `Douyin_tmp_A_${Date.now()}.mp3`,
18412
+ headers: douyinBaseHeaders
18413
+ });
18414
+ temp.push(liveimgbgm);
18415
+ if (mergeMode === "continuous") bgmContext = await createLiveImageContext(liveimgbgm.filepath);
18471
18416
  }
18472
18417
  for (const item of Detail_Data.images) {
18473
- if (item.clip_type === 2) {
18418
+ if (item.clip_type === 2 || item.clip_type === void 0) {
18474
18419
  const image_url = item.url_list[2] ?? item.url_list[1];
18475
18420
  processedImages.push(segment.image(image_url));
18476
18421
  continue;
@@ -18480,37 +18425,40 @@ var DouYinpush = class extends Base {
18480
18425
  headers: douyinBaseHeaders
18481
18426
  });
18482
18427
  if (liveimg.filepath) {
18483
- const { Common: Common$1, mergeLiveImageContinuous: mergeLiveImageContinuous$1, mergeLiveImageIndependent: mergeLiveImageIndependent$1 } = await init_utils$1().then(() => utils_exports);
18484
- const outputPath = Common$1.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
18428
+ const outputPath = Common.tempDri.video + `Douyin_Result_${Date.now()}.mp4`;
18485
18429
  let success;
18486
18430
  const loopCount = item.clip_type === 4 ? 1 : 3;
18487
- if (mergeMode === "continuous" && bgmContext) {
18488
- const result = await mergeLiveImageContinuous$1({
18431
+ if (!liveimgbgm) if (loopCount > 1) success = await loopVideo(liveimg.filepath, outputPath, loopCount);
18432
+ else {
18433
+ fs.renameSync(liveimg.filepath, outputPath);
18434
+ success = true;
18435
+ }
18436
+ else if (mergeMode === "continuous" && bgmContext) {
18437
+ const result = await mergeLiveImageContinuous({
18489
18438
  videoPath: liveimg.filepath,
18490
18439
  outputPath,
18491
18440
  loopCount
18492
18441
  }, bgmContext);
18493
18442
  success = result.success;
18494
18443
  bgmContext = result.context;
18495
- } else success = await mergeLiveImageIndependent$1({
18444
+ } else success = await mergeLiveImageIndependent({
18496
18445
  videoPath: liveimg.filepath,
18497
18446
  outputPath,
18498
18447
  loopCount
18499
18448
  }, liveimgbgm.filepath);
18500
18449
  if (success) {
18501
- const fs$1 = await import("node:fs");
18502
- const filePath = Common$1.tempDri.video + `tmp_${Date.now()}.mp4`;
18503
- fs$1.default.renameSync(outputPath, filePath);
18450
+ const filePath = Common.tempDri.video + `tmp_${Date.now()}.mp4`;
18451
+ fs.renameSync(outputPath, filePath);
18504
18452
  logger.mark(`视频文件重命名完成: ${outputPath.split("/").pop()} -> ${filePath.split("/").pop()}`);
18505
18453
  logger.mark("正在尝试删除缓存文件");
18506
- await Common$1.removeFile(liveimg.filepath, true);
18454
+ await Common.removeFile(liveimg.filepath, true);
18507
18455
  temp.push({
18508
18456
  filepath: filePath,
18509
18457
  totalBytes: 0
18510
18458
  });
18511
18459
  processedImages.push(segment.video("file://" + filePath));
18512
18460
  if (item.clip_type === 5 && item.url_list?.[0]) processedImages.push(segment.image(item.url_list[0]));
18513
- } else await Common$1.removeFile(liveimg.filepath, true);
18461
+ } else await Common.removeFile(liveimg.filepath, true);
18514
18462
  }
18515
18463
  }
18516
18464
  const bot = karin$1.getBot(botId);
@@ -18525,10 +18473,7 @@ var DouYinpush = class extends Base {
18525
18473
  } catch (error) {
18526
18474
  logger.error(`发送图集失败: ${error}`);
18527
18475
  } finally {
18528
- for (const item of temp) {
18529
- const { Common: Common$1 } = await init_utils$1().then(() => utils_exports);
18530
- await Common$1.removeFile(item.filepath, true);
18531
- }
18476
+ for (const item of temp) await Common.removeFile(item.filepath, true);
18532
18477
  }
18533
18478
  } else {
18534
18479
  const imageres = [];
@@ -18553,8 +18498,6 @@ var DouYinpush = class extends Base {
18553
18498
  }
18554
18499
  }
18555
18500
  if (skip || pushItem.pushType !== "live" && status.message_id) await douyinDBInstance.addAwemeCache(actualAwemeId, pushItem.sec_uid, groupId, pushItem.pushType);
18556
- } catch (error) {
18557
- throw new Error(`${error}`);
18558
18501
  }
18559
18502
  }
18560
18503
  return true;
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import "./core_chunk/main-C6bm6hYZ.js";
2
+ import "./core_chunk/main-Du8yBcGG.js";
3
3
  import "./core_chunk/vendor-B3KhGHI_.js";
4
4
  import "./core_chunk/template-CQ-u6h09.js";
5
5
  export {};
package/lib/root.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import "./core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import { A as init_root, k as Root } from "./core_chunk/main-C6bm6hYZ.js";
2
+ import { A as init_root, k as Root } from "./core_chunk/main-Du8yBcGG.js";
3
3
  init_root();
4
4
  export { Root };
package/lib/web.config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./core_chunk/rolldown-runtime-BMXAG3ag.js";
2
- import { D as webConfig, O as web_config_default } from "./core_chunk/main-C6bm6hYZ.js";
2
+ import { D as webConfig, O as web_config_default } from "./core_chunk/main-Du8yBcGG.js";
3
3
  import "./core_chunk/vendor-B3KhGHI_.js";
4
4
  import "./core_chunk/template-CQ-u6h09.js";
5
5
  export { web_config_default as default, webConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karin-plugin-kkk",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Karin 的「抖音」「B 站」视频解析/动态推送插件",
5
5
  "keywords": [
6
6
  "karin-plugin",