karin-plugin-kkk 1.1.11 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # 变更日志
2
2
 
3
+ ## [1.2.0](https://github.com/ikenxuan/karin-plugin-kkk/compare/v1.1.11...v1.2.0) (2025-04-08)
4
+
5
+
6
+ ### Features
7
+
8
+ * close [#62](https://github.com/ikenxuan/karin-plugin-kkk/issues/62) ([d9b5a98](https://github.com/ikenxuan/karin-plugin-kkk/commit/d9b5a984f9b00f9bb37e3dadfb253a15ae5609e6))
9
+
3
10
  ## [1.1.11](https://github.com/ikenxuan/karin-plugin-kkk/compare/v1.1.10...v1.1.11) (2025-04-05)
4
11
 
5
12
 
@@ -20,14 +20,24 @@ autoResolution: true
20
20
  push:
21
21
  # 推送开关,开启后需重启;使用「#设置B站推送 + 用户UID」配置推送列表
22
22
  switch: true
23
- # 动态中有指定关键词时,不推送
24
- banWords:
25
- - 关键词1
26
- - 关键词2
27
- # 动态中有指定标签时,不推送
28
- banTags:
29
- - 标签1
30
- - 标签2
23
+ # 过滤模式:blacklist为黑名单模式,whitelist为白名单模式
24
+ filterMode: blacklist
25
+ # 黑名单模式:动态中有指定关键词时,不推送
26
+ filterKeywords:
27
+ - 黑名单关键词1
28
+ - 黑名单关键词2
29
+ # 黑名单模式:动态中有指定标签时,不推送
30
+ filterTags:
31
+ - 黑名单标签1
32
+ - 黑名单标签2
33
+ # 白名单模式:动态中有指定关键词时,才推送
34
+ whitelistKeywords:
35
+ - 白名单关键词1
36
+ - 白名单关键词2
37
+ # 白名单模式:动态中有指定标签时,才推送
38
+ whitelistTags:
39
+ - 白名单标签1
40
+ - 白名单标签2
31
41
  # 谁可以设置推送,all为所有人,admin为管理员,master为主人,group.owner为群主,group.admin为群管理员
32
42
  permission: master
33
43
  # 推送定时任务的cron表达式,默认为每十分钟推送一次
@@ -17,14 +17,24 @@ autoResolution: true
17
17
  push:
18
18
  # 推送开关,开启后需重启;使用「#设置抖音推送 + 抖音号」配置推送列表
19
19
  switch: true
20
- # 作品中有指定关键词时,不推送
21
- banWords:
22
- - 关键词1
23
- - 关键词2
24
- # 作品中有指定标签时,不推送
25
- banTags:
26
- - 标签1
27
- - 标签2
20
+ # 过滤模式:blacklist为黑名单模式,whitelist为白名单模式
21
+ filterMode: blacklist
22
+ # 黑名单模式:作品中有指定关键词时,不推送
23
+ filterKeywords:
24
+ - 黑名单关键词1
25
+ - 黑名单关键词2
26
+ # 黑名单模式:作品中有指定标签时,不推送
27
+ filterTags:
28
+ - 黑名单标签1
29
+ - 黑名单标签2
30
+ # 白名单模式:作品中有指定关键词时,才推送
31
+ whitelistKeywords:
32
+ - 白名单关键词1
33
+ - 白名单关键词2
34
+ # 白名单模式:作品中有指定标签时,才推送
35
+ whitelistTags:
36
+ - 白名单标签1
37
+ - 白名单标签2
28
38
  # 谁可以设置推送,all为所有人,admin为管理员,master为主人,group.owner为群主,group.admin为群管理员
29
39
  permission: master
30
40
  # 推送定时任务的cron表达式,默认为每十分钟推送一次
@@ -9,6 +9,11 @@ declare class Cfg {
9
9
  constructor();
10
10
  /** 初始化配置 */
11
11
  initCfg(): this;
12
+ /**
13
+ * 迁移配置中的 banWords 和 banTags 到新的字段
14
+ * @param configName 配置名称,如 'douyin' 或 'bilibili'
15
+ */
16
+ private migrateFilterConfig;
12
17
  /**
13
18
  * 获取默认配置和用户配置
14
19
  * @param name 配置文件名
@@ -55,8 +60,11 @@ declare class Cfg {
55
60
  autoResolution: boolean;
56
61
  push: {
57
62
  switch: boolean;
58
- banWords: string[];
59
- banTags: string[];
63
+ filterMode: "blacklist" | "whitelist";
64
+ filterKeywords: string[];
65
+ filterTags: string[];
66
+ whitelistKeywords: string[];
67
+ whitelistTags: string[];
60
68
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
61
69
  cron: string;
62
70
  parsedynamic: boolean;
@@ -72,8 +80,11 @@ declare class Cfg {
72
80
  autoResolution: boolean;
73
81
  push: {
74
82
  switch: boolean;
75
- banWords: string[];
76
- banTags: string[];
83
+ filterMode: "blacklist" | "whitelist";
84
+ filterKeywords: string[];
85
+ filterTags: string[];
86
+ whitelistKeywords: string[];
87
+ whitelistTags: string[];
77
88
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
78
89
  cron: string;
79
90
  parsedynamic: boolean;
@@ -132,8 +143,11 @@ declare class Cfg {
132
143
  autoResolution: boolean;
133
144
  push: {
134
145
  switch: boolean;
135
- banWords: string[];
136
- banTags: string[];
146
+ filterMode: "blacklist" | "whitelist";
147
+ filterKeywords: string[];
148
+ filterTags: string[];
149
+ whitelistKeywords: string[];
150
+ whitelistTags: string[];
137
151
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
138
152
  cron: string;
139
153
  parsedynamic: boolean;
@@ -150,8 +164,11 @@ declare class Cfg {
150
164
  autoResolution: boolean;
151
165
  push: {
152
166
  switch: boolean;
153
- banWords: string[];
154
- banTags: string[];
167
+ filterMode: "blacklist" | "whitelist";
168
+ filterKeywords: string[];
169
+ filterTags: string[];
170
+ whitelistKeywords: string[];
171
+ whitelistTags: string[];
155
172
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
156
173
  cron: string;
157
174
  parsedynamic: boolean;
@@ -230,8 +247,11 @@ declare class Cfg {
230
247
  autoResolution: boolean;
231
248
  push: {
232
249
  switch: boolean;
233
- banWords: string[];
234
- banTags: string[];
250
+ filterMode: "blacklist" | "whitelist";
251
+ filterKeywords: string[];
252
+ filterTags: string[];
253
+ whitelistKeywords: string[];
254
+ whitelistTags: string[];
235
255
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
236
256
  cron: string;
237
257
  parsedynamic: boolean;
@@ -253,8 +273,11 @@ declare class Cfg {
253
273
  autoResolution: boolean;
254
274
  push: {
255
275
  switch: boolean;
256
- banWords: string[];
257
- banTags: string[];
276
+ filterMode: "blacklist" | "whitelist";
277
+ filterKeywords: string[];
278
+ filterTags: string[];
279
+ whitelistKeywords: string[];
280
+ whitelistTags: string[];
258
281
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
259
282
  cron: string;
260
283
  parsedynamic: boolean;
@@ -345,8 +368,11 @@ declare class Cfg {
345
368
  autoResolution: boolean;
346
369
  push: {
347
370
  switch: boolean;
348
- banWords: string[];
349
- banTags: string[];
371
+ filterMode: "blacklist" | "whitelist";
372
+ filterKeywords: string[];
373
+ filterTags: string[];
374
+ whitelistKeywords: string[];
375
+ whitelistTags: string[];
350
376
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
351
377
  cron: string;
352
378
  parsedynamic: boolean;
@@ -369,8 +395,11 @@ declare class Cfg {
369
395
  autoResolution: boolean;
370
396
  push: {
371
397
  switch: boolean;
372
- banWords: string[];
373
- banTags: string[];
398
+ filterMode: "blacklist" | "whitelist";
399
+ filterKeywords: string[];
400
+ filterTags: string[];
401
+ whitelistKeywords: string[];
402
+ whitelistTags: string[];
374
403
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
375
404
  cron: string;
376
405
  parsedynamic: boolean;
@@ -411,8 +440,11 @@ declare class Cfg {
411
440
  autoResolution: boolean;
412
441
  push: {
413
442
  switch: boolean;
414
- banWords: string[];
415
- banTags: string[];
443
+ filterMode: "blacklist" | "whitelist";
444
+ filterKeywords: string[];
445
+ filterTags: string[];
446
+ whitelistKeywords: string[];
447
+ whitelistTags: string[];
416
448
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
417
449
  cron: string;
418
450
  parsedynamic: boolean;
@@ -430,8 +462,11 @@ declare class Cfg {
430
462
  autoResolution: boolean;
431
463
  push: {
432
464
  switch: boolean;
433
- banWords: string[];
434
- banTags: string[];
465
+ filterMode: "blacklist" | "whitelist";
466
+ filterKeywords: string[];
467
+ filterTags: string[];
468
+ whitelistKeywords: string[];
469
+ whitelistTags: string[];
435
470
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
436
471
  cron: string;
437
472
  parsedynamic: boolean;
@@ -454,8 +489,11 @@ declare class Cfg {
454
489
  autoResolution: boolean;
455
490
  push: {
456
491
  switch: boolean;
457
- banWords: string[];
458
- banTags: string[];
492
+ filterMode: "blacklist" | "whitelist";
493
+ filterKeywords: string[];
494
+ filterTags: string[];
495
+ whitelistKeywords: string[];
496
+ whitelistTags: string[];
459
497
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
460
498
  cron: string;
461
499
  parsedynamic: boolean;
@@ -479,8 +517,11 @@ declare class Cfg {
479
517
  autoResolution: boolean;
480
518
  push: {
481
519
  switch: boolean;
482
- banWords: string[];
483
- banTags: string[];
520
+ filterMode: "blacklist" | "whitelist";
521
+ filterKeywords: string[];
522
+ filterTags: string[];
523
+ whitelistKeywords: string[];
524
+ whitelistTags: string[];
484
525
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
485
526
  cron: string;
486
527
  parsedynamic: boolean;
@@ -495,8 +536,11 @@ declare class Cfg {
495
536
  autoResolution: boolean;
496
537
  push: {
497
538
  switch: boolean;
498
- banWords: string[];
499
- banTags: string[];
539
+ filterMode: "blacklist" | "whitelist";
540
+ filterKeywords: string[];
541
+ filterTags: string[];
542
+ whitelistKeywords: string[];
543
+ whitelistTags: string[];
500
544
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
501
545
  cron: string;
502
546
  parsedynamic: boolean;
@@ -510,8 +554,11 @@ declare class Cfg {
510
554
  autoResolution: boolean;
511
555
  push: {
512
556
  switch: boolean;
513
- banWords: string[];
514
- banTags: string[];
557
+ filterMode: "blacklist" | "whitelist";
558
+ filterKeywords: string[];
559
+ filterTags: string[];
560
+ whitelistKeywords: string[];
561
+ whitelistTags: string[];
515
562
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
516
563
  cron: string;
517
564
  parsedynamic: boolean;
@@ -528,8 +575,11 @@ declare class Cfg {
528
575
  autoResolution: boolean;
529
576
  push: {
530
577
  switch: boolean;
531
- banWords: string[];
532
- banTags: string[];
578
+ filterMode: "blacklist" | "whitelist";
579
+ filterKeywords: string[];
580
+ filterTags: string[];
581
+ whitelistKeywords: string[];
582
+ whitelistTags: string[];
533
583
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
534
584
  cron: string;
535
585
  parsedynamic: boolean;
@@ -545,8 +595,11 @@ declare class Cfg {
545
595
  autoResolution: boolean;
546
596
  push: {
547
597
  switch: boolean;
548
- banWords: string[];
549
- banTags: string[];
598
+ filterMode: "blacklist" | "whitelist";
599
+ filterKeywords: string[];
600
+ filterTags: string[];
601
+ whitelistKeywords: string[];
602
+ whitelistTags: string[];
550
603
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
551
604
  cron: string;
552
605
  parsedynamic: boolean;
@@ -564,8 +617,11 @@ declare class Cfg {
564
617
  autoResolution: boolean;
565
618
  push: {
566
619
  switch: boolean;
567
- banWords: string[];
568
- banTags: string[];
620
+ filterMode: "blacklist" | "whitelist";
621
+ filterKeywords: string[];
622
+ filterTags: string[];
623
+ whitelistKeywords: string[];
624
+ whitelistTags: string[];
569
625
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
570
626
  cron: string;
571
627
  parsedynamic: boolean;
@@ -588,8 +644,11 @@ declare class Cfg {
588
644
  autoResolution: boolean;
589
645
  push: {
590
646
  switch: boolean;
591
- banWords: string[];
592
- banTags: string[];
647
+ filterMode: "blacklist" | "whitelist";
648
+ filterKeywords: string[];
649
+ filterTags: string[];
650
+ whitelistKeywords: string[];
651
+ whitelistTags: string[];
593
652
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
594
653
  cron: string;
595
654
  parsedynamic: boolean;
@@ -613,8 +672,11 @@ declare class Cfg {
613
672
  autoResolution: boolean;
614
673
  push: {
615
674
  switch: boolean;
616
- banWords: string[];
617
- banTags: string[];
675
+ filterMode: "blacklist" | "whitelist";
676
+ filterKeywords: string[];
677
+ filterTags: string[];
678
+ whitelistKeywords: string[];
679
+ whitelistTags: string[];
618
680
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
619
681
  cron: string;
620
682
  parsedynamic: boolean;
@@ -630,8 +692,11 @@ declare class Cfg {
630
692
  autoResolution: boolean;
631
693
  push: {
632
694
  switch: boolean;
633
- banWords: string[];
634
- banTags: string[];
695
+ filterMode: "blacklist" | "whitelist";
696
+ filterKeywords: string[];
697
+ filterTags: string[];
698
+ whitelistKeywords: string[];
699
+ whitelistTags: string[];
635
700
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
636
701
  cron: string;
637
702
  parsedynamic: boolean;
@@ -645,8 +710,11 @@ declare class Cfg {
645
710
  autoResolution: boolean;
646
711
  push: {
647
712
  switch: boolean;
648
- banWords: string[];
649
- banTags: string[];
713
+ filterMode: "blacklist" | "whitelist";
714
+ filterKeywords: string[];
715
+ filterTags: string[];
716
+ whitelistKeywords: string[];
717
+ whitelistTags: string[];
650
718
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
651
719
  cron: string;
652
720
  parsedynamic: boolean;
@@ -661,8 +729,11 @@ declare class Cfg {
661
729
  autoResolution: boolean;
662
730
  push: {
663
731
  switch: boolean;
664
- banWords: string[];
665
- banTags: string[];
732
+ filterMode: "blacklist" | "whitelist";
733
+ filterKeywords: string[];
734
+ filterTags: string[];
735
+ whitelistKeywords: string[];
736
+ whitelistTags: string[];
666
737
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
667
738
  cron: string;
668
739
  parsedynamic: boolean;
@@ -722,8 +793,11 @@ declare class Cfg {
722
793
  autoResolution: boolean;
723
794
  push: {
724
795
  switch: boolean;
725
- banWords: string[];
726
- banTags: string[];
796
+ filterMode: "blacklist" | "whitelist";
797
+ filterKeywords: string[];
798
+ filterTags: string[];
799
+ whitelistKeywords: string[];
800
+ whitelistTags: string[];
727
801
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
728
802
  cron: string;
729
803
  parsedynamic: boolean;
@@ -737,8 +811,11 @@ declare class Cfg {
737
811
  autoResolution: boolean;
738
812
  push: {
739
813
  switch: boolean;
740
- banWords: string[];
741
- banTags: string[];
814
+ filterMode: "blacklist" | "whitelist";
815
+ filterKeywords: string[];
816
+ filterTags: string[];
817
+ whitelistKeywords: string[];
818
+ whitelistTags: string[];
742
819
  permission: "all" | "admin" | "master" | "group.owner" | "group.admin";
743
820
  cron: string;
744
821
  parsedynamic: boolean;
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { basePath, copyConfigSync, filesByExt, logger, requireFileSync, watch } from 'node-karin';
3
+ import { copyConfigSync, filesByExt, karinPathBase, logger, requireFileSync, watch } from 'node-karin';
4
4
  import YAML from 'node-karin/yaml';
5
5
  import { Version } from '../../Version.js';
6
6
  class Cfg {
@@ -9,7 +9,7 @@ class Cfg {
9
9
  /** 默认配置文件路径 */
10
10
  defCfgPath;
11
11
  constructor() {
12
- this.dirCfgPath = `${basePath}/${Version.pluginName}/config`;
12
+ this.dirCfgPath = `${karinPathBase}/${Version.pluginName}/config`;
13
13
  this.defCfgPath = `${Version.pluginPath}/config/default_config/`;
14
14
  }
15
15
  /** 初始化配置 */
@@ -35,8 +35,81 @@ class Cfg {
35
35
  }));
36
36
  }, 2000);
37
37
  this.convertType();
38
+ // 迁移配置,使用通用方法
39
+ this.migrateFilterConfig('douyin');
40
+ this.migrateFilterConfig('bilibili');
38
41
  return this;
39
42
  }
43
+ /**
44
+ * 迁移配置中的 banWords 和 banTags 到新的字段
45
+ * @param configName 配置名称,如 'douyin' 或 'bilibili'
46
+ */
47
+ migrateFilterConfig(configName) {
48
+ try {
49
+ // 检查配置文件是否存在
50
+ const configPath = `${this.dirCfgPath}/${configName}.yaml`;
51
+ if (!fs.existsSync(configPath)) {
52
+ return;
53
+ }
54
+ // 读取配置,并明确指定类型
55
+ const config = this.getYaml('config', configName);
56
+ // 检查是否需要迁移
57
+ if (!config.push) {
58
+ return;
59
+ }
60
+ let needsMigration = false;
61
+ const push = config.push;
62
+ // 检查并迁移 banWords 到 filterKeywords
63
+ if ('banWords' in push) {
64
+ if (!push.filterKeywords) {
65
+ push.filterKeywords = push.banWords;
66
+ }
67
+ else {
68
+ // 如果已经有 filterKeywords,合并两个数组
69
+ push.filterKeywords = [...new Set([...push.filterKeywords, ...push.banWords])];
70
+ }
71
+ delete push.banWords;
72
+ needsMigration = true;
73
+ }
74
+ // 检查并迁移 banTags 到 filterTags
75
+ if ('banTags' in push) {
76
+ if (!push.filterTags) {
77
+ push.filterTags = push.banTags;
78
+ }
79
+ else {
80
+ // 如果已经有 filterTags,合并两个数组
81
+ push.filterTags = [...new Set([...push.filterTags, ...push.banTags])];
82
+ }
83
+ delete push.banTags;
84
+ needsMigration = true;
85
+ }
86
+ // 确保 filterMode 字段存在,默认为黑名单模式
87
+ if (!push.filterMode) {
88
+ push.filterMode = 'blacklist';
89
+ needsMigration = true;
90
+ }
91
+ // 确保白名单字段存在
92
+ if (!push.whitelistKeywords) {
93
+ push.whitelistKeywords = [];
94
+ needsMigration = true;
95
+ }
96
+ if (!push.whitelistTags) {
97
+ push.whitelistTags = [];
98
+ needsMigration = true;
99
+ }
100
+ // 如果有变更,保存配置
101
+ if (needsMigration) {
102
+ const serviceName = configName === 'douyin' ? '抖音' : '哔哩哔哩';
103
+ logger.info(`正在迁移${serviceName}配置中的黑名单字段到新格式...`);
104
+ this.ModifyPro(configName, config);
105
+ logger.info(`${serviceName}配置迁移完成`);
106
+ }
107
+ }
108
+ catch (error) {
109
+ const serviceName = configName === 'douyin' ? '抖音' : '哔哩哔哩';
110
+ logger.error(`迁移${serviceName}配置时发生错误: ${error}`);
111
+ }
112
+ }
40
113
  /**
41
114
  * 获取默认配置和用户配置
42
115
  * @param name 配置文件名
@@ -71,7 +71,6 @@ export class Bilibilipush extends Base {
71
71
  async getdata(data) {
72
72
  let nocd_data;
73
73
  for (const dynamicId in data) {
74
- // 检查banWords,banTags
75
74
  let skip = skipDynamic(data[dynamicId].Dynamic_Data);
76
75
  let send_video = true;
77
76
  let img = [];
@@ -638,38 +637,99 @@ function extractEmojisData(data) {
638
637
  /**
639
638
  * 判断标题是否有屏蔽词或屏蔽标签
640
639
  * @param Dynamic_Data 作品详情数据
641
- * @returns
640
+ * @returns 是否应该跳过推送
642
641
  */
643
642
  const skipDynamic = (Dynamic_Data) => {
644
- for (const banWord of Config.bilibili.push.banWords) {
645
- if (Dynamic_Data.modules.module_dynamic.major?.archive?.title.includes(banWord) || Dynamic_Data.modules.module_dynamic.desc?.text?.includes(banWord)) {
646
- logger.mark(`动态:${logger.green(`https://t.bilibili.com/${Dynamic_Data.id_str}`)} 包含屏蔽词:「${logger.red(banWord)}」,跳过推送`);
647
- return true;
648
- }
649
- if (Dynamic_Data.type === "DYNAMIC_TYPE_FORWARD" && 'orig' in Dynamic_Data) {
650
- if (Dynamic_Data.orig.modules.module_dynamic.major?.archive?.title.includes(banWord) || Dynamic_Data.orig.modules.module_dynamic.desc?.text?.includes(banWord)) {
651
- logger.mark(`转发动态:${`https://t.bilibili.com/${Dynamic_Data.id_str}`} 的子动态 ${logger.green(`https://t.bilibili.com/${Dynamic_Data.orig.id_str}`)} 包含屏蔽词:「${logger.red(banWord)}」,跳过推送`);
643
+ // 获取过滤模式
644
+ const filterMode = Config.bilibili.push.filterMode || 'blacklist';
645
+ if (filterMode === 'blacklist') {
646
+ // 检查关键词
647
+ for (const filterKeywords of Config.bilibili.push.filterKeywords) {
648
+ if (Dynamic_Data.modules.module_dynamic.major?.archive?.title.includes(filterKeywords) || Dynamic_Data.modules.module_dynamic.desc?.text?.includes(filterKeywords)) {
649
+ logger.mark(`动态:${logger.green(`https://t.bilibili.com/${Dynamic_Data.id_str}`)} 包含黑名单关键词:「${logger.red(filterKeywords)}」,跳过推送`);
652
650
  return true;
653
651
  }
654
- }
655
- }
656
- if (Dynamic_Data.type === DynamicType.DRAW || Dynamic_Data.type === DynamicType.FORWARD) {
657
- for (const banTag of Config.bilibili.push.banTags) {
658
- for (const tag of Dynamic_Data.modules.module_dynamic.desc.rich_text_nodes) {
659
- if (tag.orig_text.includes(banTag)) {
660
- logger.mark(`图文动态:${logger.green(`https://t.bilibili.com/${Dynamic_Data.id_str}`)} 包含屏蔽标签:「${logger.red(banTag)}」,跳过推送`);
652
+ if (Dynamic_Data.type === 'DYNAMIC_TYPE_FORWARD' && 'orig' in Dynamic_Data) {
653
+ if (Dynamic_Data.orig.modules.module_dynamic.major?.archive?.title.includes(filterKeywords) || Dynamic_Data.orig.modules.module_dynamic.desc?.text?.includes(filterKeywords)) {
654
+ logger.mark(`转发动态:${`https://t.bilibili.com/${Dynamic_Data.id_str}`} 的子动态 ${logger.green(`https://t.bilibili.com/${Dynamic_Data.orig.id_str}`)} 包含黑名单关键词:「${logger.red(filterKeywords)}」,跳过推送`);
661
655
  return true;
662
656
  }
663
657
  }
664
- if (Dynamic_Data.type === "DYNAMIC_TYPE_FORWARD" && 'orig' in Dynamic_Data) {
665
- for (const tag of Dynamic_Data.orig.modules.module_dynamic.desc.rich_text_nodes) {
666
- if (tag.orig_text.includes(banTag)) {
667
- logger.mark(`转发动态:${`https://t.bilibili.com/${Dynamic_Data.id_str}`} 的子动态 ${logger.green(`https://t.bilibili.com/${Dynamic_Data.orig.id_str}`)} 包含屏蔽标签:「${logger.red(banTag)}」,跳过推送`);
658
+ }
659
+ // 检查标签
660
+ if (Dynamic_Data.type === DynamicType.DRAW || Dynamic_Data.type === DynamicType.FORWARD) {
661
+ for (const filterTags of Config.bilibili.push.filterTags) {
662
+ for (const tag of Dynamic_Data.modules.module_dynamic.desc.rich_text_nodes) {
663
+ if (tag.orig_text.includes(filterTags)) {
664
+ logger.mark(`图文动态:${logger.green(`https://t.bilibili.com/${Dynamic_Data.id_str}`)} 包含黑名单标签:「${logger.red(filterTags)}」,跳过推送`);
668
665
  return true;
669
666
  }
670
667
  }
668
+ if (Dynamic_Data.type === 'DYNAMIC_TYPE_FORWARD' && 'orig' in Dynamic_Data) {
669
+ for (const tag of Dynamic_Data.orig.modules.module_dynamic.desc.rich_text_nodes) {
670
+ if (tag.orig_text.includes(filterTags)) {
671
+ logger.mark(`转发动态:${`https://t.bilibili.com/${Dynamic_Data.id_str}`} 的子动态 ${logger.green(`https://t.bilibili.com/${Dynamic_Data.orig.id_str}`)} 包含黑名单标签:「${logger.red(filterTags)}」,跳过推送`);
672
+ return true;
673
+ }
674
+ }
675
+ }
676
+ }
677
+ }
678
+ // 黑名单模式下,没有匹配到任何黑名单项,不跳过
679
+ return false;
680
+ }
681
+ else if (filterMode === 'whitelist') {
682
+ // 如果白名单为空,则不过滤
683
+ const hasKeywordWhitelist = Config.bilibili.push.whitelistKeywords && Config.bilibili.push.whitelistKeywords.length > 0;
684
+ const hasTagWhitelist = Config.bilibili.push.whitelistTags && Config.bilibili.push.whitelistTags.length > 0;
685
+ // 如果没有设置任何白名单,则不过滤
686
+ if (!hasKeywordWhitelist && !hasTagWhitelist) {
687
+ return false;
688
+ }
689
+ // 检查关键词白名单
690
+ if (hasKeywordWhitelist) {
691
+ // 检查主动态标题和描述
692
+ for (const whiteKeyword of Config.bilibili.push.whitelistKeywords) {
693
+ if (Dynamic_Data.modules.module_dynamic.major?.archive?.title?.includes(whiteKeyword) ||
694
+ Dynamic_Data.modules.module_dynamic.desc?.text?.includes(whiteKeyword)) {
695
+ logger.mark(`动态:${logger.green(`https://t.bilibili.com/${Dynamic_Data.id_str}`)} 包含白名单关键词:「${logger.green(whiteKeyword)}」,允许推送`);
696
+ return false; // 匹配到白名单关键词,不跳过
697
+ }
698
+ // 检查转发的原动态
699
+ if (Dynamic_Data.type === 'DYNAMIC_TYPE_FORWARD' && 'orig' in Dynamic_Data) {
700
+ if (Dynamic_Data.orig.modules.module_dynamic.major?.archive?.title?.includes(whiteKeyword) ||
701
+ Dynamic_Data.orig.modules.module_dynamic.desc?.text?.includes(whiteKeyword)) {
702
+ logger.mark(`转发动态:${`https://t.bilibili.com/${Dynamic_Data.id_str}`} 的子动态 ${logger.green(`https://t.bilibili.com/${Dynamic_Data.orig.id_str}`)} 包含白名单关键词:「${logger.green(whiteKeyword)}」,允许推送`);
703
+ return false; // 匹配到白名单关键词,不跳过
704
+ }
705
+ }
706
+ }
707
+ }
708
+ // 检查标签白名单
709
+ if (hasTagWhitelist && (Dynamic_Data.type === DynamicType.DRAW || Dynamic_Data.type === DynamicType.FORWARD)) {
710
+ // 检查主动态标签
711
+ for (const whiteTag of Config.bilibili.push.whitelistTags) {
712
+ for (const tag of Dynamic_Data.modules.module_dynamic.desc.rich_text_nodes) {
713
+ if (tag.orig_text.includes(whiteTag)) {
714
+ logger.mark(`图文动态:${logger.green(`https://t.bilibili.com/${Dynamic_Data.id_str}`)} 包含白名单标签:「${logger.green(whiteTag)}」,允许推送`);
715
+ return false; // 匹配到白名单标签,不跳过
716
+ }
717
+ }
718
+ // 检查转发的原动态标签
719
+ if (Dynamic_Data.type === 'DYNAMIC_TYPE_FORWARD' && 'orig' in Dynamic_Data) {
720
+ for (const tag of Dynamic_Data.orig.modules.module_dynamic.desc.rich_text_nodes) {
721
+ if (tag.orig_text.includes(whiteTag)) {
722
+ logger.mark(`转发动态:${`https://t.bilibili.com/${Dynamic_Data.id_str}`} 的子动态 ${logger.green(`https://t.bilibili.com/${Dynamic_Data.orig.id_str}`)} 包含白名单标签:「${logger.green(whiteTag)}」,允许推送`);
723
+ return false; // 匹配到白名单标签,不跳过
724
+ }
725
+ }
726
+ }
671
727
  }
672
728
  }
729
+ // 白名单模式下,没有匹配到任何白名单项,跳过
730
+ logger.mark(`动态:${logger.green(`https://t.bilibili.com/${Dynamic_Data.id_str}`)} 未包含任何白名单关键词或标签,跳过推送`);
731
+ return true;
673
732
  }
733
+ // 默认不跳过
674
734
  return false;
675
735
  };
@@ -524,15 +524,66 @@ export class DouYinpush extends Base {
524
524
  /**
525
525
  * 判断标题是否有屏蔽词或屏蔽标签
526
526
  * @param Detail_Data 作品详情数据
527
- * @returns
527
+ * @returns 是否应该跳过推送
528
528
  */
529
529
  const skipDynamic = (Detail_Data) => {
530
- for (const banWord of Config.douyin.push.banWords) {
531
- if (Detail_Data.desc?.includes(banWord)) {
532
- logger.mark(`动态:${logger.green(`https://www.douyin.com/video/${Detail_Data.aweme_id}`)} 包含屏蔽词:「${logger.red(banWord)}」,跳过推送`);
533
- return true;
530
+ // 获取过滤模式
531
+ const filterMode = Config.douyin.push.filterMode || 'blacklist';
532
+ if (filterMode === 'blacklist') {
533
+ // 检查关键词
534
+ for (const filterKeywords of Config.douyin.push.filterKeywords) {
535
+ if (Detail_Data.desc?.includes(filterKeywords)) {
536
+ logger.mark(`作品:${logger.green(`https://www.douyin.com/video/${Detail_Data.aweme_id}`)} 包含黑名单关键词:「${logger.red(filterKeywords)}」,跳过推送`);
537
+ return true;
538
+ }
539
+ }
540
+ // 检查标签
541
+ for (const filterTags of Config.douyin.push.filterTags) {
542
+ if (!Detail_Data.text_extra)
543
+ return false;
544
+ for (const tag of Detail_Data.text_extra) {
545
+ if (tag.hashtag_name.includes(filterTags)) {
546
+ logger.mark(`作品:${logger.green(`https://www.douyin.com/video/${Detail_Data.aweme_id}`)} 包含黑名单标签:「${logger.red(filterTags)}」,跳过推送`);
547
+ return true;
548
+ }
549
+ }
550
+ }
551
+ // 黑名单模式下,没有匹配到任何黑名单项,不跳过
552
+ return false;
553
+ }
554
+ else if (filterMode === 'whitelist') {
555
+ // 如果白名单为空,则不过滤
556
+ const hasKeywordWhitelist = Config.douyin.push.whitelistKeywords && Config.douyin.push.whitelistKeywords.length > 0;
557
+ const hasTagWhitelist = Config.douyin.push.whitelistTags && Config.douyin.push.whitelistTags.length > 0;
558
+ // 如果没有设置任何白名单,则不过滤
559
+ if (!hasKeywordWhitelist && !hasTagWhitelist) {
560
+ return false;
534
561
  }
562
+ // 检查关键词白名单
563
+ if (hasKeywordWhitelist) {
564
+ for (const whiteKeyword of Config.douyin.push.whitelistKeywords) {
565
+ if (Detail_Data.desc?.includes(whiteKeyword)) {
566
+ logger.mark(`作品:${logger.green(`https://www.douyin.com/video/${Detail_Data.aweme_id}`)} 包含白名单关键词:「${logger.green(whiteKeyword)}」,允许推送`);
567
+ return false; // 匹配到白名单关键词,不跳过
568
+ }
569
+ }
570
+ }
571
+ // 检查标签白名单
572
+ if (hasTagWhitelist && Detail_Data.text_extra) {
573
+ for (const whiteTag of Config.douyin.push.whitelistTags) {
574
+ for (const tag of Detail_Data.text_extra) {
575
+ if (tag.hashtag_name.includes(whiteTag)) {
576
+ logger.mark(`作品:${logger.green(`https://www.douyin.com/video/${Detail_Data.aweme_id}`)} 包含白名单标签:「${logger.green(whiteTag)}」,允许推送`);
577
+ return false; // 匹配到白名单标签,不跳过
578
+ }
579
+ }
580
+ }
581
+ }
582
+ // 白名单模式下,没有匹配到任何白名单项,跳过
583
+ logger.mark(`作品:${logger.green(`https://www.douyin.com/video/${Detail_Data.aweme_id}`)} 未包含任何白名单关键词或标签,跳过推送`);
584
+ return true;
535
585
  }
586
+ // 默认不跳过
536
587
  return false;
537
588
  };
538
589
  /**
@@ -2,7 +2,7 @@
2
2
  export interface bilibiliConfig {
3
3
  /** B站解析开关,单独开关,受「总开关」影响 */
4
4
  switch: boolean;
5
- /** B站解析提示,发送提示信息:“检测到B站链接,开始解析” */
5
+ /** B站解析提示,发送提示信息:"检测到B站链接,开始解析" */
6
6
  tip: boolean;
7
7
  /** B站评论图,发送哔哩哔哩作品评论图 */
8
8
  comment: boolean;
@@ -16,10 +16,16 @@ export interface bilibiliConfig {
16
16
  push: {
17
17
  /** 推送开关,开启后需重启;使用「#设置B站推送 + 用户UID」配置推送列表 */
18
18
  switch: boolean;
19
- /** 动态中有指定关键词时,不推送 */
20
- banWords: string[];
21
- /** 动态中有指定标签时,不推送 */
22
- banTags: string[];
19
+ /** 过滤模式:blacklist为黑名单模式,whitelist为白名单模式 */
20
+ filterMode: 'blacklist' | 'whitelist';
21
+ /** 黑名单模式:作品中有指定关键词时,不推送 */
22
+ filterKeywords: string[];
23
+ /** 黑名单模式:作品中有指定标签时,不推送 */
24
+ filterTags: string[];
25
+ /** 白名单模式:作品中有指定关键词时,才推送 */
26
+ whitelistKeywords: string[];
27
+ /** 白名单模式:作品中有指定标签时,才推送 */
28
+ whitelistTags: string[];
23
29
  /** 推送权限,all为所有人,admin为管理员,master为主人,group.owner为群主,group.admin为群管理员 */
24
30
  permission: 'all' | 'admin' | 'master' | 'group.owner' | 'group.admin';
25
31
  /** 推送表达式 */
@@ -2,7 +2,7 @@
2
2
  export interface douyinConfig {
3
3
  /** 抖音解析开关,单独开关,受「总开关」影响 */
4
4
  switch: boolean;
5
- /** 抖音解析提示,发送提示信息:“检测到抖音链接,开始解析” */
5
+ /** 抖音解析提示,发送提示信息:"检测到抖音链接,开始解析" */
6
6
  tip: boolean;
7
7
  /** 抖音评论解析,发送抖音作品评论图 */
8
8
  comment: boolean;
@@ -14,10 +14,16 @@ export interface douyinConfig {
14
14
  push: {
15
15
  /** 推送开关,开启后需重启;使用「#设置抖音推送 + 抖音号」配置推送列表 */
16
16
  switch: boolean;
17
- /** 作品中有指定关键词时,不推送 */
18
- banWords: string[];
19
- /** 作品中有指定标签时,不推送 */
20
- banTags: string[];
17
+ /** 过滤模式:blacklist为黑名单模式,whitelist为白名单模式 */
18
+ filterMode: 'blacklist' | 'whitelist';
19
+ /** 黑名单模式:作品中有指定关键词时,不推送 */
20
+ filterKeywords: string[];
21
+ /** 黑名单模式:作品中有指定标签时,不推送 */
22
+ filterTags: string[];
23
+ /** 白名单模式:作品中有指定关键词时,才推送 */
24
+ whitelistKeywords: string[];
25
+ /** 白名单模式:作品中有指定标签时,才推送 */
26
+ whitelistTags: string[];
21
27
  /** 推送权限,all为所有人,admin为管理员,master为主人,group.owner为群主,group.admin为群管理员 */
22
28
  permission: 'all' | 'admin' | 'master' | 'group.owner' | 'group.admin';
23
29
  /** 推送表达式 */
package/lib/web.config.js CHANGED
@@ -188,23 +188,62 @@ export default {
188
188
  description: '推送开关,开启后需重启;使用「#设置抖音推送 + 抖音号」配置推送列表',
189
189
  defaultSelected: all.douyin.push.switch
190
190
  }),
191
- components.input.group('push:banWords', {
192
- label: '作品中有以下指定关键词时,不推送',
191
+ components.radio.group('push:filterMode', {
192
+ label: '过滤模式',
193
+ orientation: 'horizontal',
194
+ defaultValue: all.douyin.push.filterMode,
195
+ radio: [
196
+ components.radio.create('push:filterMode.radio-1', {
197
+ label: '黑名单模式',
198
+ description: '作品标题中有指定关键词或标签时,不推送',
199
+ value: 'blacklist'
200
+ }),
201
+ components.radio.create('push:filterMode.radio-2', {
202
+ label: '白名单模式',
203
+ description: '作品中有指定关键词或标签时,才推送',
204
+ value: 'whitelist'
205
+ })
206
+ ]
207
+ }),
208
+ components.input.group('push:filterKeywords', {
209
+ label: '作品中有以下指定关键词时,不推送(排除模式为黑名单时生效)',
210
+ maxRows: 2,
211
+ itemsPerRow: 4,
212
+ data: all.douyin.push.filterKeywords,
213
+ template: components.input.string('push:filterKeywords', {
214
+ placeholder: '',
215
+ label: '',
216
+ color: 'danger'
217
+ })
218
+ }),
219
+ components.input.group('push:filterTags', {
220
+ label: '作品标题中有以下指定标签时,不推送(排除模式为黑名单时生效)',
221
+ maxRows: 2,
222
+ itemsPerRow: 4,
223
+ data: all.douyin.push.filterTags,
224
+ template: components.input.string('push:filterTags', {
225
+ placeholder: '',
226
+ label: '',
227
+ color: 'danger'
228
+ })
229
+ }),
230
+ components.input.group('push:whitelistKeywords', {
231
+ label: '作品中有以下指定关键词时,才推送(排除模式为白名单时生效)',
193
232
  maxRows: 2,
194
233
  itemsPerRow: 4,
195
- data: all.douyin.push.banWords,
196
- template: components.input.string('push:banWords', {
234
+ data: all.douyin.push.whitelistKeywords,
235
+ template: components.input.string('push:whitelistKeywords', {
197
236
  placeholder: '',
198
237
  label: '',
199
238
  color: 'success'
200
239
  })
201
240
  }),
202
- components.input.group('push:banTags', {
203
- label: '作品中有指定标签时,不推送',
241
+ components.input.group('push:whitelistTags', {
242
+ label: '作品标题中有以下指定标签时,才推送(排除模式为白名单时生效)',
204
243
  maxRows: 2,
205
244
  itemsPerRow: 4,
206
- data: all.douyin.push.banTags,
207
- template: components.input.string('push:banTags', {
245
+ data: all.douyin.push.whitelistTags,
246
+ template: components.input.string('push:whitelistTags', {
208
247
  placeholder: '',
209
248
  label: '',
210
249
  color: 'success'
@@ -319,23 +358,62 @@ export default {
319
358
  description: '推送开关,开启后需重启;使用「#设置B站推送 + UID」配置推送列表',
320
359
  defaultSelected: all.bilibili.push.switch
321
360
  }),
322
- components.input.group('push:banWords', {
323
- label: '动态中有以下指定关键词时,不推送',
361
+ components.radio.group('push:filterMode', {
362
+ label: '过滤模式',
363
+ orientation: 'horizontal',
364
+ defaultValue: all.douyin.push.filterMode,
365
+ radio: [
366
+ components.radio.create('push:filterMode.radio-1', {
367
+ label: '黑名单模式',
368
+ description: '动态中有指定关键词或标签时,不推送',
369
+ value: 'blacklist'
370
+ }),
371
+ components.radio.create('push:filterMode.radio-2', {
372
+ label: '白名单模式',
373
+ description: '动态中有指定关键词或标签时,才推送',
374
+ value: 'whitelist'
375
+ })
376
+ ]
377
+ }),
378
+ components.input.group('push:filterKeywords', {
379
+ label: '动态中有以下指定关键词时,不推送(排除模式为黑名单时生效)',
380
+ maxRows: 2,
381
+ itemsPerRow: 4,
382
+ data: all.bilibili.push.filterKeywords,
383
+ template: components.input.string('push:filterKeywords', {
384
+ placeholder: '',
385
+ label: '',
386
+ color: 'danger'
387
+ })
388
+ }),
389
+ components.input.group('push:filterTags', {
390
+ label: '动态中有以下指定标签时,不推送(排除模式为黑名单时生效)',
391
+ maxRows: 2,
392
+ itemsPerRow: 4,
393
+ data: all.bilibili.push.filterTags,
394
+ template: components.input.string('push:filterTags', {
395
+ placeholder: '',
396
+ label: '',
397
+ color: 'danger'
398
+ })
399
+ }),
400
+ components.input.group('push:whitelistKeywords', {
401
+ label: '动态中有以下指定关键词时,才推送(排除模式为白名单时生效)',
324
402
  maxRows: 2,
325
403
  itemsPerRow: 4,
326
- data: all.bilibili.push.banWords,
327
- template: components.input.string('push:banWords', {
404
+ data: all.douyin.push.whitelistKeywords,
405
+ template: components.input.string('push:whitelistKeywords', {
328
406
  placeholder: '',
329
407
  label: '',
330
408
  color: 'success'
331
409
  })
332
410
  }),
333
- components.input.group('push:banTags', {
334
- label: '动态中有指定标签时,不推送',
411
+ components.input.group('push:whitelistTags', {
412
+ label: '动态中有以下指定标签时,才推送(排除模式为白名单时生效)',
335
413
  maxRows: 2,
336
414
  itemsPerRow: 4,
337
- data: all.bilibili.push.banTags,
338
- template: components.input.string('push:banTags', {
415
+ data: all.douyin.push.whitelistTags,
416
+ template: components.input.string('push:whitelistTags', {
339
417
  placeholder: '',
340
418
  label: '',
341
419
  color: 'success'
@@ -494,7 +572,6 @@ export default {
494
572
  className: 'ml-4 mr-4',
495
573
  children: [
496
574
  components.input.string('short_id', {
497
- color: 'success',
498
575
  placeholder: '',
499
576
  label: '抖音号'
500
577
  }),
@@ -505,7 +582,7 @@ export default {
505
582
  template: components.input.string('accordion-item-douyin:push:douyin:group_id', {
506
583
  placeholder: '',
507
584
  label: '',
508
- color: 'success'
585
+ color: 'default'
509
586
  })
510
587
  }),
511
588
  components.input.string('sec_uid', {
@@ -539,7 +616,6 @@ export default {
539
616
  className: 'ml-4 mr-4',
540
617
  children: [
541
618
  components.input.number('host_mid', {
542
- color: 'success',
543
619
  placeholder: '',
544
620
  label: 'UID',
545
621
  rules: undefined
@@ -551,7 +627,7 @@ export default {
551
627
  template: components.input.string('accordion-item-bilibili:push:bilibili:group_id', {
552
628
  placeholder: '',
553
629
  label: '',
554
- color: 'success'
630
+ color: 'default'
555
631
  })
556
632
  }),
557
633
  components.input.string('remark', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karin-plugin-kkk",
3
- "version": "1.1.11",
3
+ "version": "1.2.0",
4
4
  "description": "Karin 的「抖音」「B 站」视频解析/动态推送插件",
5
5
  "keywords": [
6
6
  "karin-plugin",
@@ -38,7 +38,8 @@
38
38
  "pub": "npm publish --access public",
39
39
  "pub-beta": "npm publish --tag beta",
40
40
  "sort": "npx sort-package-json",
41
- "watch": "tsx watch --include \"src/**/*.ts\" src/index.ts"
41
+ "watch": "tsx watch --include \"src/**/*.ts\" src/index.ts",
42
+ "sync": "curl -X PUT \"https://registry-direct.npmmirror.com/-/package/karin-plugin-kkk/syncs\""
42
43
  },
43
44
  "dependencies": {
44
45
  "@ikenxuan/amagi": "^4.4.8",