koishi-plugin-bilibili-notify 3.7.1 → 3.8.0-alpha.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/lib/index.cjs CHANGED
@@ -42,16 +42,16 @@ let koishi = require("koishi");
42
42
  require("@koishijs/plugin-notifier");
43
43
  let _koishijs_plugin_console = require("@koishijs/plugin-console");
44
44
  let node_path = require("node:path");
45
- require("koishi-plugin-puppeteer");
46
- let luxon = require("luxon");
47
- let node_url = require("node:url");
48
- let blive_message_listener = require("blive-message-listener");
49
45
  require("@koishijs/plugin-help");
46
+ let blive_message_listener = require("blive-message-listener");
47
+ let luxon = require("luxon");
50
48
  let _node_rs_jieba = require("@node-rs/jieba");
51
49
  let _node_rs_jieba_dict = require("@node-rs/jieba/dict");
52
50
  let qrcode = require("qrcode");
53
51
  qrcode = __toESM(qrcode);
54
52
  let cron = require("cron");
53
+ require("koishi-plugin-puppeteer");
54
+ let node_url = require("node:url");
55
55
  let md5 = require("md5");
56
56
  md5 = __toESM(md5);
57
57
  let node_crypto = require("node:crypto");
@@ -164,6 +164,87 @@ const BilibiliNotifyConfigSchema = koishi.Schema.object({
164
164
  }), koishi.Schema.object({})])])
165
165
  });
166
166
 
167
+ //#endregion
168
+ //#region src/type/index.ts
169
+ let LiveType = /* @__PURE__ */ function(LiveType$1) {
170
+ LiveType$1[LiveType$1["NotLiveBroadcast"] = 0] = "NotLiveBroadcast";
171
+ LiveType$1[LiveType$1["StartBroadcasting"] = 1] = "StartBroadcasting";
172
+ LiveType$1[LiveType$1["LiveBroadcast"] = 2] = "LiveBroadcast";
173
+ LiveType$1[LiveType$1["StopBroadcast"] = 3] = "StopBroadcast";
174
+ LiveType$1[LiveType$1["FirstLiveBroadcast"] = 4] = "FirstLiveBroadcast";
175
+ return LiveType$1;
176
+ }({});
177
+ let PushType = /* @__PURE__ */ function(PushType$1) {
178
+ PushType$1[PushType$1["Live"] = 0] = "Live";
179
+ PushType$1[PushType$1["Dynamic"] = 1] = "Dynamic";
180
+ PushType$1[PushType$1["DynamicAtAll"] = 2] = "DynamicAtAll";
181
+ PushType$1[PushType$1["StartBroadcasting"] = 3] = "StartBroadcasting";
182
+ PushType$1[PushType$1["LiveGuardBuy"] = 4] = "LiveGuardBuy";
183
+ PushType$1[PushType$1["WordCloudAndLiveSummary"] = 5] = "WordCloudAndLiveSummary";
184
+ PushType$1[PushType$1["Superchat"] = 6] = "Superchat";
185
+ PushType$1[PushType$1["UserDanmakuMsg"] = 7] = "UserDanmakuMsg";
186
+ PushType$1[PushType$1["UserActions"] = 8] = "UserActions";
187
+ return PushType$1;
188
+ }({});
189
+ const PushTypeMsg = {
190
+ [PushType.Live]: "直播推送",
191
+ [PushType.Dynamic]: "动态推送",
192
+ [PushType.DynamicAtAll]: "动态推送+At全体",
193
+ [PushType.StartBroadcasting]: "开播推送",
194
+ [PushType.LiveGuardBuy]: "上舰推送",
195
+ [PushType.WordCloudAndLiveSummary]: "弹幕词云和直播总结推送",
196
+ [PushType.Superchat]: "SC推送",
197
+ [PushType.UserDanmakuMsg]: "用户弹幕推送",
198
+ [PushType.UserActions]: "用户行为推送"
199
+ };
200
+ let BiliLoginStatus = /* @__PURE__ */ function(BiliLoginStatus$1) {
201
+ BiliLoginStatus$1[BiliLoginStatus$1["NOT_LOGIN"] = 0] = "NOT_LOGIN";
202
+ BiliLoginStatus$1[BiliLoginStatus$1["LOADING_LOGIN_INFO"] = 1] = "LOADING_LOGIN_INFO";
203
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_QR"] = 2] = "LOGIN_QR";
204
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGING_QR"] = 3] = "LOGGING_QR";
205
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGING_IN"] = 4] = "LOGGING_IN";
206
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGGED_IN"] = 5] = "LOGGED_IN";
207
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_SUCCESS"] = 6] = "LOGIN_SUCCESS";
208
+ BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_FAILED"] = 7] = "LOGIN_FAILED";
209
+ return BiliLoginStatus$1;
210
+ }({});
211
+
212
+ //#endregion
213
+ //#region src/data_server.ts
214
+ /** biome-ignore-all assist/source/organizeImports: <import> */
215
+ var BilibiliNotifyDataServer = class extends _koishijs_plugin_console.DataService {
216
+ biliData = {
217
+ status: BiliLoginStatus.LOADING_LOGIN_INFO,
218
+ msg: "正在加载登录信息..."
219
+ };
220
+ constructor(ctx) {
221
+ super(ctx, "bilibili-notify");
222
+ ctx.on("bilibili-notify/login-status-report", (data) => {
223
+ this.biliData = data;
224
+ this.refresh();
225
+ });
226
+ }
227
+ async get() {
228
+ return this.biliData;
229
+ }
230
+ };
231
+
232
+ //#endregion
233
+ //#region src/database.ts
234
+ var database_exports = /* @__PURE__ */ __exportAll({
235
+ apply: () => apply$1,
236
+ name: () => name$1
237
+ });
238
+ const name$1 = "Database";
239
+ function apply$1(ctx) {
240
+ ctx.model.extend("loginBili", {
241
+ id: "unsigned",
242
+ bili_cookies: "text",
243
+ bili_refresh_token: "text",
244
+ dynamic_group_id: "string"
245
+ });
246
+ }
247
+
167
248
  //#endregion
168
249
  //#region src/utils/index.ts
169
250
  /**
@@ -214,1694 +295,322 @@ function replaceButKeep(oldObj, newObj, keepKeys) {
214
295
  }
215
296
 
216
297
  //#endregion
217
- //#region src/generate_img.ts
218
- const DYNAMIC_TYPE_NONE = "DYNAMIC_TYPE_NONE";
219
- const DYNAMIC_TYPE_FORWARD = "DYNAMIC_TYPE_FORWARD";
220
- const DYNAMIC_TYPE_AV = "DYNAMIC_TYPE_AV";
221
- const DYNAMIC_TYPE_PGC = "DYNAMIC_TYPE_PGC";
222
- const DYNAMIC_TYPE_WORD = "DYNAMIC_TYPE_WORD";
223
- const DYNAMIC_TYPE_DRAW = "DYNAMIC_TYPE_DRAW";
224
- const DYNAMIC_TYPE_ARTICLE = "DYNAMIC_TYPE_ARTICLE";
225
- const DYNAMIC_TYPE_MUSIC = "DYNAMIC_TYPE_MUSIC";
226
- const DYNAMIC_TYPE_COMMON_SQUARE = "DYNAMIC_TYPE_COMMON_SQUARE";
227
- const DYNAMIC_TYPE_LIVE = "DYNAMIC_TYPE_LIVE";
228
- const DYNAMIC_TYPE_MEDIALIST = "DYNAMIC_TYPE_MEDIALIST";
229
- const DYNAMIC_TYPE_COURSES_SEASON = "DYNAMIC_TYPE_COURSES_SEASON";
230
- const DYNAMIC_TYPE_LIVE_RCMD = "DYNAMIC_TYPE_LIVE_RCMD";
231
- const DYNAMIC_TYPE_UGC_SEASON = "DYNAMIC_TYPE_UGC_SEASON";
232
- const ADDITIONAL_TYPE_RESERVE = "ADDITIONAL_TYPE_RESERVE";
233
- var BilibiliNotifyGenerateImg = class extends koishi.Service {
234
- static inject = ["puppeteer"];
298
+ //#region src/stop_words.ts
299
+ const stopwords = new Set([
300
+ "",
301
+ "",
302
+ "",
303
+ "",
304
+ "",
305
+ "",
306
+ "",
307
+ "",
308
+ "",
309
+ "",
310
+ "",
311
+ "",
312
+ "",
313
+ "……",
314
+ "——",
315
+ "-",
316
+ "_",
317
+ ".",
318
+ ",",
319
+ "(",
320
+ ")",
321
+ "【",
322
+ "】",
323
+ "而且",
324
+ "但是",
325
+ "如果",
326
+ "虽然",
327
+ "因为",
328
+ "所以",
329
+ "但是",
330
+ "那么",
331
+ "那么就",
332
+ "今天",
333
+ "昨天",
334
+ "后天",
335
+ "明天",
336
+ "现在",
337
+ "刚刚",
338
+ "刚才",
339
+ "一直",
340
+ "一直在",
341
+ "目前",
342
+ "以前",
343
+ "以后",
344
+ "以前的",
345
+ "the",
346
+ "and",
347
+ "to",
348
+ "of",
349
+ "a",
350
+ "is",
351
+ "in",
352
+ "on",
353
+ "for",
354
+ "with",
355
+ "this",
356
+ "that",
357
+ "you",
358
+ "觉得",
359
+ "表示",
360
+ "发现",
361
+ "认为",
362
+ "看到",
363
+ "听说",
364
+ "了解",
365
+ "知道",
366
+ "说明",
367
+ "指出",
368
+ "讨论",
369
+ "讨论一下",
370
+ "看看",
371
+ "想想",
372
+ "说说",
373
+ "讲讲",
374
+ "一个",
375
+ "一些",
376
+ "这个",
377
+ "那个",
378
+ "每个",
379
+ "什么",
380
+ "东西",
381
+ "事情",
382
+ "这些",
383
+ "那些",
384
+ "这种",
385
+ "那种",
386
+ "怎么说",
387
+ "怎么会",
388
+ "怎么可能",
389
+ "不可能",
390
+ "有点像",
391
+ "真的很",
392
+ "特别是",
393
+ "有时候",
394
+ "每次都",
395
+ "一点点",
396
+ "哪里有",
397
+ "太离谱",
398
+ "太搞笑",
399
+ "太真实",
400
+ "为了",
401
+ "因为",
402
+ "所以",
403
+ "但是",
404
+ "而且",
405
+ "然后",
406
+ "如果",
407
+ "虽然",
408
+ "然而",
409
+ "不过",
410
+ "并且",
411
+ "即使",
412
+ "由于",
413
+ "那么",
414
+ "除非",
415
+ "比如",
416
+ "比如说",
417
+ "现在",
418
+ "刚刚",
419
+ "刚才",
420
+ "以前",
421
+ "以后",
422
+ "一直",
423
+ "从来",
424
+ "目前",
425
+ "最近",
426
+ "已经",
427
+ "后来",
428
+ "之前",
429
+ "某天"
430
+ ]);
431
+ var stop_words_default = stopwords;
432
+
433
+ //#endregion
434
+ //#region src/core/live.ts
435
+ var BilibiliNotifyLive = class BilibiliNotifyLive extends koishi.Service {
436
+ static inject = [
437
+ "bilibili-notify-api",
438
+ "bilibili-notify-generate-img",
439
+ "bilibili-notify-push"
440
+ ];
441
+ liveManager;
442
+ _jieba = _node_rs_jieba.Jieba.withDict(_node_rs_jieba_dict.dict);
443
+ stopwords;
444
+ listenerRecord = {};
235
445
  constructor(ctx, config) {
236
- super(ctx, "bilibili-notify-generate-img");
446
+ super(ctx, "bilibili-notify-live");
237
447
  this.config = config;
448
+ this.logger.level = config.logLevel;
449
+ this.mergeStopWords(config.wordcloudStopWords);
238
450
  }
239
- numberToStr(num) {
240
- return num > 1e4 ? `${(num / 1e4).toFixed(1)}万` : num.toString();
451
+ start() {
452
+ this.liveManager = /* @__PURE__ */ new Map();
241
453
  }
242
- CARD_STYLES = {
243
- large: {
244
- avatarSize: "70px",
245
- upNameFont: "27px",
246
- pubTimeFont: "20px",
247
- dressUpFont: "17px",
248
- cardDetailsFont: "22px",
249
- forwardUserinfoHeight: "35px",
250
- forwardUsernameFont: "20px",
251
- forwardAvatarSize: "25px",
252
- videoCardHeight: "147px",
253
- dynTitleFont: "20px",
254
- upInfoHeight: "70px",
255
- dynamicCardRight: "67px",
256
- dynamicCardTop: "24px"
257
- },
258
- normal: {
259
- avatarSize: "50px",
260
- upNameFont: "20px",
261
- pubTimeFont: "12px",
262
- dressUpFont: "12px",
263
- cardDetailsFont: "14px",
264
- forwardUserinfoHeight: "30px",
265
- forwardUsernameFont: "15px",
266
- forwardAvatarSize: "20px",
267
- videoCardHeight: "132px",
268
- dynTitleFont: "20px",
269
- upInfoHeight: "50px",
270
- dynamicCardRight: "37px",
271
- dynamicCardTop: "5px"
454
+ stop() {
455
+ this.clearPushTimers();
456
+ this.clearListeners();
457
+ }
458
+ mergeStopWords(stopWordsStr) {
459
+ if (!stopWordsStr || stopWordsStr.trim() === "") {
460
+ this.stopwords = new Set(stop_words_default);
461
+ return;
272
462
  }
273
- };
274
- BG_COLOR = {
275
- [blive_message_listener.GuardLevel.None]: ["#4ebcec", "#F9CCDF"],
276
- [blive_message_listener.GuardLevel.Jianzhang]: ["#4ebcec", "#b494e5"],
277
- [blive_message_listener.GuardLevel.Tidu]: ["#d8a0e6", "#b494e5"],
278
- [blive_message_listener.GuardLevel.Zongdu]: ["#f2a053", "#ef5f5f"]
279
- };
280
- generateCardStyle(isLargeFont, cardColorStart, cardColorEnd, cardBasePlateBorder, cardBasePlateColor, dynamicCardColor) {
281
- const style = isLargeFont ? this.CARD_STYLES.large : this.CARD_STYLES.normal;
282
- return `
283
- * {
284
- margin: 0;
285
- padding: 0;
286
- box-sizing: border-box;
287
- font-family: "${this.config.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
288
- }
289
-
290
- html {
291
- width: 800px;
292
- height: auto;
293
- }
294
-
295
- .background {
296
- width: 100%;
297
- height: auto;
298
- padding: 15px;
299
- background: linear-gradient(to right bottom, ${cardColorStart}, ${cardColorEnd});
300
- overflow: hidden;
301
- }
302
-
303
- .base-plate {
304
- width: 100%;
305
- height: auto;
306
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
307
- padding: ${cardBasePlateBorder};
308
- border-radius: 10px;
309
- background-color: ${cardBasePlateColor};
310
- }
311
-
312
- .card {
313
- width: 100%;
314
- height: auto;
315
- border-radius: 5px;
316
- padding: 15px;
317
- overflow: hidden;
318
- background-color: #fff;
319
- }
320
-
321
- .card-body {
322
- display: flex;
323
- padding: 15px;
324
- }
325
-
326
- .card .anchor-avatar {
327
- max-width: ${style.avatarSize};
328
- max-height: ${style.avatarSize};
329
- margin-right: 20px;
330
- border-radius: 10px;
331
- }
332
-
333
- .card .card-body .card-content {
334
- width: 100%;
335
- }
336
-
337
- .card .card-body .card-content .card-header {
338
- width: 100%;
339
- display: flex;
340
- justify-content: space-between;
341
- }
342
-
343
- .card .up-info {
344
- display: flex;
345
- flex-direction: column;
346
- justify-content: space-between;
347
- height: ${style.upInfoHeight};
348
- }
349
-
350
- .card .up-info .up-name {
351
- font-size: ${style.upNameFont};
352
- }
353
-
354
- .card .pub-time {
355
- font-size: ${style.pubTimeFont};
356
- color: grey;
357
- }
358
-
359
- .card .card-header img {
360
- height: 50px;
361
- }
362
-
363
- .card .dress-up {
364
- position: relative;
365
- font-size: ${style.dressUpFont};
366
- }
367
-
368
- .card .dress-up img {
369
- max-width: 100%;
370
- max-height: 100%;
371
- }
372
-
373
- .card .dress-up span {
374
- position: absolute;
375
- color: ${dynamicCardColor};
376
- right: ${style.dynamicCardRight};
377
- top: ${style.dynamicCardTop};
378
- }
379
-
380
- .card .dyn-title {
381
- font-size: ${style.dynTitleFont};
382
- margin-bottom: 10px;
383
- }
384
-
385
- .card .card-topic {
386
- display: flex;
387
- align-items: center;
388
- margin-top: 10px;
389
- font-size: 20px;
390
- color: #008AC5;
391
- gap: 3px;
392
- }
393
-
394
- .card .card-details {
395
- margin-top: 5px;
396
- margin-bottom: 15px;
397
- font-size: ${style.cardDetailsFont};
398
- width: 90%;
399
- }
400
-
401
- .card .card-major {
402
- display: flex;
403
- flex-wrap: wrap;
404
- gap: 5px;
405
- }
406
-
407
- .card .card-major .photo-item {
408
- border-radius: 10px;
409
- overflow: hidden;
410
- width: 170px;
411
- height: 170px;
412
- object-fit: cover;
413
- }
414
-
415
- .card .card-major .single-photo-mask {
416
- position: absolute;
417
- text-align: center;
418
- width: 100%;
419
- height: 100%;
420
- top: 0;
421
- left: 0;
422
- background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, transparent 30%);
423
- }
424
-
425
- .card .card-major .single-photo-mask-text {
426
- position: absolute;
427
- color: #fff;
428
- font-size: 24px;
429
- right: 0;
430
- bottom: 66px;
431
- left: 0;
432
- text-align: center;
433
- }
434
-
435
- .card .card-major .single-photo-mask-arrow {
436
- position: absolute;
437
- width: 70px;
438
- height: 70px;
439
- bottom: 7px;
440
- left: 50%;
441
- transform: translateX(-50%);
442
- }
443
-
444
- .card .card-major .single-photo-container {
445
- position: relative;
446
- max-width: 500px;
447
- max-height: 1000px;
448
- border-radius: 10px;
449
- overflow: hidden;
450
- }
451
-
452
- .card .card-major .single-photo-item {
453
- max-width: 500px;
454
- border-radius: 10px;
455
- overflow: hidden;
456
- }
457
-
458
- .card .card-major .four-photo-item {
459
- width: 170px;
460
- height: 170px;
461
- object-fit: cover;
462
- border-radius: 10px;
463
- overflow: hidden;
464
- flex-basis: 20%;
465
- }
466
-
467
- .card .card-stat {
468
- display: flex;
469
- justify-content: space-between;
470
- width: 90%;
471
- margin-top: 15px;
472
- color: gray;
473
- font-size: 14px;
474
- }
475
-
476
- .card .card-stat .stat-item {
477
- display: flex;
478
- align-items: center;
479
- gap: 3px;
480
- }
481
-
482
- .card .card-video {
483
- display: flex;
484
- overflow: hidden;
485
- border-radius: 5px 0 0 5px;
486
- margin-top: 10px;
487
- height: ${style.videoCardHeight};
488
- }
489
-
490
- .card .video-cover {
491
- position: relative;
492
- flex: 2;
493
- overflow: hidden;
494
- }
495
-
496
- .card .video-cover img {
497
- width: 236px;
498
- }
499
-
500
- .card .cover-mask {
501
- position: absolute;
502
- width: 100%;
503
- height: 100%;
504
- top: 0;
505
- left: 0;
506
- background: linear-gradient(to top, rgba(0, 0, 0, 0.5) 0%, transparent 30%);
507
- }
508
-
509
- .card .video-cover span {
510
- position: absolute;
511
- color: #fff;
512
- font-size: 14px;
513
- right: 10px;
514
- bottom: 8px;
515
- }
516
-
517
- .card .video-info {
518
- display: flex;
519
- justify-content: space-between;
520
- flex-direction: column;
521
- flex: 3;
522
- border: #e5e7e9 1px solid;
523
- border-left: none;
524
- border-radius: 0 5px 5px 0;
525
- padding: 12px 16px 10px;
526
- background-color: #fff;
527
- }
528
-
529
- .card .video-info-header .video-title {
530
- font-size: 16px;
531
- }
532
-
533
- .card .video-info-header .video-introduction {
534
- margin-top: 5px;
535
- font-size: 12px;
536
- color: #AAA;
537
- display: -webkit-box;
538
- -webkit-box-orient: vertical;
539
- -webkit-line-clamp: 2;
540
- overflow: hidden;
541
- }
542
-
543
- .card .video-stat {
544
- font-size: 12px;
545
- color: #AAA;
546
- display: flex;
547
- gap: 35px
548
- }
549
-
550
- .card .video-stat .video-stat-item {
551
- display: flex;
552
- align-items: center;
553
- gap: 3px;
554
- }
555
-
556
- .card .card-forward {
557
- border-radius: 5px;
558
- padding: 12px 10px 14px 10px;
559
- background-color: #F6F7F8;
560
- }
561
-
562
- .card-forward .forward-userinfo {
563
- display: flex;
564
- align-items: center;
565
- gap: 5px;
566
- height: ${style.forwardUserinfoHeight};
567
- }
568
-
569
- .forward-userinfo img {
570
- width: ${style.forwardAvatarSize};
571
- height: ${style.forwardAvatarSize};
572
- border-radius: 50%;
573
- }
574
-
575
- .forward-userinfo span {
576
- color: #61666D;
577
- font-size: ${style.forwardUsernameFont};
578
- }
579
-
580
- .card .card-reserve {
581
- display: flex;
582
- justify-content: space-between;
583
- align-items: center;
584
- padding: 10px 20px 10px 20px;
585
- margin-top: 10px;
586
- border-radius: 10px;
587
- background-color: #F6F7F8;
588
- }
589
-
590
- .card-reserve .reserve-title {
591
- font-size: 14px;
592
- color: #18191C;
593
- }
594
-
595
- .card-reserve .reserve-desc {
596
- margin-top: 7px;
597
- font-size: 12px;
598
- color: #9499A0;
599
- }
600
-
601
- .reserve-info .reserve-time {
602
- margin-right: 7px;
603
- }
604
-
605
- .card-reserve .reserve-prize {
606
- display: flex;
607
- align-items: center;
608
- margin-top: 3px;
609
- gap: 3px;
610
- color: #00AEEC;
611
- }
612
-
613
- .card .card-reserve .reserve-button button {
614
- border: none;
615
- height: 30px;
616
- width: 72px;
617
- font-size: 13px;
618
- border-radius: 7px;
619
- }
620
-
621
- .card .card-reserve .reserve-button .reserve-button-end {
622
- display: flex;
623
- align-items: center;
624
- justify-content: center;
625
- color: #9499A0;
626
- background-color: #E3E5E7;
627
- }
628
-
629
- .card .card-reserve .reserve-button .reserve-button-ing {
630
- display: flex;
631
- align-items: center;
632
- justify-content: center;
633
- color: #FFF;
634
- background-color: #00A0D8;
635
- }
636
- `;
637
- }
638
- async imgHandler(html) {
639
- const htmlPath = `file://${__dirname.replaceAll("\\", "/")}/page/0.html`;
640
- const page = await this.ctx.puppeteer.page();
641
- await page.goto(htmlPath);
642
- await page.setContent(html, { waitUntil: "networkidle0" });
643
- const elementHandle = await page.$("html");
644
- const boundingBox = await elementHandle.boundingBox();
645
- const buffer = await page.screenshot({
646
- type: "jpeg",
647
- clip: {
648
- x: boundingBox.x,
649
- y: boundingBox.y,
650
- width: boundingBox.width,
651
- height: boundingBox.height
652
- }
653
- });
654
- await elementHandle.dispose();
655
- await page.close();
656
- return buffer;
657
- }
658
- async generateLiveImg(data, username, userface, liveData, liveStatus, { cardColorStart = this.config.cardColorStart, cardColorEnd = this.config.cardColorEnd, cardBasePlateColor = this.config.cardBasePlateColor, cardBasePlateBorder = this.config.cardBasePlateBorder } = {}) {
659
- const [titleStatus, liveTime, cover] = await this.getLiveStatus(data.live_time, liveStatus);
660
- const html = `
661
- <!DOCTYPE html>
662
- <html>
663
- <head>
664
- <title>直播通知</title>
665
- <style>
666
- * {
667
- margin: 0;
668
- padding: 0;
669
- box-sizing: border-box;
670
- font-family: "${this.config.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
671
- }
672
-
673
- html {
674
- width: 800px;
675
- height: auto;
676
- }
677
-
678
- .background {
679
- width: 100%;
680
- height: auto;
681
- padding: 15px;
682
- background: linear-gradient(to right bottom, ${cardColorStart}, ${cardColorEnd});
683
- overflow: hidden;
684
- }
685
-
686
- .base-plate {
687
- width: 100%;
688
- height: auto;
689
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
690
- padding: ${cardBasePlateBorder};
691
- border-radius: 10px;
692
- background-color: ${cardBasePlateColor};
693
- }
694
-
695
- .card {
696
- width: 100%;
697
- height: auto;
698
- border-radius: 5px;
699
- padding: 15px;
700
- overflow: hidden;
701
- background-color: #fff;
702
- }
703
-
704
- .card img {
705
- border-radius: 5px 5px 0 0;
706
- max-width: 100%;
707
- /* 设置最大宽度为容器宽度的100% */
708
- max-height: 80%;
709
- /* 设置最大高度为容器高度的90% */
710
- }
711
-
712
- .card-header {
713
- display: flex;
714
- justify-content: space-between;
715
- align-items: center;
716
- margin-top: 5px;
717
- margin-bottom: 10px;
718
- }
719
-
720
- .card-title {
721
- line-height: 50px;
722
- }
723
-
724
- .card-body {
725
- padding: 2px 16px;
726
- margin-bottom: 10px;
727
- }
728
-
729
- .live-broadcast-info {
730
- display: flex;
731
- align-items: center;
732
- margin-bottom: 10px;
733
- }
734
-
735
- .anchor-avatar {
736
- width: 50px;
737
- /* 主播头像大小 */
738
- height: auto;
739
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
740
- }
741
-
742
- .broadcast-message {
743
- display: inline-block;
744
- margin-left: 10px;
745
- font-size: 20px;
746
- color: #333;
747
- }
748
-
749
- .card-text {
750
- color: grey;
751
- font-size: 20px;
752
- }
753
-
754
- .card-link {
755
- display: flex;
756
- justify-content: space-between;
757
- text-decoration: none;
758
- font-size: 20px;
759
- margin-top: 10px;
760
- margin-bottom: 10px;
761
- }
762
- </style>
763
- </head>
764
- <body>
765
- <div class="background">
766
- <div ${this.config.removeBorder ? "" : "class=\"base-plate\""}>
767
- <div class="card">
768
- <img src="${cover ? data.user_cover : data.keyframe}"
769
- alt="封面">
770
- <div class="card-body">
771
- <div class="card-header">
772
- <h1 class="card-title">${data.title}</h1>
773
- <div class="live-broadcast-info">
774
- <!-- 主播头像 -->
775
- <img style="border-radius: 10px; margin-left: 10px" class="anchor-avatar"
776
- src="${userface}" alt="主播头像">
777
- <span class="broadcast-message">${username}${titleStatus}</span>
778
- </div>
779
- </div>
780
- ${this.config.hideDesc ? "" : `<p class="card-text">${data.description ? data.description : "这个主播很懒,什么简介都没写"}</p>`}
781
- <p class="card-link">
782
- <span>${liveStatus === 3 ? `本场直播点赞数:${this.numberToStr(+liveData.likedNum)}` : `人气:${this.numberToStr(data.online)}`}</span>
783
- <span>分区名称:${data.area_name}</span>
784
- </p>
785
- <p class="card-link">
786
- <span>${liveTime}</span>
787
- ${this.config.followerDisplay ? `
788
- <span>
789
- ${liveStatus === 1 ? `当前粉丝数:${liveData.fansNum || "暂未获取到"}` : liveStatus === 2 ? `${liveData.watchedNum !== "API" ? `累计观看人数:${liveData.watchedNum}` : ""}` : liveStatus === 3 ? `粉丝数变化:${liveData.fansChanged}` : ""}
790
- </span>` : ""}
791
- </p>
792
- </div>
793
- </div>
794
- </div>
795
- </div>
796
- </body>
797
- </html>
798
- `;
799
- return await withRetry(() => this.imgHandler(html)).catch((e) => {
800
- throw new Error(`生成图片失败!错误: ${e.toString()}`);
801
- });
802
- }
803
- async generateBoardingImg(captainImgUrl, { guardLevel, uname, face, isAdmin }, { masterAvatarUrl, masterName }) {
804
- const bgColor = this.BG_COLOR[guardLevel];
805
- const desc = {
806
- [blive_message_listener.GuardLevel.Jianzhang]: () => {
807
- return `"${uname}号"加入<br/>"${masterName}"大航海舰队!`;
808
- },
809
- [blive_message_listener.GuardLevel.Tidu]: () => {
810
- return `"${uname}"就任<br/>"${masterName}"大航海舰队提督!`;
811
- },
812
- [blive_message_listener.GuardLevel.Zongdu]: () => {
813
- return `"${uname}"上任<br/>"${masterName}"大航海舰队总督!`;
814
- }
815
- };
816
- const html = `
817
- <!DOCTYPE html>
818
- <html>
819
-
820
- <head>
821
- <title>上舰通知</title>
822
- <style>
823
- * {
824
- margin: 0;
825
- padding: 0;
826
- box-sizing: border-box;
827
- font-family: "${this.config.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
828
- }
829
-
830
- html {
831
- width: 430px;
832
- height: auto;
833
- }
834
-
835
- .bg {
836
- display: flex;
837
- justify-content: center;
838
- align-items: center;
839
- width: 430px;
840
- height: 220px;
841
- background: linear-gradient(to right bottom, ${bgColor[0]}, ${bgColor[1]});
842
- }
843
-
844
- .baseplate {
845
- display: flex;
846
- justify-content: space-between;
847
- align-items: center;
848
- border-radius: 10px;
849
- width: 410px;
850
- height: 200px;
851
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
852
- background-color: rgba(255, 255, 255, 0.65);
853
- backdrop-filter: blur(10px);
854
- }
855
-
856
- .info {
857
- flex: 1;
858
- height: 100%;
859
- display: flex;
860
- flex-direction: column;
861
- justify-content: space-between;
862
- padding: 10px 0 10px 10px;
863
- }
864
-
865
- .user {
866
- display: flex;
867
- gap: 10px;
868
- }
869
-
870
- .avatar {
871
- height: 90px;
872
- width: 90px;
873
- border-radius: 50%;
874
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
875
- }
876
-
877
- .avatar img {
878
- width: 100%;
879
- height: 100%;
880
- border-radius: 50%;
881
- border: 3px solid white;
882
- }
883
-
884
- .user-info {
885
- display: flex;
886
- flex-direction: column;
887
- align-items: flex-start;
888
- gap: 7px;
889
- margin-top: 10px;
890
- }
891
-
892
- .name-badge {
893
- display: flex;
894
- align-items: center;
895
- height: 30px;
896
- background-color: ${bgColor[0]};
897
- border-radius: 25px;
898
- color: white;
899
- padding: 0 10px;
900
- border: solid 2px white;
901
- overflow: hidden;
902
- }
903
-
904
- .name-badge span {
905
- max-width: 100px;
906
- white-space: nowrap;
907
- text-overflow: ellipsis;
908
- overflow: hidden;
909
- font-weight: bold;
910
- font-size: 12px;
911
- }
912
-
913
- .accompany {
914
- display: flex;
915
- gap: 5px;
916
- align-items: center;
917
- height: 25px;
918
- background-color: ${bgColor[0]};
919
- border-radius: 25px;
920
- border: solid 2px white;
921
- overflow: hidden;
922
- }
923
-
924
- .master-avatar {
925
- width: 25px;
926
- height: 25px;
927
- border-radius: 50%;
928
- background: url("${masterAvatarUrl}") no-repeat center;
929
- background-size: cover;
930
- }
931
-
932
- .accompany span {
933
- max-width: 85px;
934
- white-space: nowrap;
935
- text-overflow: ellipsis;
936
- overflow: hidden;
937
- color: white;
938
- font-size: 10px;
939
- font-weight: bold;
940
- margin-right: 5px;
941
- }
942
-
943
- .desc {
944
- margin-bottom: 10px;
945
- font-size: 16px;
946
- font-weight: bold;
947
- font-style: italic;
948
- color: #333;
949
- }
950
-
951
- .captain {
952
- width: 175px;
953
- height: 175px;
954
- background: url("${captainImgUrl}") no-repeat center;
955
- background-size: cover;
956
- }
957
- </style>
958
- </head>
959
-
960
- <body>
961
- <div class="bg">
962
- <div class="baseplate">
963
- <div class="info">
964
- <div class="user">
965
- <div class="avatar">
966
- <img src="${face}" alt="用户头像">
967
- </div>
968
- <div class="user-info">
969
- <div class="name-badge">
970
- <span>${uname}</span>
971
- </div>
972
- <div class="accompany">
973
- <div class="master-avatar"></div><span>${isAdmin ? "房管" : masterName}</span>
974
- </div>
975
- </div>
976
- </div>
977
- <div class="desc">
978
- ${desc[guardLevel]()}
979
- </div>
980
- </div>
981
- <div class="captain"></div>
982
- </div>
983
- </div>
984
- </body>
985
-
986
- </html>
987
- `;
988
- return await withRetry(() => this.imgHandler(html)).catch((e) => {
989
- throw new Error(`生成图片失败!错误: ${e.toString()}`);
990
- });
991
- }
992
- richTextParser(rt, title) {
993
- const richText = rt.reduce((accumulator, currentValue) => {
994
- if (currentValue.emoji) return `${accumulator}<img style="width:17px; height:17px;" src="${currentValue.emoji.icon_url}"/>`;
995
- return accumulator + currentValue.text;
996
- }, "");
997
- if (this.config.filter.enable) {
998
- if (this.config.filter.regex) {
999
- if (new RegExp(this.config.filter.regex).test(richText)) throw new Error("出现关键词,屏蔽该动态");
1000
- }
1001
- if (this.config.filter.keywords.length !== 0 && this.config.filter.keywords.some((keyword) => richText.includes(keyword))) throw new Error("出现关键词,屏蔽该动态");
1002
- }
1003
- const text = richText.replace(/\n/g, "<br>");
1004
- return `
1005
- <div class="card-details">
1006
- ${title ? `<h1 class="dyn-title">${title}</h1>` : ""}
1007
- ${text}
1008
- </div>
1009
- `;
1010
- }
1011
- async generateDynamicImg(data, { cardColorStart = this.config.cardColorStart, cardColorEnd = this.config.cardColorEnd, cardBasePlateColor = this.config.cardBasePlateColor, cardBasePlateBorder = this.config.cardBasePlateBorder } = {}) {
1012
- const module_author = data.modules.module_author;
1013
- const avatarUrl = module_author.face;
1014
- const upName = module_author.name;
1015
- let pubTime = this.unixTimestampToString(module_author.pub_ts);
1016
- let dynamicCardUrl;
1017
- let dynamicCardId;
1018
- let dynamicCardColor;
1019
- if (module_author.decorate) {
1020
- dynamicCardUrl = module_author.decorate.card_url;
1021
- dynamicCardId = module_author.decorate.fan.num_str;
1022
- dynamicCardColor = module_author.decorate.fan.color;
1023
- }
1024
- const module_stat = data.modules.module_stat;
1025
- const comment = module_stat.comment.count;
1026
- const forward = module_stat.forward.count;
1027
- const like = module_stat.like.count;
1028
- const topic = data.modules.module_dynamic.topic ? data.modules.module_dynamic.topic.name : "";
1029
- const getDynamicMajor = async (dynamic, forward$1) => {
1030
- let main$1 = "";
1031
- let forwardInfo;
1032
- const basicDynamic = () => {
1033
- const module_dynamic = dynamic.modules.module_dynamic;
1034
- if (module_dynamic?.desc?.rich_text_nodes) {
1035
- const content = this.richTextParser(module_dynamic.desc.rich_text_nodes);
1036
- main$1 += content;
1037
- }
1038
- if (module_dynamic?.major?.opus?.summary?.rich_text_nodes) {
1039
- const content = this.richTextParser(module_dynamic.major.opus.summary.rich_text_nodes, module_dynamic.major.opus.title);
1040
- main$1 += content;
1041
- }
1042
- let major = "";
1043
- const arrowImg = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "img/arrow.png"));
1044
- if (module_dynamic?.major?.opus?.pics) {
1045
- if (module_dynamic.major.opus.pics.length === 1) if (module_dynamic.major.opus.pics[0].height > 3e3) major += `
1046
- <div class="single-photo-container">
1047
- <img class="single-photo-item" src="${module_dynamic.major.opus.pics[0].url}"/>
1048
- <div class="single-photo-mask">
1049
- <span class="single-photo-mask-text">点击链接浏览全部</span>
1050
- </div>
1051
- <img class="single-photo-mask-arrow" src="${arrowImg}"/>
1052
- </div>
1053
- `;
1054
- else major += `
1055
- <div class="single-photo-container">
1056
- <img class="single-photo-item" src="${module_dynamic.major.opus.pics[0].url}"/>
1057
- </div>
1058
- `;
1059
- else if (module_dynamic.major.opus.pics.length === 4) major += module_dynamic.major.opus.pics.reduce((acc, cV) => {
1060
- return `${acc}<img class="four-photo-item" src="${cV.url}"/>`;
1061
- }, "");
1062
- else major += module_dynamic.major.opus.pics.reduce((acc, cV) => {
1063
- return `${acc}<img class="photo-item" src="${cV.url}"/>`;
1064
- }, "");
1065
- main$1 += `
1066
- <div class="card-major">
1067
- ${major}
1068
- </div>
1069
- `;
1070
- }
1071
- };
1072
- switch (dynamic.type) {
1073
- case DYNAMIC_TYPE_WORD:
1074
- case DYNAMIC_TYPE_DRAW:
1075
- case DYNAMIC_TYPE_FORWARD:
1076
- basicDynamic();
1077
- if (dynamic.type === DYNAMIC_TYPE_FORWARD) {
1078
- if (this.config.filter.enable && this.config.filter.forward) throw new Error("已屏蔽转发动态");
1079
- const forward_module_author = dynamic.orig.modules.module_author;
1080
- const forwardUserAvatarUrl = forward_module_author.face;
1081
- const forwardUserName = forward_module_author.name;
1082
- const [forwardMain, forwardInfo$1] = await getDynamicMajor(dynamic.orig, true);
1083
- main$1 += `
1084
- <div class="card-forward">
1085
- <div class="forward-userinfo">
1086
- <img class="forward-avatar" src="${forwardUserAvatarUrl}" alt="avatar">
1087
- <span class="forward-username">${forwardUserName} ${forwardInfo$1 ? forwardInfo$1 : ""}</span>
1088
- </div>
1089
- <div class="forward-main">
1090
- ${forwardMain}
1091
- </div>
1092
- </div>
1093
- `;
1094
- }
1095
- if (dynamic.modules.module_dynamic.additional) {
1096
- const additional = dynamic.modules.module_dynamic.additional;
1097
- switch (additional.type) {
1098
- case ADDITIONAL_TYPE_RESERVE: {
1099
- const reserve = additional.reserve;
1100
- let button;
1101
- if (reserve.button.uncheck.text === "已结束") button = `
1102
- <button class="reserve-button-end">
1103
- <span>${reserve.button.uncheck.text}</span>
1104
- </button>
1105
- `;
1106
- else button = `
1107
- <button class="reserve-button-ing">
1108
- <svg class="bili-dyn-card-reserve__action__icon" style="width: 16px; height: 16px;"
1109
- xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
1110
- viewBox="0 0 16 16" width="16" height="16">
1111
- <path
1112
- d="M3.0000133333333334 6.999199999999999C3.0000133333333334 4.23776 5.2385866666666665 1.9991866666666667 8 1.9991866666666667C10.761433333333333 1.9991866666666667 13 4.23776 13 6.999199999999999L13 9.860933333333332C13 9.923533333333333 13.024899999999999 9.983633333333334 13.069199999999999 10.027933333333333L13.588366666666666 10.5471C14.389533333333333 11.348299999999998 13.914133333333334 12.734533333333333 12.754199999999999 12.8183C11.535999999999998 12.906233333333333 9.818933333333334 12.999199999999998 8 12.999199999999998C6.181073333333334 12.999199999999998 4.464026666666666 12.906233333333333 3.2458266666666664 12.8183C2.0859066666666664 12.734533333333333 1.61046 11.348299999999998 2.4116466666666665 10.547133333333333L2.93084 10.027933333333333C2.975133333333333 9.983633333333334 3.0000133333333334 9.923533333333333 3.0000133333333334 9.860933333333332L3.0000133333333334 6.999199999999999zM8 2.9991866666666667C5.790873333333334 2.9991866666666667 4.000013333333333 4.790046666666666 4.000013333333333 6.999199999999999L4.000013333333333 9.860933333333332C4.000013333333333 10.1888 3.8697733333333333 10.5032 3.6379466666666667 10.735033333333334L3.1187466666666666 11.254233333333334C2.911966666666667 11.461 3.0317600000000002 11.800199999999998 3.317833333333333 11.820899999999998C4.5211266666666665 11.907766666666667 6.212726666666666 11.999199999999998 8 11.999199999999998C9.787266666666666 11.999199999999998 11.4789 11.907733333333333 12.682199999999998 11.820899999999998C12.968233333333332 11.800199999999998 13.088033333333332 11.461 12.881266666666665 11.254233333333334L12.362066666666665 10.735033333333334C12.130233333333333 10.5032 12 10.1888 12 9.860933333333332L12 6.999199999999999C12 4.790046666666666 10.209166666666667 2.9991866666666667 8 2.9991866666666667z"
1113
- fill="currentColor"></path>
1114
- <path
1115
- d="M8.720066666666666 2.0260466666666668C8.720066666666666 2.42372 8.397666666666666 2.746093333333333 8 2.746093333333333C7.602333333333332 2.746093333333333 7.279933333333333 2.42372 7.279933333333333 2.0260466666666668C7.279933333333333 1.6283666666666667 7.602333333333332 1.3059866666666666 8 1.3059866666666666C8.397666666666666 1.3059866666666666 8.720066666666666 1.6283666666666667 8.720066666666666 2.0260466666666668z"
1116
- fill="currentColor"></path>
1117
- <path
1118
- d="M6.791266666666666 12.499199999999998C6.791266666666666 13.173966666666667 7.335266666666667 13.715866666666665 8 13.715866666666665C8.664766666666665 13.715866666666665 9.208733333333333 13.173966666666667 9.208733333333333 12.499199999999998L10.208733333333333 12.499199999999998C10.208733333333333 13.720566666666667 9.2227 14.715866666666665 8 14.715866666666665C6.777346666666666 14.715866666666665 5.791273333333333 13.720566666666667 5.791273333333333 12.499199999999998L6.791266666666666 12.499199999999998z"
1119
- fill="currentColor"></path>
1120
- </svg>
1121
- <span>${reserve.button.uncheck.text}</span>
1122
- </button>
1123
- `;
1124
- main$1 += `
1125
- <div class="card-reserve">
1126
- <div class="reserve-main">
1127
- <div class="reserve-title">
1128
- ${reserve.title}
1129
- </div>
1130
- <div class="reserve-desc">
1131
- <div class="reserve-info">
1132
- <span class="reserve-time">${reserve.desc1.text}</span>
1133
- <span class="reserve-num">${reserve.desc2.text}</span>
1134
- </div>
1135
- ${reserve.desc3 ? `<div class="reserve-prize">
1136
- <svg class="bili-dyn-card-reserve__lottery__icon"
1137
- style="width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg"
1138
- xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" width="16"
1139
- height="16">
1140
- <path
1141
- d="M2.99998 7.785666666666666C3.2761266666666664 7.785666666666666 3.49998 8.0095 3.49998 8.285666666666666L3.49998 12.285666666666666C3.49998 12.719566666666667 3.8517599999999996 13.071333333333332 4.285693333333333 13.071333333333332L11.714266666666667 13.071333333333332C12.1482 13.071333333333332 12.5 12.719566666666667 12.5 12.285666666666666L12.5 8.285666666666666C12.5 8.0095 12.723833333333333 7.785666666666666 13 7.785666666666666C13.276133333333334 7.785666666666666 13.5 8.0095 13.5 8.285666666666666L13.5 12.285666666666666C13.5 13.271866666666668 12.7005 14.071333333333332 11.714266666666667 14.071333333333332L4.285693333333333 14.071333333333332C3.2994733333333333 14.071333333333332 2.49998 13.271866666666668 2.49998 12.285666666666666L2.49998 8.285666666666666C2.49998 8.0095 2.7238399999999996 7.785666666666666 2.99998 7.785666666666666z"
1142
- fill="currentColor"></path>
1143
- <path
1144
- d="M1.9285533333333333 5.857139999999999C1.9285533333333333 5.107613333333333 2.5361666666666665 4.5 3.285693333333333 4.5L12.714266666666667 4.5C13.463799999999999 4.5 14.071399999999999 5.107613333333333 14.071399999999999 5.857139999999999L14.071399999999999 7.134066666666667C14.071399999999999 7.793799999999999 13.590066666666667 8.373766666666667 12.905000000000001 8.4432C12.058933333333332 8.528966666666665 10.470166666666666 8.642866666666666 8 8.642866666666666C5.529819999999999 8.642866666666666 3.9410399999999997 8.528966666666665 3.09498 8.4432C2.4099066666666666 8.373766666666667 1.9285533333333333 7.793799999999999 1.9285533333333333 7.134066666666667L1.9285533333333333 5.857139999999999zM3.285693333333333 5.5C3.088453333333333 5.5 2.9285533333333333 5.6599 2.9285533333333333 5.857139999999999L2.9285533333333333 7.134066666666667C2.9285533333333333 7.3082 3.0432666666666663 7.432833333333333 3.1958066666666665 7.4483C4.00544 7.530366666666667 5.560420000000001 7.6428666666666665 8 7.6428666666666665C10.439566666666666 7.6428666666666665 11.994533333333333 7.530366666666667 12.804133333333333 7.4483C12.9567 7.432833333333333 13.071399999999999 7.3082 13.071399999999999 7.134066666666667L13.071399999999999 5.857139999999999C13.071399999999999 5.6599 12.911499999999998 5.5 12.714266666666667 5.5L3.285693333333333 5.5z"
1145
- fill="currentColor"></path>
1146
- <path
1147
- d="M4.357126666666666 3.5714733333333335C4.357126666666666 2.506353333333333 5.220573333333333 1.6429066666666667 6.285693333333333 1.6429066666666667C7.350833333333332 1.6429066666666667 8.214266666666667 2.506353333333333 8.214266666666667 3.5714733333333335L8.214266666666667 5.500046666666666L6.285693333333333 5.500046666666666C5.220573333333333 5.500046666666666 4.357126666666666 4.636593333333333 4.357126666666666 3.5714733333333335zM6.285693333333333 2.6429066666666667C5.77286 2.6429066666666667 5.357126666666667 3.0586399999999996 5.357126666666667 3.5714733333333335C5.357126666666667 4.084313333333333 5.77286 4.500046666666666 6.285693333333333 4.500046666666666L7.214266666666667 4.500046666666666L7.214266666666667 3.5714733333333335C7.214266666666667 3.0586399999999996 6.798533333333333 2.6429066666666667 6.285693333333333 2.6429066666666667z"
1148
- fill="currentColor"></path>
1149
- <path
1150
- d="M7.785666666666666 3.5714733333333335C7.785666666666666 2.506353333333333 8.649133333333332 1.6429066666666667 9.714266666666667 1.6429066666666667C10.779399999999999 1.6429066666666667 11.642866666666666 2.506353333333333 11.642866666666666 3.5714733333333335C11.642866666666666 4.636593333333333 10.779399999999999 5.500046666666666 9.714266666666667 5.500046666666666L7.785666666666666 5.500046666666666L7.785666666666666 3.5714733333333335zM9.714266666666667 2.6429066666666667C9.201433333333332 2.6429066666666667 8.785666666666666 3.0586399999999996 8.785666666666666 3.5714733333333335L8.785666666666666 4.500046666666666L9.714266666666667 4.500046666666666C10.2271 4.500046666666666 10.642866666666666 4.084313333333333 10.642866666666666 3.5714733333333335C10.642866666666666 3.0586399999999996 10.2271 2.6429066666666667 9.714266666666667 2.6429066666666667z"
1151
- fill="currentColor"></path>
1152
- <path
1153
- d="M8 3.7856466666666666C8.276133333333332 3.7856466666666666 8.5 4.009499999999999 8.5 4.285646666666667L8.5 13.142800000000001C8.5 13.418933333333332 8.276133333333332 13.642800000000001 8 13.642800000000001C7.723833333333333 13.642800000000001 7.5 13.418933333333332 7.5 13.142800000000001L7.5 4.285646666666667C7.5 4.009499999999999 7.723833333333333 3.7856466666666666 8 3.7856466666666666z"
1154
- fill="currentColor"></path>
1155
- </svg>
1156
- <span>${reserve.desc3.text}</span>
1157
- <svg style="width: 12px; height: 12px;" xmlns="http://www.w3.org/2000/svg"
1158
- xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 12 12" width="12"
1159
- height="12">
1160
- <path
1161
- d="M4.359835 1.609835C4.21339 1.756285 4.21339 1.99372 4.359835 2.140165L8.0429 5.823225C8.140525 5.920875 8.140525 6.079125 8.0429 6.176775L4.359835 9.859825C4.21339 10.006275 4.21339 10.243725 4.359835 10.390175C4.506285 10.5366 4.743725 10.5366 4.89017 10.390175L8.573225 6.7071C8.96375 6.316575 8.96375 5.683425 8.573225 5.2929L4.89017 1.609835C4.743725 1.46339 4.506285 1.46339 4.359835 1.609835z"
1162
- fill="currentColor"></path>
1163
- </svg>
1164
- </div>` : ""}
1165
- </div>
1166
- </div>
1167
- <div class="reserve-button">
1168
- ${button}
1169
- </div>
1170
- </div>
1171
- `;
1172
- }
1173
- }
1174
- }
1175
- break;
1176
- case DYNAMIC_TYPE_AV: {
1177
- basicDynamic();
1178
- const archive = dynamic.modules.module_dynamic.major.archive;
1179
- if (archive.badge.text === "投稿视频") if (forward$1) forwardInfo = "投稿了视频";
1180
- else pubTime = `${pubTime} · 投稿了视频`;
1181
- main$1 += `
1182
- <div class="card-video">
1183
- <div class="video-cover">
1184
- <img src="${archive.cover}"
1185
- alt="">
1186
- <div class="cover-mask"></div>
1187
- <span>${archive.duration_text}</span>
1188
- </div>
1189
- <div class="video-info">
1190
- <div class="video-info-header">
1191
- <div class="video-title">
1192
- ${archive.title}
1193
- </div>
1194
- <div class="video-introduction">
1195
- ${archive.desc}
1196
- </div>
1197
- </div>
1198
- <div class="video-stat">
1199
- <div class="video-stat-item">
1200
- <svg style="width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg"
1201
- xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" width="16"
1202
- height="16">
1203
- <path
1204
- d="M8 3.3320333333333334C6.321186666666667 3.3320333333333334 4.855333333333333 3.4174399999999996 3.820593333333333 3.5013466666666666C3.1014733333333333 3.5596599999999996 2.5440733333333334 4.109013333333333 2.48 4.821693333333333C2.4040466666666664 5.666533333333334 2.333333333333333 6.780666666666666 2.333333333333333 7.998666666666666C2.333333333333333 9.216733333333334 2.4040466666666664 10.330866666666665 2.48 11.175699999999999C2.5440733333333334 11.888366666666666 3.1014733333333333 12.437733333333334 3.820593333333333 12.496066666666666C4.855333333333333 12.579933333333333 6.321186666666667 12.665333333333333 8 12.665333333333333C9.678999999999998 12.665333333333333 11.144933333333334 12.579933333333333 12.179733333333333 12.496033333333333C12.898733333333332 12.4377 13.456 11.888533333333331 13.520066666666667 11.176033333333333C13.595999999999998 10.331533333333333 13.666666666666666 9.217633333333332 13.666666666666666 7.998666666666666C13.666666666666666 6.779766666666667 13.595999999999998 5.665846666666667 13.520066666666667 4.821366666666666C13.456 4.108866666666666 12.898733333333332 3.55968 12.179733333333333 3.5013666666666663C11.144933333333334 3.417453333333333 9.678999999999998 3.3320333333333334 8 3.3320333333333334zM3.7397666666666667 2.50462C4.794879999999999 2.41906 6.288386666666666 2.3320333333333334 8 2.3320333333333334C9.7118 2.3320333333333334 11.2054 2.4190733333333334 12.260533333333331 2.5046399999999998C13.458733333333331 2.6018133333333333 14.407866666666665 3.5285199999999994 14.516066666666667 4.73182C14.593933333333332 5.597933333333334 14.666666666666666 6.7427 14.666666666666666 7.998666666666666C14.666666666666666 9.2547 14.593933333333332 10.399466666666665 14.516066666666667 11.2656C14.407866666666665 12.468866666666665 13.458733333333331 13.395566666666667 12.260533333333331 13.492766666666665C11.2054 13.578333333333333 9.7118 13.665333333333333 8 13.665333333333333C6.288386666666666 13.665333333333333 4.794879999999999 13.578333333333333 3.7397666666666667 13.492799999999999C2.541373333333333 13.395599999999998 1.5922066666666668 12.468633333333333 1.4840200000000001 11.265266666666665C1.4061199999999998 10.3988 1.3333333333333333 9.253866666666667 1.3333333333333333 7.998666666666666C1.3333333333333333 6.743533333333333 1.4061199999999998 5.598579999999999 1.4840200000000001 4.732153333333333C1.5922066666666668 3.5287466666666667 2.541373333333333 2.601793333333333 3.7397666666666667 2.50462z"
1205
- fill="currentColor"></path>
1206
- <path
1207
- d="M9.8092 7.3125C10.338433333333333 7.618066666666666 10.338433333333333 8.382 9.809166666666666 8.687533333333333L7.690799999999999 9.910599999999999C7.161566666666666 10.216133333333332 6.5 9.8342 6.500006666666666 9.223066666666666L6.500006666666666 6.776999999999999C6.500006666666666 6.165873333333334 7.161566666666666 5.783913333333333 7.690799999999999 6.089479999999999L9.8092 7.3125z"
1208
- fill="currentColor"></path>
1209
- </svg>
1210
- <span>${archive.stat.play}</span>
1211
- </div>
1212
- <div class="video-stat-item">
1213
- <svg style="width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg"
1214
- xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" width="16"
1215
- height="16">
1216
- <path
1217
- d="M8 3.3320333333333334C6.321186666666667 3.3320333333333334 4.855333333333333 3.4174399999999996 3.820593333333333 3.5013466666666666C3.1014733333333333 3.5596599999999996 2.5440733333333334 4.109013333333333 2.48 4.821693333333333C2.4040466666666664 5.666533333333334 2.333333333333333 6.780666666666666 2.333333333333333 7.998666666666666C2.333333333333333 9.216733333333334 2.4040466666666664 10.330866666666665 2.48 11.175699999999999C2.5440733333333334 11.888366666666666 3.1014733333333333 12.437733333333334 3.820593333333333 12.496066666666666C4.855333333333333 12.579933333333333 6.321186666666667 12.665333333333333 8 12.665333333333333C9.678999999999998 12.665333333333333 11.144933333333334 12.579933333333333 12.179733333333333 12.496033333333333C12.898733333333332 12.4377 13.456 11.888533333333331 13.520066666666667 11.176033333333333C13.595999999999998 10.331533333333333 13.666666666666666 9.217633333333332 13.666666666666666 7.998666666666666C13.666666666666666 6.779766666666667 13.595999999999998 5.665846666666667 13.520066666666667 4.821366666666666C13.456 4.108866666666666 12.898733333333332 3.55968 12.179733333333333 3.5013666666666663C11.144933333333334 3.417453333333333 9.678999999999998 3.3320333333333334 8 3.3320333333333334zM3.7397666666666667 2.50462C4.794879999999999 2.41906 6.288386666666666 2.3320333333333334 8 2.3320333333333334C9.7118 2.3320333333333334 11.2054 2.4190733333333334 12.260533333333331 2.5046399999999998C13.458733333333331 2.6018133333333333 14.407866666666665 3.5285199999999994 14.516066666666667 4.73182C14.593933333333332 5.597933333333334 14.666666666666666 6.7427 14.666666666666666 7.998666666666666C14.666666666666666 9.2547 14.593933333333332 10.399466666666665 14.516066666666667 11.2656C14.407866666666665 12.468866666666665 13.458733333333331 13.395566666666667 12.260533333333331 13.492766666666665C11.2054 13.578333333333333 9.7118 13.665333333333333 8 13.665333333333333C6.288386666666666 13.665333333333333 4.794879999999999 13.578333333333333 3.7397666666666667 13.492799999999999C2.541373333333333 13.395599999999998 1.5922066666666668 12.468633333333333 1.4840200000000001 11.265266666666665C1.4061199999999998 10.3988 1.3333333333333333 9.253866666666667 1.3333333333333333 7.998666666666666C1.3333333333333333 6.743533333333333 1.4061199999999998 5.598579999999999 1.4840200000000001 4.732153333333333C1.5922066666666668 3.5287466666666667 2.541373333333333 2.601793333333333 3.7397666666666667 2.50462z"
1218
- fill="currentColor"></path>
1219
- <path
1220
- d="M10.583333333333332 7.166666666666666L6.583333333333333 7.166666666666666C6.307193333333332 7.166666666666666 6.083333333333333 6.942799999999999 6.083333333333333 6.666666666666666C6.083333333333333 6.390526666666666 6.307193333333332 6.166666666666666 6.583333333333333 6.166666666666666L10.583333333333332 6.166666666666666C10.859466666666666 6.166666666666666 11.083333333333332 6.390526666666666 11.083333333333332 6.666666666666666C11.083333333333332 6.942799999999999 10.859466666666666 7.166666666666666 10.583333333333332 7.166666666666666z"
1221
- fill="currentColor"></path>
1222
- <path
1223
- d="M11.583333333333332 9.833333333333332L7.583333333333333 9.833333333333332C7.3072 9.833333333333332 7.083333333333333 9.609466666666666 7.083333333333333 9.333333333333332C7.083333333333333 9.0572 7.3072 8.833333333333332 7.583333333333333 8.833333333333332L11.583333333333332 8.833333333333332C11.859466666666666 8.833333333333332 12.083333333333332 9.0572 12.083333333333332 9.333333333333332C12.083333333333332 9.609466666666666 11.859466666666666 9.833333333333332 11.583333333333332 9.833333333333332z"
1224
- fill="currentColor"></path>
1225
- <path
1226
- d="M5.25 6.666666666666666C5.25 6.942799999999999 5.02614 7.166666666666666 4.75 7.166666666666666L4.416666666666666 7.166666666666666C4.140526666666666 7.166666666666666 3.9166666666666665 6.942799999999999 3.9166666666666665 6.666666666666666C3.9166666666666665 6.390526666666666 4.140526666666666 6.166666666666666 4.416666666666666 6.166666666666666L4.75 6.166666666666666C5.02614 6.166666666666666 5.25 6.390526666666666 5.25 6.666666666666666z"
1227
- fill="currentColor"></path>
1228
- <path
1229
- d="M6.25 9.333333333333332C6.25 9.609466666666666 6.02614 9.833333333333332 5.75 9.833333333333332L5.416666666666666 9.833333333333332C5.140526666666666 9.833333333333332 4.916666666666666 9.609466666666666 4.916666666666666 9.333333333333332C4.916666666666666 9.0572 5.140526666666666 8.833333333333332 5.416666666666666 8.833333333333332L5.75 8.833333333333332C6.02614 8.833333333333332 6.25 9.0572 6.25 9.333333333333332z"
1230
- fill="currentColor"></path>
1231
- </svg>
1232
- <span>${archive.stat.danmaku}</span>
1233
- </div>
1234
- </div>
1235
- </div>
1236
- </div>
1237
- `;
1238
- break;
1239
- }
1240
- case DYNAMIC_TYPE_LIVE: return [`${upName}发起了直播预约,我暂时无法渲染,请自行查看`];
1241
- case DYNAMIC_TYPE_MEDIALIST: return [`${upName}分享了收藏夹,我暂时无法渲染,请自行查看`];
1242
- case DYNAMIC_TYPE_PGC: return [`${upName}发布了剧集(番剧、电影、纪录片),我暂时无法渲染,请自行查看`];
1243
- case DYNAMIC_TYPE_ARTICLE:
1244
- if (this.config.filter.enable && this.config.filter.article) throw new Error("已屏蔽专栏动态");
1245
- return [`${upName}投稿了新专栏,我暂时无法渲染,请自行查看`];
1246
- case DYNAMIC_TYPE_MUSIC: return [`${upName}发行了新歌,我暂时无法渲染,请自行查看`];
1247
- case DYNAMIC_TYPE_COMMON_SQUARE: return [`${upName}发布了装扮|剧集|点评|普通分享,我暂时无法渲染,请自行查看`];
1248
- case DYNAMIC_TYPE_COURSES_SEASON: return [`${upName}发布了新课程,我暂时无法渲染,请自行查看`];
1249
- case DYNAMIC_TYPE_UGC_SEASON: return [`${upName}更新了合集,我暂时无法渲染,请自行查看`];
1250
- case DYNAMIC_TYPE_NONE: return [`${upName}发布了一条无效动态`];
1251
- case DYNAMIC_TYPE_LIVE_RCMD: throw new Error("直播开播动态,不做处理");
1252
- default: return [`${upName}发布了一条我无法识别的动态,请自行查看`];
1253
- }
1254
- return [main$1, forwardInfo];
1255
- };
1256
- const [main] = await getDynamicMajor(data, false);
1257
- const html = `
1258
- <!DOCTYPE html>
1259
- <html>
1260
- <head>
1261
- <title>动态通知</title>
1262
- <style>
1263
- ${this.generateCardStyle(this.config.enableLargeFont, cardColorStart, cardColorEnd, cardBasePlateBorder, cardBasePlateColor, dynamicCardColor ?? "#FFFFFF")}
1264
- </style>
1265
- </head>
1266
- <body>
1267
- <div class="background">
1268
- <div ${this.config.removeBorder ? "" : "class=\"base-plate\""}>
1269
- <div class="card">
1270
- <div class="card-body">
1271
- <!-- 主播头像 -->
1272
- <img class="anchor-avatar"
1273
- src="${avatarUrl}"
1274
- alt="主播头像">
1275
- <div class="card-content">
1276
- <div class="card-header">
1277
- <div class="up-info">
1278
- <div class="up-name" style="${module_author.vip.type !== 0 ? "color: #FB7299" : ""}">${upName}</div>
1279
- <div class="pub-time">${pubTime}</div>
1280
- </div>
1281
- ${module_author.decorate ? `
1282
- <div class="dress-up">
1283
- <img src="${dynamicCardUrl}" />
1284
- <span>${dynamicCardId}</span>
1285
- </div>
1286
- ` : ""}
1287
- </div>
1288
- <div class="card-topic">
1289
- ${topic ? `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"
1290
- class="bili-dyn-topic__icon">
1291
- <path fill-rule="evenodd" clip-rule="evenodd"
1292
- d="M11.4302 2.57458C11.4416 2.51023 11.4439 2.43974 11.4218 2.3528C11.3281 1.98196 10.9517 1.72037 10.5284 1.7527C10.432 1.76018 10.3599 1.78383 10.297 1.81376C10.2347 1.84398 10.1832 1.88155 10.1401 1.92465C10.1195 1.94485 10.1017 1.96692 10.0839 1.98897L10.0808 1.99289L10.0237 2.06277L9.91103 2.2033C9.76177 2.39141 9.61593 2.58191 9.47513 2.77556C9.33433 2.96936 9.19744 3.16585 9.06672 3.36638C9.00275 3.46491 8.93968 3.56401 8.87883 3.66461L8.56966 3.6613C8.00282 3.6574 7.43605 3.65952 6.86935 3.67034C6.80747 3.56778 6.74325 3.46677 6.67818 3.3664C6.54732 3.16585 6.41045 2.96934 6.26968 2.77568C6.12891 2.58186 5.98309 2.39134 5.83387 2.20322L5.72122 2.06268L5.66416 1.99279L5.6622 1.99036C5.64401 1.96783 5.62586 1.94535 5.60483 1.92454C5.56192 1.88144 5.51022 1.84388 5.44797 1.81364C5.38522 1.78386 5.31305 1.76006 5.21665 1.75273C4.80555 1.72085 4.4203 1.97094 4.32341 2.35273C4.30147 2.43968 4.30358 2.51018 4.31512 2.57453C4.32715 2.63859 4.34975 2.69546 4.38112 2.74649C4.39567 2.77075 4.41283 2.79315 4.42999 2.81557C4.43104 2.81694 4.43209 2.81831 4.43314 2.81968L4.48759 2.89122L4.59781 3.03355C4.74589 3.22242 4.89739 3.40905 5.05377 3.59254C5.09243 3.63788 5.13136 3.68306 5.17057 3.72785C4.99083 3.73681 4.81112 3.7467 4.63143 3.75756C4.41278 3.771 4.19397 3.78537 3.97547 3.80206L3.64757 3.82786L3.48362 3.84177L3.39157 3.85181C3.36984 3.8543 3.34834 3.8577 3.32679 3.86111C3.31761 3.86257 3.30843 3.86402 3.29921 3.86541C3.05406 3.90681 2.81526 3.98901 2.59645 4.10752C2.37765 4.22603 2.17867 4.38039 2.00992 4.56302C1.84117 4.74565 1.70247 4.95593 1.60144 5.18337C1.50025 5.4105 1.43687 5.65447 1.41362 5.90153C1.33103 6.77513 1.27663 7.6515 1.25742 8.5302C1.23758 9.40951 1.25835 10.2891 1.3098 11.1655C1.32266 11.3846 1.33738 11.6035 1.35396 11.8223L1.38046 12.1505L1.39472 12.3144L1.39658 12.335L1.39906 12.3583L1.40417 12.4048C1.40671 12.4305 1.41072 12.4558 1.41473 12.4811C1.41561 12.4866 1.41648 12.4922 1.41734 12.4977C1.45717 12.7449 1.53806 12.9859 1.65567 13.2074C1.77314 13.4289 1.92779 13.6304 2.11049 13.8022C2.29319 13.974 2.50441 14.1159 2.73329 14.2197C2.96201 14.3235 3.2084 14.3901 3.45836 14.4135C3.47066 14.415 3.48114 14.4159 3.49135 14.4167C3.49477 14.417 3.49817 14.4173 3.50159 14.4176L3.5425 14.4212L3.62448 14.4283L3.78843 14.4417L4.11633 14.4674C4.33514 14.4831 4.55379 14.4983 4.7726 14.5111C6.52291 14.6145 8.27492 14.6346 10.0263 14.5706C10.4642 14.5547 10.9019 14.5332 11.3396 14.5062C11.5584 14.4923 11.7772 14.4776 11.9959 14.4604L12.3239 14.434L12.4881 14.4196L12.5813 14.4093C12.6035 14.4065 12.6255 14.403 12.6474 14.3995C12.6565 14.3981 12.6655 14.3966 12.6746 14.3952C12.9226 14.3527 13.1635 14.2691 13.3844 14.1486C13.6052 14.0284 13.8059 13.8716 13.9759 13.6868C14.1463 13.5022 14.2861 13.2892 14.3874 13.0593C14.4381 12.9444 14.4793 12.8253 14.5108 12.7037C14.519 12.6734 14.5257 12.6428 14.5322 12.612L14.5421 12.566L14.55 12.5196C14.5556 12.4887 14.5607 12.4578 14.5641 12.4266C14.5681 12.3959 14.5723 12.363 14.5746 12.3373C14.6642 11.4637 14.7237 10.5864 14.7435 9.70617C14.764 8.825 14.7347 7.94337 14.6719 7.06715C14.6561 6.8479 14.6385 6.62896 14.6183 6.41033L14.5867 6.08246L14.5697 5.91853L14.5655 5.87758C14.5641 5.86445 14.5618 5.8473 14.5599 5.83231C14.5588 5.8242 14.5578 5.81609 14.5567 5.80797C14.5538 5.78514 14.5509 5.76229 14.5466 5.7396C14.5064 5.49301 14.4252 5.25275 14.3067 5.03242C14.1886 4.81208 14.0343 4.61153 13.8519 4.44095C13.6695 4.27038 13.4589 4.12993 13.2311 4.02733C13.0033 3.92458 12.7583 3.85907 12.5099 3.83636C12.4974 3.83492 12.4865 3.83394 12.4759 3.833C12.4729 3.83273 12.4698 3.83246 12.4668 3.83219L12.4258 3.82879L12.3438 3.82199L12.1798 3.80886L11.8516 3.78413C11.633 3.76915 11.4143 3.75478 11.1955 3.74288C10.993 3.73147 10.7904 3.72134 10.5878 3.71243L10.6914 3.59236C10.8479 3.40903 10.9992 3.22242 11.1473 3.03341L11.2576 2.89124L11.312 2.81971C11.3136 2.81773 11.3151 2.81575 11.3166 2.81377C11.3333 2.79197 11.3501 2.77013 11.3641 2.74653C11.3954 2.6955 11.418 2.63863 11.4302 2.57458ZM9.33039 5.49268C9.38381 5.16945 9.67705 4.95281 9.98536 5.00882L9.98871 5.00944C10.2991 5.06783 10.5063 5.37802 10.4524 5.70377L10.2398 6.99039L11.3846 6.9904C11.7245 6.9904 12 7.27925 12 7.63557C12 7.99188 11.7245 8.28073 11.3846 8.28073L10.0266 8.28059L9.7707 9.82911L11.0154 9.82913C11.3553 9.82913 11.6308 10.118 11.6308 10.4743C11.6308 10.8306 11.3553 11.1195 11.0154 11.1195L9.55737 11.1195L9.32807 12.5073C9.27465 12.8306 8.98141 13.0472 8.6731 12.9912L8.66975 12.9906C8.35937 12.9322 8.1522 12.622 8.20604 12.2962L8.40041 11.1195H6.89891L6.66961 12.5073C6.61619 12.8306 6.32295 13.0472 6.01464 12.9912L6.01129 12.9906C5.7009 12.9322 5.49374 12.622 5.54758 12.2962L5.74196 11.1195L4.61538 11.1195C4.27552 11.1195 4 10.8306 4 10.4743C4 10.118 4.27552 9.82913 4.61538 9.82913L5.95514 9.82911L6.21103 8.28059L4.98462 8.28073C4.64475 8.28073 4.36923 7.99188 4.36923 7.63557C4.36923 7.27925 4.64475 6.9904 4.98462 6.9904L6.42421 6.99039L6.67193 5.49268C6.72535 5.16945 7.01859 4.95281 7.3269 5.00882L7.33025 5.00944C7.64063 5.06783 7.8478 5.37802 7.79396 5.70377L7.58132 6.99039H9.08281L9.33039 5.49268ZM8.61374 9.82911L8.86963 8.28059H7.36813L7.11225 9.82911H8.61374Z"
1293
- fill="currentColor"></path>
1294
- </svg>
1295
- ${topic}` : ""}
1296
- </div>
1297
- ${main}
1298
- <div class="card-stat">
1299
- <div class="stat-item">
1300
- <svg style="width: 18px; height: 18px;" xmlns="http://www.w3.org/2000/svg"
1301
- xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 18 18" width="18"
1302
- height="18">
1303
- <path
1304
- d="M9.789075 2.2956175C8.97235 1.6308450000000003 7.74999 2.212005 7.74999 3.26506L7.74999 5.3915500000000005C6.642015000000001 5.5780325 5.3073725 6.040405 4.141735000000001 7.11143C2.809155 8.335825 1.751515 10.3041 1.45716 13.404099999999998C1.409905 13.9018 1.7595399999999999 14.22505 2.105415 14.317499999999999C2.442215 14.40755 2.8807175 14.314625 3.127745 13.92915C3.9664525 12.620249999999999 4.89282 11.894575 5.765827499999999 11.50585C6.4628049999999995 11.19545 7.14528 11.093125 7.74999 11.0959L7.74999 13.235025C7.74999 14.2881 8.97235 14.869250000000001 9.789075 14.2045L15.556199999999999 9.510425000000001C16.355075 8.860149999999999 16.355075 7.640124999999999 15.556199999999999 6.989840000000001L9.789075 2.2956175zM9.165099999999999 3.0768275000000003L14.895025 7.739050000000001C15.227975 7.980475 15.235775 8.468875 14.943874999999998 8.7142L9.17615 13.416800000000002C8.979474999999999 13.562024999999998 8.75 13.4269 8.75 13.227375000000002L8.75 10.638175C8.75 10.326975000000001 8.542125 10.134725 8.2544 10.1118C7.186765 10.02955 6.1563175 10.2037 5.150895 10.69295C4.14982 11.186925 3.2102250000000003 12.096525 2.573625 13.00995C2.54981 13.046975 2.52013 13.046025 2.5211725 12.986C2.8971525 10.0573 3.9373475 8.652125 4.807025 7.85305C5.87747 6.8694775 7.213197500000001 6.444867500000001 8.2272 6.33056C8.606525 6.287802500000001 8.74805 6.0849325 8.74805 5.7032275L8.74805 3.2615475C8.74805 3.0764875000000007 8.993175 2.9321925 9.165099999999999 3.0768275000000003z"
1305
- fill="currentColor"></path>
1306
- </svg>
1307
- <span>${forward}</span>
1308
- </div>
1309
- <div class="stat-item">
1310
- <svg style="width: 18px; height: 18px;" xmlns="http://www.w3.org/2000/svg"
1311
- xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 18 18" width="18"
1312
- height="18">
1313
- <path
1314
- d="M1.5625 7.875C1.5625 4.595807499999999 4.220807499999999 1.9375 7.5 1.9375L10.5 1.9375C13.779175 1.9375 16.4375 4.595807499999999 16.4375 7.875C16.4375 11.0504 13.944675 13.6435 10.809275 13.80405C10.097025 14.722974999999998 8.920875 15.880675 7.267095 16.331325C6.9735075 16.4113 6.704762499999999 16.286224999999998 6.55411 16.092325C6.40789 15.904149999999998 6.3561 15.634350000000001 6.4652449999999995 15.383025C6.72879 14.776249999999997 6.776465 14.221025000000001 6.7340175 13.761800000000001C3.8167675 13.387125 1.5625 10.894475 1.5625 7.875zM7.5 2.9375C4.773095 2.9375 2.5625 5.148095 2.5625 7.875C2.5625 10.502575 4.61524 12.651075000000002 7.2041924999999996 12.8038C7.4305875 12.817174999999999 7.619625000000001 12.981200000000001 7.664724999999999 13.203475C7.772575 13.734575000000001 7.8012 14.405425000000001 7.5884275 15.148399999999999C8.748325 14.6682 9.606 13.759825 10.151275 13.016475C10.24445 12.889475 10.392050000000001 12.8138 10.54955 12.812275C13.253575 12.785725 15.4375 10.58535 15.4375 7.875C15.4375 5.148095 13.226899999999999 2.9375 10.5 2.9375L7.5 2.9375z"
1315
- fill="currentColor"></path>
1316
- </svg>
1317
- <span>${comment}</span>
1318
- </div>
1319
- <div class="stat-item">
1320
- <svg style="width: 18px; height: 18px;" xmlns="http://www.w3.org/2000/svg"
1321
- xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 18 18" width="18"
1322
- height="18">
1323
- <path
1324
- d="M10.4511 2.2220125C10.218425 2.194885 10.002175 2.2953725 9.884175 2.433395C9.4264 2.9688525 9.321875 3.7501399999999996 8.978575 4.3581725C8.533574999999999 5.146395 8.1198 5.6213375 7.609775000000001 6.068507499999999C7.1751375 6.449565 6.738407499999999 6.697442499999999 6.3125 6.8050575L6.3125 14.854575C6.9198900000000005 14.868174999999999 7.572900000000001 14.876875 8.25 14.876875C9.936425 14.876875 11.367025 14.823325 12.33115 14.773699999999998C13.03235 14.737575 13.646025000000002 14.390075 13.966750000000001 13.81945C14.401900000000001 13.04535 14.9387 11.909650000000001 15.264174999999998 10.571200000000001C15.56665 9.327275 15.704699999999999 8.304325 15.766675 7.582224999999999C15.7988 7.208262500000001 15.50165 6.875019999999999 15.059999999999999 6.875019999999999L11.323274999999999 6.875019999999999C11.156575 6.875019999999999 11.000800000000002 6.791952499999999 10.907975 6.653499999999999C10.783725 6.468192500000001 10.82855 6.2670175 10.9037 6.07485C11.059 5.675084999999999 11.29355 4.9974475 11.382425000000001 4.4018275C11.470875000000001 3.80917 11.450999999999999 3.32219 11.212050000000001 2.86913C10.9571 2.3857825 10.66065 2.2464475 10.4511 2.2220125zM12.034300000000002 5.87502L15.059999999999999 5.87502C16.02035 5.87502 16.850875 6.64489 16.763 7.667825C16.697100000000002 8.435525 16.55155 9.5092 16.235825000000002 10.807500000000001C15.882625 12.259950000000002 15.3035 13.482225 14.838450000000002 14.309474999999999C14.32695 15.2194 13.377475 15.721150000000002 12.38255 15.772375C11.405125 15.822725 9.956949999999999 15.876875000000002 8.25 15.876875000000002C6.5961925 15.876875000000002 5.0846825 15.826025000000001 4.0136674999999995 15.77715C2.8370825 15.723474999999999 1.8519999999999999 14.850000000000001 1.725645 13.654824999999999C1.6404649999999998 12.849274999999999 1.5625 11.80725 1.5625 10.689375C1.5625 9.665175000000001 1.6279400000000002 8.736175 1.7045524999999997 7.998975C1.8351224999999998 6.7427075 2.9137075 5.87502 4.130655 5.87502L5.8125 5.87502C6.072015 5.87502 6.457235 5.7490675 6.9505175 5.316582499999999C7.377705000000001 4.942045 7.7193000000000005 4.5546075 8.107775 3.8665374999999997C8.492075 3.18585 8.605825 2.389785 9.124075 1.783595C9.452975 1.3988800000000001 9.99475 1.162025 10.5669 1.228745C11.16225 1.29816 11.717425 1.683875 12.09655 2.4025825000000003C12.478275 3.1262375000000002 12.474075 3.8618225 12.371500000000001 4.54938C12.302149999999997 5.0139949999999995 12.155425000000001 5.510059999999999 12.034300000000002 5.87502zM5.3125 14.82705L5.3125 6.875019999999999L4.130655 6.875019999999999C3.3792199999999997 6.875019999999999 2.77211 7.400795 2.6991975000000004 8.10235C2.6253525 8.812875 2.5625 9.70665 2.5625 10.689375C2.5625 11.762875 2.6374975 12.768475 2.7200975 13.549700000000001C2.7919925 14.229675 3.3521950000000005 14.74595 4.05924 14.778224999999999C4.4278775 14.795 4.849985 14.812050000000001 5.3125 14.82705z"
1325
- fill="currentColor"></path>
1326
- </svg>
1327
- <span>${like}</span>
1328
- </div>
1329
- </div>
1330
- </div>
1331
- </div>
1332
- </div>
1333
- </div>
1334
- </div>
1335
- </body>
1336
- </html>
1337
- `;
1338
- return await withRetry(() => this.imgHandler(html)).catch((e) => {
1339
- throw new Error(`生成图片失败!错误: ${e.toString()}`);
1340
- });
1341
- }
1342
- async generateWordCloudImg(words, masterName) {
1343
- const wordcloudJS = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "static/wordcloud2.min.js"));
1344
- const renderFunc = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "static/render.js"));
1345
- const html = `
1346
- <!DOCTYPE html>
1347
- <html lang="zh-CN">
1348
-
1349
- <head>
1350
- <meta charset="UTF-8">
1351
- <title>高清词云展示</title>
1352
- <style>
1353
- * {
1354
- margin: 0;
1355
- padding: 0;
1356
- box-sizing: border-box;
1357
- font-family: "${this.config.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
1358
- }
1359
-
1360
- html {
1361
- width: 720px;
1362
- height: 520px;
1363
- }
1364
-
1365
- .wordcloud-bg {
1366
- width: 720px;
1367
- height: 520px;
1368
- background: linear-gradient(to right, #e0eafc, #cfdef3);
1369
- font-family: 'Quicksand', sans-serif;
1370
- display: flex;
1371
- justify-content: center;
1372
- align-items: center;
1373
- }
1374
-
1375
- .wordcloud-card {
1376
- width: 700px;
1377
- height: 500px;
1378
- backdrop-filter: blur(10px);
1379
- background: rgba(255, 255, 255, 0.25);
1380
- border-radius: 20px;
1381
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
1382
- padding: 20px;
1383
- display: flex;
1384
- flex-direction: column;
1385
- align-items: center;
1386
- justify-content: center;
1387
- }
1388
-
1389
- h2 {
1390
- margin: 0 0 10px;
1391
- color: #333;
1392
- font-size: 24px;
1393
- }
1394
-
1395
- canvas {
1396
- width: 100%;
1397
- height: 100%;
1398
- display: block;
1399
- }
1400
- </style>
1401
- </head>
1402
-
1403
- <body>
1404
- <div class="wordcloud-bg">
1405
- <div class="wordcloud-card">
1406
- <h2>${masterName}直播弹幕词云</h2>
1407
- <canvas id="wordCloudCanvas"></canvas>
1408
- </div>
1409
- </div>
1410
-
1411
- <script src="${wordcloudJS}"><\/script>
1412
- <script src="${renderFunc}"><\/script>
1413
- <script>
1414
- const canvas = document.getElementById('wordCloudCanvas');
1415
- const ctx = canvas.getContext('2d');
1416
-
1417
- // 获取 CSS 大小
1418
- const style = getComputedStyle(canvas);
1419
- const cssWidth = parseInt(style.width);
1420
- const cssHeight = parseInt(style.height);
1421
- const ratio = window.devicePixelRatio || 1;
1422
-
1423
- // 设置 canvas 分辨率 & 缩放
1424
- canvas.width = cssWidth * ratio;
1425
- canvas.height = cssHeight * ratio;
1426
- ctx.scale(ratio, ratio);
1427
-
1428
- const words = ${JSON.stringify(words)}
1429
-
1430
- renderAutoFitWordCloud(canvas, words, {
1431
- maxFontSize: 60,
1432
- minFontSize: 12,
1433
- densityTarget: 0.3,
1434
- weightExponent: 0.4
1435
- });
1436
- <\/script>
1437
- </body>
1438
-
1439
- </html>
1440
- `;
1441
- return await withRetry(() => this.imgHandler(html)).catch((e) => {
1442
- throw new Error(`生成图片失败!错误: ${e.toString()}`);
1443
- });
1444
- }
1445
- async getLiveStatus(time, liveStatus) {
1446
- let titleStatus;
1447
- let liveTime;
1448
- let cover;
1449
- switch (liveStatus) {
1450
- case 0:
1451
- titleStatus = "未直播";
1452
- liveTime = "未开播";
1453
- cover = true;
1454
- break;
1455
- case 1:
1456
- titleStatus = "开播啦";
1457
- liveTime = `开播时间:${time}`;
1458
- cover = true;
1459
- break;
1460
- case 2:
1461
- titleStatus = "正在直播";
1462
- liveTime = `直播时长:${await this.getTimeDifference(time)}`;
1463
- cover = false;
1464
- break;
1465
- case 3:
1466
- titleStatus = "下播啦";
1467
- liveTime = `开播时间:${time}`;
1468
- cover = true;
1469
- break;
1470
- }
1471
- return [
1472
- titleStatus,
1473
- liveTime,
1474
- cover
1475
- ];
1476
- }
1477
- async getTimeDifference(dateString) {
1478
- const apiDateTime = luxon.DateTime.fromFormat(dateString, "yyyy-MM-dd HH:mm:ss", { zone: "UTC+8" });
1479
- const diff = luxon.DateTime.now().diff(apiDateTime, [
1480
- "years",
1481
- "months",
1482
- "days",
1483
- "hours",
1484
- "minutes",
1485
- "seconds"
1486
- ]);
1487
- const { years, months, days, hours, minutes, seconds } = diff.toObject();
1488
- const parts = [];
1489
- if (years !== 0) parts.push(`${Math.abs(years)}年`);
1490
- if (months !== 0) parts.push(`${Math.abs(months)}个月`);
1491
- if (days !== 0) parts.push(`${Math.abs(days)}天`);
1492
- if (hours !== 0) parts.push(`${Math.abs(hours)}小时`);
1493
- if (minutes !== 0) parts.push(`${Math.abs(minutes)}分`);
1494
- if (seconds !== 0) parts.push(`${Math.round(Math.abs(seconds))}秒`);
1495
- const sign = diff.as("seconds") < 0 ? "-" : "";
1496
- return parts.length > 0 ? `${sign}${parts.join("")}` : "0秒";
1497
- }
1498
- unixTimestampToString(timestamp) {
1499
- const date = /* @__PURE__ */ new Date(timestamp * 1e3);
1500
- return `${date.getFullYear()}年${`0${date.getMonth() + 1}`.slice(-2)}月${`0${date.getDate()}`.slice(-2)}日 ${`0${date.getHours()}`.slice(-2)}:${`0${date.getMinutes()}`.slice(-2)}:${`0${date.getSeconds()}`.slice(-2)}`;
1501
- }
1502
- };
1503
- (function(_BilibiliNotifyGenerateImg) {
1504
- _BilibiliNotifyGenerateImg.Config = koishi.Schema.object({
1505
- logLevel: koishi.Schema.number().required(),
1506
- filter: koishi.Schema.object({
1507
- enable: koishi.Schema.boolean(),
1508
- notify: koishi.Schema.boolean(),
1509
- regex: koishi.Schema.string(),
1510
- keywords: koishi.Schema.array(String),
1511
- forward: koishi.Schema.boolean(),
1512
- article: koishi.Schema.boolean()
1513
- }),
1514
- removeBorder: koishi.Schema.boolean(),
1515
- cardColorStart: koishi.Schema.string(),
1516
- cardColorEnd: koishi.Schema.string(),
1517
- cardBasePlateColor: koishi.Schema.string(),
1518
- cardBasePlateBorder: koishi.Schema.string(),
1519
- enableLargeFont: koishi.Schema.boolean(),
1520
- font: koishi.Schema.string(),
1521
- hideDesc: koishi.Schema.boolean(),
1522
- followerDisplay: koishi.Schema.boolean()
1523
- });
1524
- })(BilibiliNotifyGenerateImg || (BilibiliNotifyGenerateImg = {}));
1525
- var generate_img_default = BilibiliNotifyGenerateImg;
1526
-
1527
- //#endregion
1528
- //#region src/type/index.ts
1529
- let LiveType = /* @__PURE__ */ function(LiveType$1) {
1530
- LiveType$1[LiveType$1["NotLiveBroadcast"] = 0] = "NotLiveBroadcast";
1531
- LiveType$1[LiveType$1["StartBroadcasting"] = 1] = "StartBroadcasting";
1532
- LiveType$1[LiveType$1["LiveBroadcast"] = 2] = "LiveBroadcast";
1533
- LiveType$1[LiveType$1["StopBroadcast"] = 3] = "StopBroadcast";
1534
- LiveType$1[LiveType$1["FirstLiveBroadcast"] = 4] = "FirstLiveBroadcast";
1535
- return LiveType$1;
1536
- }({});
1537
- let PushType = /* @__PURE__ */ function(PushType$1) {
1538
- PushType$1[PushType$1["Live"] = 0] = "Live";
1539
- PushType$1[PushType$1["Dynamic"] = 1] = "Dynamic";
1540
- PushType$1[PushType$1["DynamicAtAll"] = 2] = "DynamicAtAll";
1541
- PushType$1[PushType$1["StartBroadcasting"] = 3] = "StartBroadcasting";
1542
- PushType$1[PushType$1["LiveGuardBuy"] = 4] = "LiveGuardBuy";
1543
- PushType$1[PushType$1["WordCloudAndLiveSummary"] = 5] = "WordCloudAndLiveSummary";
1544
- PushType$1[PushType$1["Superchat"] = 6] = "Superchat";
1545
- return PushType$1;
1546
- }({});
1547
- const PushTypeMsg = {
1548
- [PushType.Live]: "直播推送",
1549
- [PushType.Dynamic]: "动态推送",
1550
- [PushType.DynamicAtAll]: "动态推送+At全体",
1551
- [PushType.StartBroadcasting]: "开播推送",
1552
- [PushType.LiveGuardBuy]: "上舰推送",
1553
- [PushType.WordCloudAndLiveSummary]: "弹幕词云和直播总结推送",
1554
- [PushType.Superchat]: "SC推送"
1555
- };
1556
- let BiliLoginStatus = /* @__PURE__ */ function(BiliLoginStatus$1) {
1557
- BiliLoginStatus$1[BiliLoginStatus$1["NOT_LOGIN"] = 0] = "NOT_LOGIN";
1558
- BiliLoginStatus$1[BiliLoginStatus$1["LOADING_LOGIN_INFO"] = 1] = "LOADING_LOGIN_INFO";
1559
- BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_QR"] = 2] = "LOGIN_QR";
1560
- BiliLoginStatus$1[BiliLoginStatus$1["LOGGING_QR"] = 3] = "LOGGING_QR";
1561
- BiliLoginStatus$1[BiliLoginStatus$1["LOGGING_IN"] = 4] = "LOGGING_IN";
1562
- BiliLoginStatus$1[BiliLoginStatus$1["LOGGED_IN"] = 5] = "LOGGED_IN";
1563
- BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_SUCCESS"] = 6] = "LOGIN_SUCCESS";
1564
- BiliLoginStatus$1[BiliLoginStatus$1["LOGIN_FAILED"] = 7] = "LOGIN_FAILED";
1565
- return BiliLoginStatus$1;
1566
- }({});
1567
-
1568
- //#endregion
1569
- //#region src/data_server.ts
1570
- /** biome-ignore-all assist/source/organizeImports: <import> */
1571
- var BilibiliNotifyDataServer = class extends _koishijs_plugin_console.DataService {
1572
- biliData = {
1573
- status: BiliLoginStatus.LOADING_LOGIN_INFO,
1574
- msg: "正在加载登录信息..."
1575
- };
1576
- constructor(ctx) {
1577
- super(ctx, "bilibili-notify");
1578
- ctx.on("bilibili-notify/login-status-report", (data) => {
1579
- this.biliData = data;
1580
- this.refresh();
1581
- });
1582
- }
1583
- async get() {
1584
- return this.biliData;
1585
- }
1586
- };
1587
-
1588
- //#endregion
1589
- //#region src/stop_words.ts
1590
- const stopwords = new Set([
1591
- ",",
1592
- "。",
1593
- "!",
1594
- "?",
1595
- ":",
1596
- ";",
1597
- "“",
1598
- "”",
1599
- "‘",
1600
- "’",
1601
- "(",
1602
- ")",
1603
- "、",
1604
- "……",
1605
- "——",
1606
- "-",
1607
- "_",
1608
- ".",
1609
- ",",
1610
- "(",
1611
- ")",
1612
- "【",
1613
- "】",
1614
- "而且",
1615
- "但是",
1616
- "如果",
1617
- "虽然",
1618
- "因为",
1619
- "所以",
1620
- "但是",
1621
- "那么",
1622
- "那么就",
1623
- "今天",
1624
- "昨天",
1625
- "后天",
1626
- "明天",
1627
- "现在",
1628
- "刚刚",
1629
- "刚才",
1630
- "一直",
1631
- "一直在",
1632
- "目前",
1633
- "以前",
1634
- "以后",
1635
- "以前的",
1636
- "the",
1637
- "and",
1638
- "to",
1639
- "of",
1640
- "a",
1641
- "is",
1642
- "in",
1643
- "on",
1644
- "for",
1645
- "with",
1646
- "this",
1647
- "that",
1648
- "you",
1649
- "觉得",
1650
- "表示",
1651
- "发现",
1652
- "认为",
1653
- "看到",
1654
- "听说",
1655
- "了解",
1656
- "知道",
1657
- "说明",
1658
- "指出",
1659
- "讨论",
1660
- "讨论一下",
1661
- "看看",
1662
- "想想",
1663
- "说说",
1664
- "讲讲",
1665
- "一个",
1666
- "一些",
1667
- "这个",
1668
- "那个",
1669
- "每个",
1670
- "什么",
1671
- "东西",
1672
- "事情",
1673
- "这些",
1674
- "那些",
1675
- "这种",
1676
- "那种",
1677
- "怎么说",
1678
- "怎么会",
1679
- "怎么可能",
1680
- "不可能",
1681
- "有点像",
1682
- "真的很",
1683
- "特别是",
1684
- "有时候",
1685
- "每次都",
1686
- "一点点",
1687
- "哪里有",
1688
- "太离谱",
1689
- "太搞笑",
1690
- "太真实",
1691
- "为了",
1692
- "因为",
1693
- "所以",
1694
- "但是",
1695
- "而且",
1696
- "然后",
1697
- "如果",
1698
- "虽然",
1699
- "然而",
1700
- "不过",
1701
- "并且",
1702
- "即使",
1703
- "由于",
1704
- "那么",
1705
- "除非",
1706
- "比如",
1707
- "比如说",
1708
- "现在",
1709
- "刚刚",
1710
- "刚才",
1711
- "以前",
1712
- "以后",
1713
- "一直",
1714
- "从来",
1715
- "目前",
1716
- "最近",
1717
- "已经",
1718
- "后来",
1719
- "之前",
1720
- "某天"
1721
- ]);
1722
- var stop_words_default = stopwords;
1723
-
1724
- //#endregion
1725
- //#region src/core/live.ts
1726
- var BilibiliNotifyLive = class BilibiliNotifyLive extends koishi.Service {
1727
- static inject = [
1728
- "bilibili-notify-api",
1729
- "bilibili-notify-generate-img",
1730
- "bilibili-notify-push"
1731
- ];
1732
- liveManager;
1733
- _jieba = _node_rs_jieba.Jieba.withDict(_node_rs_jieba_dict.dict);
1734
- stopwords;
1735
- listenerRecord = {};
1736
- constructor(ctx, config) {
1737
- super(ctx, "bilibili-notify-live");
1738
- this.config = config;
1739
- this.logger.level = config.logLevel;
1740
- this.mergeStopWords(config.wordcloudStopWords);
1741
- }
1742
- start() {
1743
- this.liveManager = /* @__PURE__ */ new Map();
1744
- }
1745
- stop() {
1746
- this.clearPushTimers();
1747
- this.clearListeners();
1748
- }
1749
- mergeStopWords(stopWordsStr) {
1750
- if (!stopWordsStr || stopWordsStr.trim() === "") {
1751
- this.stopwords = new Set(stop_words_default);
1752
- return;
1753
- }
1754
- const additionalStopWords = stopWordsStr.split(",").map((word) => word.trim()).filter((word) => word !== "");
1755
- this.stopwords = new Set([...stop_words_default, ...additionalStopWords]);
1756
- }
1757
- async startLiveRoomListener(roomId, handler) {
1758
- if (this.listenerRecord[roomId]) {
1759
- this.logger.warn(`直播间 [${roomId}] 连接已存在,跳过创建`);
1760
- return;
1761
- }
1762
- const cookiesStr = await this.ctx["bilibili-notify-api"].getCookiesForHeader();
1763
- const mySelfInfo = await this.ctx["bilibili-notify-api"].getMyselfInfo();
1764
- if (mySelfInfo.code !== 0) {
1765
- this.logger.warn(`获取个人信息失败,无法创建直播间 [${roomId}] 连接`);
1766
- return;
1767
- }
1768
- this.listenerRecord[roomId] = (0, blive_message_listener.startListen)(Number.parseInt(roomId, 10), handler, { ws: {
1769
- headers: { Cookie: cookiesStr },
1770
- uid: mySelfInfo.data.mid
1771
- } });
1772
- this.logger.info(`直播间 [${roomId}] 连接已建立`);
1773
- }
1774
- closeListener(roomId) {
1775
- if (!this.listenerRecord || !this.listenerRecord[roomId]?.closed) this.logger.debug(`直播间 [${roomId}] 连接无需关闭`);
1776
- this.listenerRecord[roomId].close();
1777
- if (this.listenerRecord[roomId].closed) {
1778
- delete this.listenerRecord[roomId];
1779
- this.logger.info(`直播间 [${roomId}] 连接已关闭`);
1780
- return;
1781
- }
1782
- this.logger.error(`直播间 [${roomId}] 连接关闭失败`);
1783
- }
1784
- clearListeners() {
1785
- for (const key of Object.keys(this.listenerRecord)) {
1786
- this.closeListener(key);
1787
- delete this.listenerRecord[key];
1788
- }
1789
- }
1790
- clearPushTimers() {
1791
- for (const [_, timer] of this.liveManager) timer?.();
1792
- }
1793
- async getLiveRoomInfo(roomId) {
1794
- const data = await withRetry(async () => await this.ctx["bilibili-notify-api"].getLiveRoomInfo(roomId)).then((content) => content.data).catch((e) => {
1795
- this.logger.error(`获取直播间信息失败:${e.message}`);
1796
- });
1797
- if (!data) {
1798
- await this.ctx["bilibili-notify-push"].sendPrivateMsgAndStopService();
1799
- return;
1800
- }
1801
- return data;
1802
- }
1803
- async getMasterInfo(uid, masterInfo, liveType) {
1804
- const { data } = await this.ctx["bilibili-notify-api"].getMasterInfo(uid);
1805
- let liveOpenFollowerNum;
1806
- let liveEndFollowerNum;
1807
- let liveFollowerChange;
1808
- if (liveType === LiveType.StartBroadcasting || liveType === LiveType.FirstLiveBroadcast) {
1809
- liveOpenFollowerNum = data.follower_num;
1810
- liveEndFollowerNum = data.follower_num;
1811
- liveFollowerChange = 0;
1812
- }
1813
- if (liveType === LiveType.StopBroadcast || liveType === LiveType.LiveBroadcast) {
1814
- liveOpenFollowerNum = masterInfo.liveOpenFollowerNum;
1815
- liveEndFollowerNum = data.follower_num;
1816
- liveFollowerChange = liveEndFollowerNum - masterInfo.liveOpenFollowerNum;
1817
- }
1818
- return {
1819
- username: data.info.uname,
1820
- userface: data.info.face,
1821
- roomId: data.room_id,
1822
- liveOpenFollowerNum,
1823
- liveEndFollowerNum,
1824
- liveFollowerChange,
1825
- medalName: data.medal_name
1826
- };
1827
- }
1828
- async sendLiveNotifyCard(liveType, liveData, liveInfo, uid, liveNotifyMsg) {
1829
- const buffer = await withRetry(async () => {
1830
- return await this.ctx["bilibili-notify-generate-img"].generateLiveImg(liveInfo.liveRoomInfo, liveInfo.masterInfo.username, liveInfo.masterInfo.userface, liveData, liveType, liveInfo.cardStyle.enable ? liveInfo.cardStyle : void 0);
1831
- }, 1).catch((e) => {
1832
- this.logger.error(`生成直播图片失败:${e.message}`);
1833
- });
1834
- if (!buffer) return await this.ctx["bilibili-notify-push"].sendPrivateMsgAndStopService();
1835
- const msg = (0, koishi.h)("message", [koishi.h.image(buffer, "image/jpeg"), koishi.h.text(liveNotifyMsg || "")]);
1836
- return await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, msg, liveType === LiveType.StartBroadcasting ? PushType.StartBroadcasting : PushType.Live);
1837
- }
1838
- segmentDanmaku(danmaku, danmakuWeightRecord) {
1839
- this._jieba.cut(danmaku, true).filter((word) => word.length >= 2 && !this.stopwords.has(word)).forEach((w) => {
1840
- danmakuWeightRecord[w] = (danmakuWeightRecord[w] || 0) + 1;
1841
- });
1842
- }
1843
- addUserToDanmakuMaker(username, danmakuMakerRecord) {
1844
- danmakuMakerRecord[username] = (danmakuMakerRecord[username] || 0) + 1;
1845
- }
1846
- async liveDetectWithListener(sub) {
1847
- let liveTime;
1848
- let pushAtTimeTimer;
1849
- const danmakuWeightRecord = {};
1850
- const danmakuSenderRecord = {};
1851
- let liveStatus = false;
1852
- let liveRoomInfo;
1853
- let masterInfo;
1854
- const liveData = { likedNum: "0" };
1855
- const sendDanmakuWordCloudAndLiveSummary = async (customLiveSummary) => {
1856
- this.logger.debug("开始制作弹幕词云");
1857
- this.logger.debug("获取前90热词");
1858
- const words = Object.entries(danmakuWeightRecord);
1859
- const danmaker = Object.entries(danmakuSenderRecord);
1860
- const img = await (async () => {
1861
- if (words.length < 50) {
1862
- this.logger.debug("热词不足50个,放弃生成弹幕词云");
1863
- return;
1864
- }
1865
- const top90Words = words.sort((a, b) => b[1] - a[1]).slice(0, 90);
1866
- this.logger.debug("整理弹幕词云前90词及权重");
1867
- this.logger.debug(top90Words);
1868
- this.logger.debug("准备生成弹幕词云");
1869
- const buffer = await this.ctx["bilibili-notify-generate-img"].generateWordCloudImg(top90Words, masterInfo.username);
1870
- return koishi.h.image(buffer, "image/jpeg");
1871
- })();
1872
- const summary = await (async () => {
1873
- if (danmaker.length < 5) {
1874
- this.logger.debug("发言人数不足5位,放弃生成弹幕词云");
1875
- return;
1876
- }
1877
- this.logger.debug("开始构建弹幕发送排行榜消息");
1878
- const danmakuSenderCount = Object.keys(danmakuSenderRecord).length;
1879
- const danmakuCount = Object.values(danmakuSenderRecord).reduce((sum, val) => sum + val, 0);
1880
- const top5DanmakuSender = Object.entries(danmakuSenderRecord).sort((a, b) => b[1] - a[1]).slice(0, 5);
1881
- if (this.config.ai.enable) {
1882
- this.logger.debug("生成 AI 直播总结");
1883
- const top10Words = words.sort((a, b) => b[1] - a[1]).slice(0, 10);
1884
- const liveSummaryData = {
1885
- medalName: masterInfo.medalName,
1886
- danmakuSenderCount,
1887
- danmakuCount,
1888
- top5DanmakuSender,
1889
- top10Words,
1890
- liveStartTime: liveTime,
1891
- liveEndTime: luxon.DateTime.now().toFormat("yyyy-MM-dd HH:mm:ss")
1892
- };
1893
- const res = await this.ctx["bilibili-notify-api"].chatWithAI(`请你生成直播总结,用这样的风格,多使用emoji并且替换示例中的emoji,同时要对每个人进行个性化点评,以下是风格参考:
1894
-
1895
- 🔍【弹幕情报站】本场直播数据如下:
1896
- 🧍‍♂️ 总共 XX 位 (这里用medalName) 上线
1897
- 💬 共计 XXX 条弹幕飞驰而过
1898
- 📊 热词云图已生成,快来看看你有没有上榜!
1899
- 👑 本场顶级输出选手:
1900
- 🥇 XXX - 弹幕输出 XX 条,(这里进行吐槽)
1901
- 🥈 XXX - 弹幕 XX 条,(这里进行吐槽)
1902
- 🥉 XXX - 弹幕 XX 条,(这里进行吐槽)
1903
- 🎖️ 特别嘉奖:XXX(这里进行吐槽) & XXX(这里进行吐槽)。
1904
- 别以为发这么点弹幕就能糊弄过去,本兔可是盯着你们的!下次再偷懒小心被我踹飞!🐰🥕
463
+ const additionalStopWords = stopWordsStr.split(",").map((word) => word.trim()).filter((word) => word !== "");
464
+ this.stopwords = new Set([...stop_words_default, ...additionalStopWords]);
465
+ }
466
+ async startLiveRoomListener(roomId, handler) {
467
+ if (this.listenerRecord[roomId]) {
468
+ this.logger.warn(`直播间 [${roomId}] 连接已存在,跳过创建`);
469
+ return;
470
+ }
471
+ const cookiesStr = await this.ctx["bilibili-notify-api"].getCookiesForHeader();
472
+ const mySelfInfo = await this.ctx["bilibili-notify-api"].getMyselfInfo();
473
+ if (mySelfInfo.code !== 0) {
474
+ this.logger.warn(`获取个人信息失败,无法创建直播间 [${roomId}] 连接`);
475
+ return;
476
+ }
477
+ this.listenerRecord[roomId] = (0, blive_message_listener.startListen)(Number.parseInt(roomId, 10), handler, { ws: {
478
+ headers: { Cookie: cookiesStr },
479
+ uid: mySelfInfo.data.mid
480
+ } });
481
+ this.logger.info(`直播间 [${roomId}] 连接已建立`);
482
+ }
483
+ closeListener(roomId) {
484
+ if (!this.listenerRecord || !this.listenerRecord[roomId]?.closed) this.logger.debug(`直播间 [${roomId}] 连接无需关闭`);
485
+ this.listenerRecord[roomId].close();
486
+ if (this.listenerRecord[roomId].closed) {
487
+ delete this.listenerRecord[roomId];
488
+ this.logger.info(`直播间 [${roomId}] 连接已关闭`);
489
+ return;
490
+ }
491
+ this.logger.error(`直播间 [${roomId}] 连接关闭失败`);
492
+ }
493
+ clearListeners() {
494
+ for (const key of Object.keys(this.listenerRecord)) {
495
+ this.closeListener(key);
496
+ delete this.listenerRecord[key];
497
+ }
498
+ }
499
+ clearPushTimers() {
500
+ for (const [_, timer] of this.liveManager) timer?.();
501
+ }
502
+ async getLiveRoomInfo(roomId) {
503
+ const data = await withRetry(async () => await this.ctx["bilibili-notify-api"].getLiveRoomInfo(roomId)).then((content) => content.data).catch((e) => {
504
+ this.logger.error(`获取直播间信息失败:${e.message}`);
505
+ });
506
+ if (!data) {
507
+ await this.ctx["bilibili-notify-push"].sendPrivateMsgAndStopService();
508
+ return;
509
+ }
510
+ return data;
511
+ }
512
+ async getMasterInfo(uid, masterInfo, liveType) {
513
+ const { data } = await this.ctx["bilibili-notify-api"].getMasterInfo(uid);
514
+ let liveOpenFollowerNum;
515
+ let liveEndFollowerNum;
516
+ let liveFollowerChange;
517
+ if (liveType === LiveType.StartBroadcasting || liveType === LiveType.FirstLiveBroadcast) {
518
+ liveOpenFollowerNum = data.follower_num;
519
+ liveEndFollowerNum = data.follower_num;
520
+ liveFollowerChange = 0;
521
+ }
522
+ if (liveType === LiveType.StopBroadcast || liveType === LiveType.LiveBroadcast) {
523
+ liveOpenFollowerNum = masterInfo.liveOpenFollowerNum;
524
+ liveEndFollowerNum = data.follower_num;
525
+ liveFollowerChange = liveEndFollowerNum - masterInfo.liveOpenFollowerNum;
526
+ }
527
+ return {
528
+ username: data.info.uname,
529
+ userface: data.info.face,
530
+ roomId: data.room_id,
531
+ liveOpenFollowerNum,
532
+ liveEndFollowerNum,
533
+ liveFollowerChange,
534
+ medalName: data.medal_name
535
+ };
536
+ }
537
+ async sendLiveNotifyCard(liveType, liveData, liveInfo, uid, liveNotifyMsg) {
538
+ const buffer = await withRetry(async () => {
539
+ return await this.ctx["bilibili-notify-generate-img"].generateLiveImg(liveInfo.liveRoomInfo, liveInfo.masterInfo.username, liveInfo.masterInfo.userface, liveData, liveType, liveInfo.cardStyle.enable ? liveInfo.cardStyle : void 0);
540
+ }, 1).catch((e) => {
541
+ this.logger.error(`生成直播图片失败:${e.message}`);
542
+ });
543
+ if (!buffer) return await this.ctx["bilibili-notify-push"].sendPrivateMsgAndStopService();
544
+ const msg = (0, koishi.h)("message", [koishi.h.image(buffer, "image/jpeg"), koishi.h.text(liveNotifyMsg || "")]);
545
+ return await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, msg, liveType === LiveType.StartBroadcasting ? PushType.StartBroadcasting : PushType.Live);
546
+ }
547
+ segmentDanmaku(danmaku, danmakuWeightRecord) {
548
+ this._jieba.cut(danmaku, true).filter((word) => word.length >= 2 && !this.stopwords.has(word)).forEach((w) => {
549
+ danmakuWeightRecord[w] = (danmakuWeightRecord[w] || 0) + 1;
550
+ });
551
+ }
552
+ addUserToDanmakuMaker(username, danmakuMakerRecord) {
553
+ danmakuMakerRecord[username] = (danmakuMakerRecord[username] || 0) + 1;
554
+ }
555
+ async liveDetectWithListener(sub) {
556
+ let liveTime;
557
+ let pushAtTimeTimer;
558
+ const danmakuWeightRecord = {};
559
+ const danmakuSenderRecord = {};
560
+ let liveStatus = false;
561
+ let liveRoomInfo;
562
+ let masterInfo;
563
+ const liveData = { likedNum: "0" };
564
+ const sendDanmakuWordCloudAndLiveSummary = async (customLiveSummary) => {
565
+ this.logger.debug("开始制作弹幕词云");
566
+ this.logger.debug("获取前90热词");
567
+ const words = Object.entries(danmakuWeightRecord);
568
+ const danmaker = Object.entries(danmakuSenderRecord);
569
+ const img = await (async () => {
570
+ if (words.length < 50) {
571
+ this.logger.debug("热词不足50个,放弃生成弹幕词云");
572
+ return;
573
+ }
574
+ const top90Words = words.sort((a, b) => b[1] - a[1]).slice(0, 90);
575
+ this.logger.debug("整理弹幕词云前90词及权重");
576
+ this.logger.debug(top90Words);
577
+ this.logger.debug("准备生成弹幕词云");
578
+ const buffer = await this.ctx["bilibili-notify-generate-img"].generateWordCloudImg(top90Words, masterInfo.username);
579
+ return koishi.h.image(buffer, "image/jpeg");
580
+ })();
581
+ const summary = await (async () => {
582
+ if (danmaker.length < 5) {
583
+ this.logger.debug("发言人数不足5位,放弃生成弹幕词云");
584
+ return;
585
+ }
586
+ this.logger.debug("开始构建弹幕发送排行榜消息");
587
+ const danmakuSenderCount = Object.keys(danmakuSenderRecord).length;
588
+ const danmakuCount = Object.values(danmakuSenderRecord).reduce((sum, val) => sum + val, 0);
589
+ const top5DanmakuSender = Object.entries(danmakuSenderRecord).sort((a, b) => b[1] - a[1]).slice(0, 5);
590
+ if (this.config.ai.enable) {
591
+ this.logger.debug("生成 AI 直播总结");
592
+ const top10Words = words.sort((a, b) => b[1] - a[1]).slice(0, 10);
593
+ const liveSummaryData = {
594
+ medalName: masterInfo.medalName,
595
+ danmakuSenderCount,
596
+ danmakuCount,
597
+ top5DanmakuSender,
598
+ top10Words,
599
+ liveStartTime: liveTime,
600
+ liveEndTime: luxon.DateTime.now().toFormat("yyyy-MM-dd HH:mm:ss")
601
+ };
602
+ const res = await this.ctx["bilibili-notify-api"].chatWithAI(`请你生成直播总结,用这样的风格,多使用emoji并且替换示例中的emoji,同时要对每个人进行个性化点评,以下是风格参考:
603
+
604
+ 🔍【弹幕情报站】本场直播数据如下:
605
+ 🧍‍♂️ 总共 XX 位 (这里用medalName) 上线
606
+ 💬 共计 XXX 条弹幕飞驰而过
607
+ 📊 热词云图已生成,快来看看你有没有上榜!
608
+ 👑 本场顶级输出选手:
609
+ 🥇 XXX - 弹幕输出 XX 条,(这里进行吐槽)
610
+ 🥈 XXX - 弹幕 XX 条,(这里进行吐槽)
611
+ 🥉 XXX - 弹幕 XX 条,(这里进行吐槽)
612
+ 🎖️ 特别嘉奖:XXX(这里进行吐槽) & XXX(这里进行吐槽)。
613
+ 别以为发这么点弹幕就能糊弄过去,本兔可是盯着你们的!下次再偷懒小心被我踹飞!🐰🥕
1905
614
 
1906
615
  以下是直播数据:${JSON.stringify(liveSummaryData)}`);
1907
616
  this.logger.debug("AI 直播总结生成完毕");
@@ -1965,7 +674,7 @@ var BilibiliNotifyLive = class BilibiliNotifyLive extends koishi.Service {
1965
674
  const LIVE_EVENT_COOLDOWN = 10 * 1e3;
1966
675
  let lastLiveStart = 0;
1967
676
  let lastLiveEnd = 0;
1968
- await this.startLiveRoomListener(sub.roomid, {
677
+ const handler = {
1969
678
  onError: async () => {
1970
679
  liveStatus = false;
1971
680
  pushAtTimeTimer?.();
@@ -1977,6 +686,11 @@ var BilibiliNotifyLive = class BilibiliNotifyLive extends koishi.Service {
1977
686
  onIncomeDanmu: ({ body }) => {
1978
687
  this.segmentDanmaku(body.content, danmakuWeightRecord);
1979
688
  this.addUserToDanmakuMaker(body.user.uname, danmakuSenderRecord);
689
+ if (sub.customSpecialDanmakuUsers.enable && sub.customSpecialDanmakuUsers.specialDanmakuUsers?.includes(body.user.uid.toString())) {
690
+ const msgTemplate = sub.customSpecialDanmakuUsers.msgTemplate.replace("-mastername", masterInfo.username).replace("-uname", body.user.uname).replace("-msg", body.content);
691
+ const content = (0, koishi.h)("message", [koishi.h.text(msgTemplate)]);
692
+ this.ctx["bilibili-notify-push"].broadcastToTargets(sub.uid, content, PushType.UserDanmakuMsg);
693
+ }
1980
694
  },
1981
695
  onIncomeSuperChat: ({ body }) => {
1982
696
  this.segmentDanmaku(body.content, danmakuWeightRecord);
@@ -2096,7 +810,19 @@ var BilibiliNotifyLive = class BilibiliNotifyLive extends koishi.Service {
2096
810
  await sendDanmakuWordCloudAndLiveSummary(sub.customLiveSummary.liveSummary);
2097
811
  }
2098
812
  }
2099
- });
813
+ };
814
+ const userAction = { onUserAction: ({ body }) => {
815
+ if (body.action === "enter" && sub.customSpecialUsersEnterTheRoom.specialUsersEnterTheRoom?.includes(body.user.toString())) {
816
+ const msgTemplate = sub.customSpecialUsersEnterTheRoom.msgTemplate.replace("-mastername", masterInfo.username).replace("-uname", body.user.uname);
817
+ const content = (0, koishi.h)("message", [koishi.h.text(msgTemplate)]);
818
+ this.ctx["bilibili-notify-push"].broadcastToTargets(sub.uid, content, PushType.UserActions);
819
+ }
820
+ } };
821
+ const finalMsgHandler = {
822
+ ...handler,
823
+ ...sub.customSpecialUsersEnterTheRoom.enable ? userAction : {}
824
+ };
825
+ await this.startLiveRoomListener(sub.roomid, finalMsgHandler);
2100
826
  if (!await useLiveRoomInfo(LiveType.FirstLiveBroadcast) && !await useMasterInfo(LiveType.FirstLiveBroadcast)) return this.ctx["bilibili-notify-push"].sendPrivateMsg("获取直播间信息失败,启动直播间弹幕检测失败");
2101
827
  this.logger.debug(`当前粉丝数:${masterInfo.liveOpenFollowerNum}`);
2102
828
  if (liveRoomInfo.live_status === 1) {
@@ -2141,17 +867,17 @@ var live_default = BilibiliNotifyLive;
2141
867
 
2142
868
  //#endregion
2143
869
  //#region src/command/bili.ts
2144
- function bili_default(ctx) {
2145
- const biliCom = ctx.command("bili", "bili-notify插件相关指令", { permissions: ["authority:3"] });
870
+ function bili_default() {
871
+ const biliCom = this.ctx.command("bili", "bili-notify插件相关指令", { permissions: ["authority:3"] });
2146
872
  biliCom.subcommand(".list", "展示订阅对象").usage("展示订阅对象").example("bili list").action(() => {
2147
873
  return this.subShow();
2148
874
  });
2149
875
  biliCom.subcommand(".private", "向管理员账号发送一条测试消息", { hidden: true }).usage("向管理员账号发送一条测试消息").example("bili private 向管理员账号发送一条测试消息").action(async ({ session }) => {
2150
- await this.sendPrivateMsg("测试消息");
876
+ await this.ctx["bilibili-notify-push"].sendPrivateMsg("测试消息");
2151
877
  await session.send("已发送测试消息。如果未收到,可能是机器人不支持发送私聊消息或配置信息有误");
2152
878
  });
2153
879
  biliCom.subcommand(".ll").usage("展示当前正在直播的订阅对象").example("bili ll").action(async () => {
2154
- const { data: { live_users } } = await ctx["bilibili-notify-api"].getTheUserWhoIsLiveStreaming();
880
+ const { data: { live_users } } = await this.ctx["bilibili-notify-api"].getTheUserWhoIsLiveStreaming();
2155
881
  const subLiveUsers = [];
2156
882
  if (live_users?.items) for (const [uid, sub] of this.subManager) {
2157
883
  let onLive = false;
@@ -2316,7 +1042,7 @@ function bili_default(ctx) {
2316
1042
  };
2317
1043
  }).then((content) => content.data);
2318
1044
  if (userInfoCode !== -352 || !userInfoData.v_voucher) return "不满足验证条件,无需执行。如果提示风控,请尝试重启插件";
2319
- const { data } = await ctx["bilibili-notify-api"].v_voucherCaptcha(userInfoData.v_voucher);
1045
+ const { data } = await this.ctx["bilibili-notify-api"].v_voucherCaptcha(userInfoData.v_voucher);
2320
1046
  if (!data.geetest) return "当前风控无法通过验证解除,可能需要人工申诉";
2321
1047
  await session.send("请到这个网站进行验证操作:https://kuresaru.github.io/geetest-validator/");
2322
1048
  await session.send("请手动填入 gt 和 challenge,然后点击生成进行验证。验证完成后再点击结果,并根据提示输入对应的 validate");
@@ -2325,10 +1051,10 @@ function bili_default(ctx) {
2325
1051
  await session.send("验证完成,请直接输入 validate");
2326
1052
  const validate = await session.prompt();
2327
1053
  const seccode = `${validate}|jordan`;
2328
- const { data: validateCaptchaData } = await ctx["bilibili-notify-api"].validateCaptcha(data.geetest.challenge, data.token, validate, seccode);
1054
+ const { data: validateCaptchaData } = await this.ctx["bilibili-notify-api"].validateCaptcha(data.geetest.challenge, data.token, validate, seccode);
2329
1055
  if (validateCaptchaData?.is_valid !== 1) return "验证失败,请重试";
2330
1056
  await this.ctx.sleep(10 * 1e3);
2331
- const { code: validCode, data: validData } = await ctx["bilibili-notify-api"].getUserInfo("114514", validateCaptchaData.grisk_id);
1057
+ const { code: validCode, data: validData } = await this.ctx["bilibili-notify-api"].getUserInfo("114514", validateCaptchaData.grisk_id);
2332
1058
  if (validCode === -352 && validData.v_voucher) return "验证失败,请重试";
2333
1059
  await session.send("验证成功!请重启插件以继续工作");
2334
1060
  });
@@ -2393,10 +1119,10 @@ function bili_default(ctx) {
2393
1119
 
2394
1120
  //#endregion
2395
1121
  //#region src/command/status.ts
2396
- function status_default(ctx) {
2397
- const statusCom = ctx.command("status", "插件状态相关指令", { permissions: ["authority:5"] });
1122
+ function status_default() {
1123
+ const statusCom = this.ctx.command("status", "插件状态相关指令", { permissions: ["authority:5"] });
2398
1124
  statusCom.subcommand(".dyn", "查看动态监测运行状态").usage("查看动态监测运行状态").example("status dyn").action(() => {
2399
- if (this.dynamicJob?.isActive) return "动态监测正在运行";
1125
+ if (this.ctx["bilibili-notify-dynamic"].isActive) return "动态监测正在运行";
2400
1126
  return "动态监测未运行";
2401
1127
  });
2402
1128
  statusCom.subcommand(".sm", "查看订阅管理对象").usage("查看订阅管理对象").example("status sm").action(async () => {
@@ -2405,7 +1131,7 @@ function status_default(ctx) {
2405
1131
  });
2406
1132
  statusCom.subcommand(".bot", "查询当前拥有的机器人信息", { hidden: true }).usage("查询当前拥有的机器人信息").example("status bot 查询当前拥有的机器人信息").action(() => {
2407
1133
  this.logger.debug("开始输出BOT信息");
2408
- for (const bot of ctx.bots) {
1134
+ for (const bot of this.ctx.bots) {
2409
1135
  this.logger.debug("--------------------------------");
2410
1136
  this.logger.debug(`平台:${bot.platform}`);
2411
1137
  this.logger.debug(`名称:${bot.user.name}`);
@@ -2419,8 +1145,26 @@ function status_default(ctx) {
2419
1145
  }
2420
1146
 
2421
1147
  //#endregion
2422
- //#region src/core/core.ts
2423
- var BilibiliNotifyCore = class extends koishi.Service {
1148
+ //#region src/command/sys.ts
1149
+ function sys_default() {
1150
+ const sysCom = this.ctx.command("bn", "bilibili-notify 插件运行相关指令", { permissions: ["authority:5"] });
1151
+ sysCom.subcommand(".restart", "重启插件").usage("重启插件").example("bn restart").action(async () => {
1152
+ if (await this.restartPlugin()) return "主人~女仆成功重启插件啦~乖乖继续为主人服务呢 (>ω<)♡";
1153
+ return "主人呜呜 (;>_<) 女仆重启插件失败啦~请主人检查一下再试哦 (>ω<)♡";
1154
+ });
1155
+ sysCom.subcommand(".stop", "停止插件").usage("停止插件").example("bn stop").action(async () => {
1156
+ if (await this.disposePlugin()) return "主人~女仆已经停止插件啦~休息一下先 (>ω<)♡";
1157
+ return "主人呜呜 (;>_<) 女仆停止插件失败啦~请主人检查一下再试哦 (>ω<)♡";
1158
+ });
1159
+ sysCom.subcommand(".start", "启动插件").usage("启动插件").example("bn start").action(async () => {
1160
+ if (await this.registerPlugin()) return "主人~女仆成功启动插件啦~准备好乖乖为主人工作呢 (>ω<)♡";
1161
+ return "主人呜呜 (;>_<) 女仆启动插件失败啦~请主人检查一下再试哦 (>ω<)♡";
1162
+ });
1163
+ }
1164
+
1165
+ //#endregion
1166
+ //#region src/core/sub.ts
1167
+ var BilibiliNotifySub = class extends koishi.Service {
2424
1168
  static inject = [
2425
1169
  "database",
2426
1170
  "bilibili-notify",
@@ -2513,6 +1257,8 @@ var BilibiliNotifyCore = class extends koishi.Service {
2513
1257
  const superchatArr = [];
2514
1258
  const wordcloudArr = [];
2515
1259
  const liveSummaryArr = [];
1260
+ const spacialDanmakuArr = [];
1261
+ const spacialUserEnterTheRoomArr = [];
2516
1262
  for (const platform of sub.target) for (const channel of platform.channelArr) {
2517
1263
  const target = `${platform.platform}:${channel.channelId}`;
2518
1264
  const conditions = [
@@ -2523,7 +1269,9 @@ var BilibiliNotifyCore = class extends koishi.Service {
2523
1269
  ["liveGuardBuy", liveGuardBuyArr],
2524
1270
  ["superchat", superchatArr],
2525
1271
  ["wordcloud", wordcloudArr],
2526
- ["liveSummary", liveSummaryArr]
1272
+ ["liveSummary", liveSummaryArr],
1273
+ ["spacialDanmaku", spacialDanmakuArr],
1274
+ ["spacialUserEnterTheRoom", spacialUserEnterTheRoomArr]
2527
1275
  ];
2528
1276
  for (const [key, arr] of conditions) if (channel[key]) arr.push(target);
2529
1277
  }
@@ -2544,8 +1292,8 @@ var BilibiliNotifyCore = class extends koishi.Service {
2544
1292
  this.logger.debug(pushArrMap);
2545
1293
  }
2546
1294
  registerCommands() {
2547
- bili_default(this.ctx);
2548
- status_default(this.ctx);
1295
+ bili_default.call(this);
1296
+ status_default.call(this);
2549
1297
  }
2550
1298
  registeringForEvents() {
2551
1299
  this.ctx.console.addListener("bilibili-notify/start-login", async () => {
@@ -2698,7 +1446,9 @@ var BilibiliNotifyCore = class extends koishi.Service {
2698
1446
  liveGuardBuy: s.liveGuardBuy,
2699
1447
  superchat: s.superchat,
2700
1448
  wordcloud: s.wordcloud,
2701
- liveSummary: s.liveSummary
1449
+ liveSummary: s.liveSummary,
1450
+ spacialDanmaku: false,
1451
+ spacialUserEnterTheRoom: false
2702
1452
  })),
2703
1453
  platform: s.platform
2704
1454
  }];
@@ -2714,7 +1464,9 @@ var BilibiliNotifyCore = class extends koishi.Service {
2714
1464
  customCardStyle: { enable: false },
2715
1465
  customLiveMsg: { enable: false },
2716
1466
  customLiveSummary: { enable: false },
2717
- customGuardBuy: { enable: false }
1467
+ customGuardBuy: { enable: false },
1468
+ customSpecialDanmakuUsers: { enable: false },
1469
+ customSpecialUsersEnterTheRoom: { enable: false }
2718
1470
  };
2719
1471
  });
2720
1472
  return subs;
@@ -2889,450 +1641,1764 @@ var BilibiliNotifyCore = class extends koishi.Service {
2889
1641
  code: subUserData.code,
2890
1642
  message: subUserData.message
2891
1643
  };
2892
- }))();
1644
+ }))();
1645
+ }
1646
+ async loadSubFromConfig(subs) {
1647
+ this.preInitConfig(subs);
1648
+ for (const sub of Object.values(subs)) {
1649
+ this.logger.debug(`加载订阅 UID:${sub.uid}`);
1650
+ const subInfo = await this.subUserInBili(sub.uid);
1651
+ if (subInfo.code !== 0 && subInfo.code !== 22015) return subInfo;
1652
+ if (subInfo.code === 22015) this.logger.warn(`账号异常,无法自动订阅 UID:${sub.uid},请手动订阅并移动到 "订阅" 分组`);
1653
+ this.subManager.set(sub.uid, {
1654
+ uname: sub.uname,
1655
+ roomId: sub.roomid,
1656
+ target: sub.target,
1657
+ live: sub.live,
1658
+ dynamic: sub.dynamic,
1659
+ customCardStyle: sub.customCardStyle,
1660
+ customLiveMsg: sub.customLiveMsg,
1661
+ customLiveSummary: sub.customLiveSummary
1662
+ });
1663
+ if (sub.live && !sub.roomid) {
1664
+ this.logger.debug(`UID:${sub.uid} 请求了用户接口`);
1665
+ const { code: userInfoCode, message: userInfoMsg, data: userInfoData } = await withRetry(async () => {
1666
+ return await this.ctx["bilibili-notify-api"].getUserInfo(sub.uid);
1667
+ }).catch((e) => {
1668
+ this.logger.error(`获取用户信息失败:${e.message}`);
1669
+ return {
1670
+ code: -1,
1671
+ message: `加载订阅 UID:${sub.uid} 失败`
1672
+ };
1673
+ });
1674
+ if (userInfoCode === -352 && userInfoData.v_voucher) {
1675
+ this.logger.warn("账号被风控,请使用 `bili cap` 指令进行风控验证");
1676
+ await this.ctx["bilibili-notify-push"].sendPrivateMsg("账号被风控,请使用 `bili cap` 指令进行风控验证");
1677
+ return {
1678
+ code: userInfoCode,
1679
+ message: userInfoMsg
1680
+ };
1681
+ }
1682
+ if (userInfoCode !== 0) return {
1683
+ code: userInfoCode,
1684
+ message: userInfoMsg
1685
+ };
1686
+ if (sub.live && !userInfoData.live_room) {
1687
+ sub.live = false;
1688
+ this.logger.warn(`UID:${sub.uid} 的用户没有开通直播间,无法订阅直播`);
1689
+ }
1690
+ sub.roomid = userInfoData.live_room?.roomid;
1691
+ }
1692
+ if (sub.live && sub.roomid) await this.ctx["bilibili-notify-live"].liveDetectWithListener(sub);
1693
+ this.logger.debug(`订阅 UID:${sub.uid} 加载完成`);
1694
+ if (sub !== Object.values(subs).pop()) {
1695
+ const randomDelay = Math.floor(Math.random() * 3) + 1;
1696
+ this.logger.debug(`设置随机延迟:${randomDelay} 秒`);
1697
+ await this.ctx.sleep(randomDelay * 1e3);
1698
+ }
1699
+ }
1700
+ return {
1701
+ code: 0,
1702
+ message: "订阅加载完成"
1703
+ };
1704
+ }
1705
+ async checkIfIsLogin() {
1706
+ if ((await this.ctx.database.get("loginBili", 1)).length !== 0) {
1707
+ if (this.ctx["bilibili-notify-api"].getCookies() !== "[]") return true;
1708
+ }
1709
+ return false;
1710
+ }
1711
+ };
1712
+ (function(_BilibiliNotifySub) {
1713
+ _BilibiliNotifySub.Config = koishi.Schema.object({
1714
+ logLevel: koishi.Schema.number().required(),
1715
+ advancedSub: koishi.Schema.boolean(),
1716
+ subs: koishi.Schema.array(koishi.Schema.object({
1717
+ name: koishi.Schema.string().required().description("备注"),
1718
+ uid: koishi.Schema.string().required().description("UID"),
1719
+ dynamic: koishi.Schema.boolean().default(true).description("动态"),
1720
+ dynamicAtAll: koishi.Schema.boolean().default(false).description("动态At全体"),
1721
+ live: koishi.Schema.boolean().default(true).description("直播"),
1722
+ liveAtAll: koishi.Schema.boolean().default(true).description("直播At全体"),
1723
+ liveGuardBuy: koishi.Schema.boolean().default(false).description("上舰消息"),
1724
+ superchat: koishi.Schema.boolean().default(false).description("SC"),
1725
+ wordcloud: koishi.Schema.boolean().default(true).description("弹幕词云"),
1726
+ liveSummary: koishi.Schema.boolean().default(true).description("直播总结"),
1727
+ platform: koishi.Schema.string().required().description("平台名"),
1728
+ target: koishi.Schema.string().required().description("群号/频道号")
1729
+ })).role("table").description("输入订阅信息,自定义订阅内容; 群号/频道号格式:频道号,频道号 使用英文逗号分隔,例如 1234567,2345678"),
1730
+ wordcloudStopWords: koishi.Schema.string(),
1731
+ liveSummary: koishi.Schema.array(String),
1732
+ liveLoopTime: koishi.Schema.number().default(10),
1733
+ customLiveStart: koishi.Schema.string().required(),
1734
+ customLive: koishi.Schema.string(),
1735
+ customLiveEnd: koishi.Schema.string().required(),
1736
+ customGuardBuy: koishi.Schema.object({
1737
+ enable: koishi.Schema.boolean().default(false).description("是否启用自定义舰长购买图片"),
1738
+ captainImgUrl: koishi.Schema.string().description("舰长图片链接"),
1739
+ supervisorImgUrl: koishi.Schema.string().description("提督图片链接"),
1740
+ governorImgUrl: koishi.Schema.string().description("总督图片链接"),
1741
+ guardBuyMsg: koishi.Schema.string().description("舰长购买消息")
1742
+ })
1743
+ });
1744
+ })(BilibiliNotifySub || (BilibiliNotifySub = {}));
1745
+ var sub_default = BilibiliNotifySub;
1746
+
1747
+ //#endregion
1748
+ //#region src/core/push.ts
1749
+ var BilibiliNotifyPush = class extends koishi.Service {
1750
+ privateBot;
1751
+ rebootCount = 0;
1752
+ pushArrMapInitializing = false;
1753
+ pushArrMap;
1754
+ constructor(ctx, config) {
1755
+ super(ctx, "bilibili-notify-push");
1756
+ this.config = config;
1757
+ this.logger.level = config.logLevel;
1758
+ }
1759
+ start() {
1760
+ this.privateBot = this.ctx.bots.find((bot) => bot.platform === this.config.master.platform);
1761
+ if (!this.privateBot) this.ctx.notifier.create({ content: "未配置管理员账号,无法推送插件运行状态,请尽快配置" });
1762
+ }
1763
+ getBot(pf, selfId) {
1764
+ if (!selfId || selfId === "") return this.ctx.bots.find((bot) => bot.platform === pf);
1765
+ return this.ctx.bots.find((bot) => bot.platform === pf && bot.selfId === selfId);
1766
+ }
1767
+ async sendPrivateMsg(content) {
1768
+ if (this.config.master.enable) {
1769
+ if (this.privateBot?.status !== koishi.Universal.Status.ONLINE) {
1770
+ this.logger.warn(`${this.privateBot.platform} 机器人未初始化,暂时无法推送`);
1771
+ return;
1772
+ }
1773
+ if (this.config.master.masterAccountGuildId) await this.privateBot.sendPrivateMessage(this.config.master.masterAccount, content, this.config.master.masterAccountGuildId);
1774
+ else await this.privateBot.sendPrivateMessage(this.config.master.masterAccount, content);
1775
+ }
1776
+ }
1777
+ async sendPrivateMsgAndRebootService() {
1778
+ if (this.rebootCount >= 3) {
1779
+ this.logger.error("已重启插件3次,请检查机器人状态后使用 `bn start` 启动插件");
1780
+ await this.sendPrivateMsg("已重启插件3次,请检查机器人状态后使用 `bn start` 启动插件");
1781
+ await this.ctx["bilibili-notify"].disposePlugin();
1782
+ return;
1783
+ }
1784
+ this.rebootCount++;
1785
+ this.logger.info("插件出现未知错误,正在重启插件");
1786
+ if (await this.ctx["bilibili-notify"].restartPlugin()) this.logger.info("插件重启成功");
1787
+ else {
1788
+ this.logger.error("插件重启失败,请检查机器人状态后使用 `bn start` 启动插件");
1789
+ await this.sendPrivateMsg("插件重启失败,请检查机器人状态后使用 `bn start` 启动插件");
1790
+ await this.ctx["bilibili-notify"].disposePlugin();
1791
+ }
1792
+ }
1793
+ async sendPrivateMsgAndStopService() {
1794
+ await this.sendPrivateMsg("插件发生未知错误,请检查机器人状态后使用 `bn start` 启动插件");
1795
+ this.logger.error("插件发生未知错误,请检查机器人状态后使用 `bn start` 启动插件");
1796
+ await this.ctx["bilibili-notify"].disposePlugin();
1797
+ }
1798
+ async sendMessageWithRetry(bot, channelId, content) {
1799
+ withRetry(async () => await bot.sendMessage(channelId, content), 1).catch(async (e) => {
1800
+ if (e.message === "this._request is not a function") {
1801
+ this.ctx.setTimeout(async () => {
1802
+ await this.sendMessageWithRetry(bot, channelId, content);
1803
+ }, 2e3);
1804
+ return;
1805
+ }
1806
+ this.logger.error(`发送消息失败,群组ID: ${channelId},错误:${e.message}`);
1807
+ await this.sendPrivateMsg(`发送消息失败,群组ID: ${channelId}`);
1808
+ });
1809
+ }
1810
+ async pushMessage(targets, content) {
1811
+ const t = {};
1812
+ for (const target of targets) {
1813
+ const [platform, channleId] = target.split(":");
1814
+ if (!t[platform]) t[platform] = [channleId];
1815
+ else t[platform].push(channleId);
1816
+ }
1817
+ for (const platform of Object.keys(t)) {
1818
+ const bots = [];
1819
+ for (const bot of this.ctx.bots) if (bot.platform === platform) bots.push(bot);
1820
+ let num = 0;
1821
+ const sendMessageByBot = async (channelId, botIndex = 0, retry = 3e3) => {
1822
+ if (!bots[botIndex]) {
1823
+ this.logger.warn(`${platform} 没有配置对应机器人,无法推送`);
1824
+ return;
1825
+ }
1826
+ if (bots[botIndex].status !== koishi.Universal.Status.ONLINE) {
1827
+ if (retry >= 3e3 * 2 ** 5) {
1828
+ this.logger.error(`${platform} 机器人未初始化,已重试5次,放弃推送`);
1829
+ await this.sendPrivateMsg(`${platform} 机器人未初始化,已重试5次,放弃推送`);
1830
+ return;
1831
+ }
1832
+ this.logger.warn(`${platform} 机器人未初始化,${retry / 1e3} 秒后重试`);
1833
+ await this.ctx.sleep(retry);
1834
+ await sendMessageByBot(channelId, botIndex, retry * 2);
1835
+ return;
1836
+ }
1837
+ try {
1838
+ await bots[botIndex].sendMessage(channelId, content);
1839
+ num++;
1840
+ await this.ctx.sleep(500);
1841
+ } catch (e) {
1842
+ this.logger.error(`发送消息失败:${e}`);
1843
+ if (bots.length > 1) await sendMessageByBot(channelId, botIndex++);
1844
+ }
1845
+ };
1846
+ for (const channelId of t[platform]) await sendMessageByBot(channelId);
1847
+ this.logger.info(`成功推送 ${num} 条消息`);
1848
+ }
2893
1849
  }
2894
- async loadSubFromConfig(subs) {
2895
- this.preInitConfig(subs);
2896
- for (const sub of Object.values(subs)) {
2897
- this.logger.debug(`加载订阅 UID:${sub.uid}`);
2898
- const subInfo = await this.subUserInBili(sub.uid);
2899
- if (subInfo.code !== 0 && subInfo.code !== 22015) return subInfo;
2900
- if (subInfo.code === 22015) this.logger.warn(`账号异常,无法自动订阅 UID:${sub.uid},请手动订阅并移动到 "订阅" 分组`);
2901
- this.subManager.set(sub.uid, {
2902
- uname: sub.uname,
2903
- roomId: sub.roomid,
2904
- target: sub.target,
2905
- live: sub.live,
2906
- dynamic: sub.dynamic,
2907
- customCardStyle: sub.customCardStyle,
2908
- customLiveMsg: sub.customLiveMsg,
2909
- customLiveSummary: sub.customLiveSummary
1850
+ async broadcastToTargets(uid, content, type) {
1851
+ if (!this.pushArrMapInitializing) {
1852
+ this.logger.warn(`推送对象信息尚未初始化完毕,等待5秒钟后重试推送,推送对象: ${uid}, 推送类型: ${PushTypeMsg[type]}`);
1853
+ await this.ctx.sleep(5e3);
1854
+ return this.broadcastToTargets(uid, content, type);
1855
+ }
1856
+ const record = this.pushArrMap.get(uid);
1857
+ if (!record) return;
1858
+ if (!(type === PushType.StartBroadcasting && record.liveAtAllArr?.length > 0 || type === PushType.Dynamic && (record.dynamicArr?.length > 0 || record.dynamicAtAllArr?.length > 0) || (type === PushType.Live || type === PushType.StartBroadcasting) && record.liveArr?.length > 0 || type === PushType.LiveGuardBuy && record.liveGuardBuyArr?.length > 0 || type === PushType.Superchat && record.superchatArr?.length > 0 || type === PushType.WordCloudAndLiveSummary && (record.wordcloudArr?.length > 0 || record.liveSummaryArr?.length > 0))) return;
1859
+ this.logger.info(`推送对象: ${uid}, 推送类型: ${PushTypeMsg[type]}`);
1860
+ if (type === PushType.StartBroadcasting && record.liveAtAllArr?.length > 0) {
1861
+ this.logger.debug(`推送给 @全体,对象列表:${record.liveAtAllArr}`);
1862
+ const atAllArr = structuredClone(record.liveAtAllArr);
1863
+ await withRetry(() => this.pushMessage(atAllArr, koishi.h.at("all")), 1);
1864
+ }
1865
+ if (type === PushType.Dynamic && record.dynamicArr?.length > 0) {
1866
+ if (record.dynamicAtAllArr?.length > 0) {
1867
+ this.logger.debug(`推送动态给 @全体,对象列表:${record.dynamicAtAllArr}`);
1868
+ const dynamicAtAllArr = structuredClone(record.dynamicAtAllArr);
1869
+ await withRetry(() => this.pushMessage(dynamicAtAllArr, koishi.h.at("all")), 1);
1870
+ }
1871
+ this.logger.debug(`推送动态,对象列表:${record.dynamicArr}`);
1872
+ const dynamicArr = structuredClone(record.dynamicArr);
1873
+ await withRetry(() => this.pushMessage(dynamicArr, (0, koishi.h)("message", content)), 1);
1874
+ }
1875
+ if ((type === PushType.Live || type === PushType.StartBroadcasting) && record.liveArr?.length > 0) {
1876
+ this.logger.debug(`推送直播,对象列表:${record.liveArr}`);
1877
+ const liveArr = structuredClone(record.liveArr);
1878
+ await withRetry(() => this.pushMessage(liveArr, (0, koishi.h)("message", content)), 1);
1879
+ }
1880
+ if (type === PushType.LiveGuardBuy && record.liveGuardBuyArr?.length > 0) {
1881
+ this.logger.debug(`推送直播守护购买消息,对象列表:${record.liveGuardBuyArr}`);
1882
+ const liveGuardBuyArr = structuredClone(record.liveGuardBuyArr);
1883
+ await withRetry(() => this.pushMessage(liveGuardBuyArr, (0, koishi.h)("message", content)), 1);
1884
+ }
1885
+ if (type === PushType.Superchat && record.superchatArr?.length > 0) {
1886
+ this.logger.debug(`推送 SC 消息,对象列表:${record.superchatArr}`);
1887
+ const superchatArr = structuredClone(record.superchatArr);
1888
+ await withRetry(() => this.pushMessage(superchatArr, (0, koishi.h)("message", content)), 1);
1889
+ }
1890
+ if (type === PushType.WordCloudAndLiveSummary) {
1891
+ const wordcloudArr = structuredClone(record.wordcloudArr);
1892
+ const liveSummaryArr = structuredClone(record.liveSummaryArr);
1893
+ const wordcloudAndLiveSummaryArr = wordcloudArr.filter((item) => liveSummaryArr.includes(item));
1894
+ const wordcloudOnlyArr = wordcloudArr.filter((item) => !liveSummaryArr.includes(item));
1895
+ const liveSummaryOnlyArr = liveSummaryArr.filter((item) => !wordcloudArr.includes(item));
1896
+ if (wordcloudAndLiveSummaryArr.length > 0) {
1897
+ this.logger.debug(`推送词云和直播总结,对象列表:${wordcloudAndLiveSummaryArr}`);
1898
+ const msgs = content.filter(Boolean);
1899
+ if (msgs.length > 0) await withRetry(() => this.pushMessage(wordcloudAndLiveSummaryArr, (0, koishi.h)("message", msgs)), 1);
1900
+ }
1901
+ if (content[0] && wordcloudOnlyArr.length > 0) {
1902
+ this.logger.debug(`推送词云,对象列表:${wordcloudOnlyArr}`);
1903
+ await withRetry(() => this.pushMessage(wordcloudOnlyArr, (0, koishi.h)("message", content[0])), 1);
1904
+ }
1905
+ if (content[1] && liveSummaryOnlyArr.length > 0) {
1906
+ this.logger.debug(`推送直播总结,对象列表:${liveSummaryOnlyArr}`);
1907
+ await withRetry(() => this.pushMessage(liveSummaryOnlyArr, (0, koishi.h)("message", content[1])), 1);
1908
+ }
1909
+ }
1910
+ }
1911
+ };
1912
+ (function(_BilibiliNotifyPush) {
1913
+ _BilibiliNotifyPush.Config = koishi.Schema.object({
1914
+ logLevel: koishi.Schema.number().required(),
1915
+ master: koishi.Schema.object({
1916
+ enable: koishi.Schema.boolean(),
1917
+ platform: koishi.Schema.string(),
1918
+ masterAccount: koishi.Schema.string(),
1919
+ masterAccountGuildId: koishi.Schema.string()
1920
+ })
1921
+ });
1922
+ })(BilibiliNotifyPush || (BilibiliNotifyPush = {}));
1923
+ var push_default = BilibiliNotifyPush;
1924
+
1925
+ //#endregion
1926
+ //#region src/core/dynamic.ts
1927
+ var BilibiliNotifyDynamic = class extends koishi.Service {
1928
+ static inject = [
1929
+ "bilibili-notify-api",
1930
+ "bilibili-notify-generate-img",
1931
+ "bilibili-notify-push"
1932
+ ];
1933
+ dynamicJob;
1934
+ dynamicSubManager;
1935
+ dynamicTimelineManager;
1936
+ constructor(ctx, config) {
1937
+ super(ctx, "bilibili-notify-dynamic");
1938
+ this.config = config;
1939
+ this.logger.level = config.logLevel;
1940
+ }
1941
+ start() {
1942
+ this.dynamicTimelineManager = /* @__PURE__ */ new Map();
1943
+ }
1944
+ stop() {
1945
+ if (this.dynamicJob) {
1946
+ this.dynamicJob.stop();
1947
+ this.logger.info("动态检测任务已停止");
1948
+ }
1949
+ }
1950
+ get isActive() {
1951
+ return this.dynamicJob?.isActive ?? false;
1952
+ }
1953
+ startDynamicDetector(subManager) {
1954
+ if (this.dynamicJob) {
1955
+ this.logger.warn("动态检测任务已存在,跳过创建新的任务");
1956
+ return;
1957
+ }
1958
+ if (subManager.size === 0) {
1959
+ this.logger.warn("没有订阅对象,跳过创建动态检测任务");
1960
+ return;
1961
+ }
1962
+ const dynamicSubManager = /* @__PURE__ */ new Map();
1963
+ for (const [uid, sub] of subManager) if (sub.dynamic) {
1964
+ this.dynamicTimelineManager.set(uid, Math.floor(luxon.DateTime.now().toSeconds()));
1965
+ dynamicSubManager.set(uid, sub);
1966
+ }
1967
+ this.dynamicSubManager = dynamicSubManager;
1968
+ this.dynamicJob = new cron.CronJob(this.config.dynamicCron, this.dynamicDetector());
1969
+ this.dynamicJob.start();
1970
+ this.logger.info("动态检测任务已启动");
1971
+ }
1972
+ dynamicDetector() {
1973
+ const handler = async () => {
1974
+ const currentPushDyn = {};
1975
+ this.logger.debug(`开始获取动态信息`);
1976
+ const content = await withRetry(async () => {
1977
+ return await this.ctx["bilibili-notify-api"].getAllDynamic();
1978
+ }, 1).catch((e) => {
1979
+ this.logger.error(`获取动态失败:${e.message}`);
2910
1980
  });
2911
- if (sub.live && !sub.roomid) {
2912
- this.logger.debug(`UID:${sub.uid} 请求了用户接口`);
2913
- const { code: userInfoCode, message: userInfoMsg, data: userInfoData } = await withRetry(async () => {
2914
- return await this.ctx["bilibili-notify-api"].getUserInfo(sub.uid);
2915
- }).catch((e) => {
2916
- this.logger.error(`获取用户信息失败:${e.message}`);
2917
- return {
2918
- code: -1,
2919
- message: `加载订阅 UID:${sub.uid} 失败`
2920
- };
2921
- });
2922
- if (userInfoCode === -352 && userInfoData.v_voucher) {
2923
- this.logger.warn("账号被风控,请使用 `bili cap` 指令进行风控验证");
2924
- await this.ctx["bilibili-notify-push"].sendPrivateMsg("账号被风控,请使用 `bili cap` 指令进行风控验证");
2925
- return {
2926
- code: userInfoCode,
2927
- message: userInfoMsg
2928
- };
2929
- }
2930
- if (userInfoCode !== 0) return {
2931
- code: userInfoCode,
2932
- message: userInfoMsg
2933
- };
2934
- if (sub.live && !userInfoData.live_room) {
2935
- sub.live = false;
2936
- this.logger.warn(`UID:${sub.uid} 的用户没有开通直播间,无法订阅直播`);
1981
+ if (!content) return;
1982
+ if (content.code !== 0) switch (content.code) {
1983
+ case -101:
1984
+ this.logger.error(`账号未登录,插件已停止工作,请先登录`);
1985
+ await this.ctx["bilibili-notify-push"].sendPrivateMsg(`账号未登录,插件已停止工作,请先登录`);
1986
+ await this.ctx["bilibili-notify"].disposePlugin();
1987
+ break;
1988
+ case -352:
1989
+ this.logger.error("账号被风控,插件已停止工作,请使用 `bili cap` 指令解除风控");
1990
+ await this.ctx["bilibili-notify-push"].sendPrivateMsg("账号被风控,插件已停止工作,请使用 `bili cap` 指令解除风控");
1991
+ await this.ctx["bilibili-notify"].disposePlugin();
1992
+ break;
1993
+ default:
1994
+ this.logger.error(`获取动态信息失败,错误码:${content.code},错误信息:${content.message}`);
1995
+ await this.ctx["bilibili-notify-push"].sendPrivateMsg(`获取动态信息失败,错误码:${content.code}`);
1996
+ await this.ctx["bilibili-notify"].disposePlugin();
1997
+ break;
1998
+ }
1999
+ this.logger.debug("成功获取动态信息,开始处理");
2000
+ const items = content.data.items;
2001
+ for (const item of items) {
2002
+ if (!item) continue;
2003
+ const postTime = item.modules.module_author.pub_ts;
2004
+ const uid = item.modules.module_author.mid.toString();
2005
+ const name$2 = item.modules.module_author.name;
2006
+ this.logger.debug(`获取动态信息:UP主=${name$2}, UID=${uid}, 发布时间=${luxon.DateTime.fromSeconds(postTime).toFormat("yyyy-MM-dd HH:mm:ss")}`);
2007
+ if (this.dynamicTimelineManager.has(uid)) {
2008
+ this.logger.debug("已订阅该UP主,检查动态时间线");
2009
+ const timeline = this.dynamicTimelineManager.get(uid);
2010
+ this.logger.debug(`上次推送时间线:${luxon.DateTime.fromSeconds(timeline).toFormat("yyyy-MM-dd HH:mm:ss")}`);
2011
+ if (timeline < postTime) {
2012
+ this.logger.debug("该动态需要推送");
2013
+ const sub = this.dynamicSubManager.get(uid);
2014
+ this.logger.debug("开始渲染推送卡片");
2015
+ const buffer = await withRetry(async () => {
2016
+ return await this.ctx["bilibili-notify-generate-img"].generateDynamicImg(item, sub.customCardStyle.enable ? sub.customCardStyle : void 0);
2017
+ }, 1).catch(async (e) => {
2018
+ if (e.message === "直播开播动态,不做处理") return;
2019
+ if (e.message === "出现关键词,屏蔽该动态") {
2020
+ if (this.config.filter.notify) await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, (0, koishi.h)("message", `${name$2}发布了一条含有屏蔽关键字的动态`), PushType.Dynamic);
2021
+ return;
2022
+ }
2023
+ if (e.message === "已屏蔽转发动态") {
2024
+ if (this.config.filter.notify) await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, (0, koishi.h)("message", `${name$2}转发了一条动态,已屏蔽`), PushType.Dynamic);
2025
+ return;
2026
+ }
2027
+ if (e.message === "已屏蔽专栏动态") {
2028
+ if (this.config.filter.notify) await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, (0, koishi.h)("message", `${name$2}投稿了一条专栏,已屏蔽`), PushType.Dynamic);
2029
+ return;
2030
+ }
2031
+ this.logger.error(`生成动态图片失败:${e.message}`);
2032
+ await this.ctx["bilibili-notify-push"].sendPrivateMsgAndStopService();
2033
+ });
2034
+ if (!buffer) continue;
2035
+ this.logger.debug("渲染推送卡片成功");
2036
+ let dUrl = "";
2037
+ if (this.config.dynamicUrl) {
2038
+ this.logger.debug("生成动态链接");
2039
+ if (item.type === "DYNAMIC_TYPE_AV") if (this.config.dynamicVideoUrlToBV) {
2040
+ const bv = item.modules.module_dynamic.major.archive.jump_url.match(/BV[0-9A-Za-z]+/);
2041
+ dUrl = bv ? bv[0] : "";
2042
+ } else dUrl = `${name$2}发布了新视频:https:${item.modules.module_dynamic.major.archive.jump_url}`;
2043
+ else dUrl = `${name$2}发布了一条动态:https://t.bilibili.com/${item.id_str}`;
2044
+ this.logger.debug("生成动态链接成功");
2045
+ }
2046
+ this.logger.debug("推送动态");
2047
+ await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, (0, koishi.h)("message", [koishi.h.image(buffer, "image/jpeg"), koishi.h.text(dUrl)]), PushType.Dynamic);
2048
+ if (this.config.pushImgsInDynamic) {
2049
+ this.logger.debug("发送动态中的图片");
2050
+ if (item.type === "DYNAMIC_TYPE_DRAW") {
2051
+ const pics = item.modules?.module_dynamic?.major?.opus?.pics;
2052
+ if (pics) {
2053
+ const picsMsg = (0, koishi.h)("message", { forward: true }, pics.map((pic) => koishi.h.img(pic.url)));
2054
+ await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, picsMsg, PushType.Dynamic);
2055
+ }
2056
+ }
2057
+ this.logger.debug("动态中的图片发送完毕");
2058
+ }
2059
+ if (!currentPushDyn[uid]) currentPushDyn[uid] = item;
2060
+ this.logger.debug("动态推送完成");
2061
+ }
2937
2062
  }
2938
- sub.roomid = userInfoData.live_room?.roomid;
2939
2063
  }
2940
- if (sub.live && sub.roomid) await this.ctx["bilibili-notify-live"].liveDetectWithListener(sub);
2941
- this.logger.debug(`订阅 UID:${sub.uid} 加载完成`);
2942
- if (sub !== Object.values(subs).pop()) {
2943
- const randomDelay = Math.floor(Math.random() * 3) + 1;
2944
- this.logger.debug(`设置随机延迟:${randomDelay} 秒`);
2945
- await this.ctx.sleep(randomDelay * 1e3);
2064
+ this.logger.debug("动态信息处理完毕");
2065
+ for (const uid in currentPushDyn) {
2066
+ const postTime = currentPushDyn[uid].modules.module_author.pub_ts;
2067
+ this.dynamicTimelineManager.set(uid, postTime);
2068
+ this.logger.debug(`更新时间线:UP主=${uid}, 时间线=${luxon.DateTime.fromSeconds(postTime).toFormat("yyyy-MM-dd HH:mm:ss")}`);
2946
2069
  }
2947
- }
2948
- return {
2949
- code: 0,
2950
- message: "订阅加载完成"
2070
+ this.logger.debug(`推送的动态数量:${Object.keys(currentPushDyn).length} 条`);
2951
2071
  };
2952
- }
2953
- async checkIfIsLogin() {
2954
- if ((await this.ctx.database.get("loginBili", 1)).length !== 0) {
2955
- if (this.ctx["bilibili-notify-api"].getCookies() !== "[]") return true;
2956
- }
2957
- return false;
2072
+ return withLock(handler);
2958
2073
  }
2959
2074
  };
2960
- (function(_BilibiliNotifyCore) {
2961
- _BilibiliNotifyCore.Config = koishi.Schema.object({
2075
+ (function(_BilibiliNotifyDynamic) {
2076
+ _BilibiliNotifyDynamic.Config = koishi.Schema.object({
2962
2077
  logLevel: koishi.Schema.number().required(),
2963
- advancedSub: koishi.Schema.boolean(),
2964
- subs: koishi.Schema.array(koishi.Schema.object({
2965
- name: koishi.Schema.string().required().description("备注"),
2966
- uid: koishi.Schema.string().required().description("UID"),
2967
- dynamic: koishi.Schema.boolean().default(true).description("动态"),
2968
- dynamicAtAll: koishi.Schema.boolean().default(false).description("动态At全体"),
2969
- live: koishi.Schema.boolean().default(true).description("直播"),
2970
- liveAtAll: koishi.Schema.boolean().default(true).description("直播At全体"),
2971
- liveGuardBuy: koishi.Schema.boolean().default(false).description("上舰消息"),
2972
- superchat: koishi.Schema.boolean().default(false).description("SC"),
2973
- wordcloud: koishi.Schema.boolean().default(true).description("弹幕词云"),
2974
- liveSummary: koishi.Schema.boolean().default(true).description("直播总结"),
2975
- platform: koishi.Schema.string().required().description("平台名"),
2976
- target: koishi.Schema.string().required().description("群号/频道号")
2977
- })).role("table").description("输入订阅信息,自定义订阅内容; 群号/频道号格式:频道号,频道号 使用英文逗号分隔,例如 1234567,2345678"),
2978
- wordcloudStopWords: koishi.Schema.string(),
2979
- liveSummary: koishi.Schema.array(String),
2980
- liveLoopTime: koishi.Schema.number().default(10),
2981
- customLiveStart: koishi.Schema.string().required(),
2982
- customLive: koishi.Schema.string(),
2983
- customLiveEnd: koishi.Schema.string().required(),
2984
- customGuardBuy: koishi.Schema.object({
2985
- enable: koishi.Schema.boolean().default(false).description("是否启用自定义舰长购买图片"),
2986
- captainImgUrl: koishi.Schema.string().description("舰长图片链接"),
2987
- supervisorImgUrl: koishi.Schema.string().description("提督图片链接"),
2988
- governorImgUrl: koishi.Schema.string().description("总督图片链接"),
2989
- guardBuyMsg: koishi.Schema.string().description("舰长购买消息")
2990
- })
2078
+ filter: koishi.Schema.object({
2079
+ enable: koishi.Schema.boolean(),
2080
+ notify: koishi.Schema.boolean(),
2081
+ regex: koishi.Schema.string(),
2082
+ keywords: koishi.Schema.array(String)
2083
+ }),
2084
+ dynamicUrl: koishi.Schema.boolean().required(),
2085
+ dynamicCron: koishi.Schema.string().required(),
2086
+ dynamicVideoUrlToBV: koishi.Schema.boolean().required(),
2087
+ pushImgsInDynamic: koishi.Schema.boolean().required()
2991
2088
  });
2992
- })(BilibiliNotifyCore || (BilibiliNotifyCore = {}));
2993
- var core_default = BilibiliNotifyCore;
2089
+ })(BilibiliNotifyDynamic || (BilibiliNotifyDynamic = {}));
2090
+ var dynamic_default = BilibiliNotifyDynamic;
2091
+
2092
+ //#endregion
2093
+ //#region src/core/generate_img.ts
2094
+ const DYNAMIC_TYPE_NONE = "DYNAMIC_TYPE_NONE";
2095
+ const DYNAMIC_TYPE_FORWARD = "DYNAMIC_TYPE_FORWARD";
2096
+ const DYNAMIC_TYPE_AV = "DYNAMIC_TYPE_AV";
2097
+ const DYNAMIC_TYPE_PGC = "DYNAMIC_TYPE_PGC";
2098
+ const DYNAMIC_TYPE_WORD = "DYNAMIC_TYPE_WORD";
2099
+ const DYNAMIC_TYPE_DRAW = "DYNAMIC_TYPE_DRAW";
2100
+ const DYNAMIC_TYPE_ARTICLE = "DYNAMIC_TYPE_ARTICLE";
2101
+ const DYNAMIC_TYPE_MUSIC = "DYNAMIC_TYPE_MUSIC";
2102
+ const DYNAMIC_TYPE_COMMON_SQUARE = "DYNAMIC_TYPE_COMMON_SQUARE";
2103
+ const DYNAMIC_TYPE_LIVE = "DYNAMIC_TYPE_LIVE";
2104
+ const DYNAMIC_TYPE_MEDIALIST = "DYNAMIC_TYPE_MEDIALIST";
2105
+ const DYNAMIC_TYPE_COURSES_SEASON = "DYNAMIC_TYPE_COURSES_SEASON";
2106
+ const DYNAMIC_TYPE_LIVE_RCMD = "DYNAMIC_TYPE_LIVE_RCMD";
2107
+ const DYNAMIC_TYPE_UGC_SEASON = "DYNAMIC_TYPE_UGC_SEASON";
2108
+ const ADDITIONAL_TYPE_RESERVE = "ADDITIONAL_TYPE_RESERVE";
2109
+ var BilibiliNotifyGenerateImg = class extends koishi.Service {
2110
+ static inject = ["puppeteer"];
2111
+ constructor(ctx, config) {
2112
+ super(ctx, "bilibili-notify-generate-img");
2113
+ this.config = config;
2114
+ }
2115
+ numberToStr(num) {
2116
+ return num > 1e4 ? `${(num / 1e4).toFixed(1)}万` : num.toString();
2117
+ }
2118
+ CARD_STYLES = {
2119
+ large: {
2120
+ avatarSize: "70px",
2121
+ upNameFont: "27px",
2122
+ pubTimeFont: "20px",
2123
+ dressUpFont: "17px",
2124
+ cardDetailsFont: "22px",
2125
+ forwardUserinfoHeight: "35px",
2126
+ forwardUsernameFont: "20px",
2127
+ forwardAvatarSize: "25px",
2128
+ videoCardHeight: "147px",
2129
+ dynTitleFont: "20px",
2130
+ upInfoHeight: "70px",
2131
+ dynamicCardRight: "67px",
2132
+ dynamicCardTop: "24px"
2133
+ },
2134
+ normal: {
2135
+ avatarSize: "50px",
2136
+ upNameFont: "20px",
2137
+ pubTimeFont: "12px",
2138
+ dressUpFont: "12px",
2139
+ cardDetailsFont: "14px",
2140
+ forwardUserinfoHeight: "30px",
2141
+ forwardUsernameFont: "15px",
2142
+ forwardAvatarSize: "20px",
2143
+ videoCardHeight: "132px",
2144
+ dynTitleFont: "20px",
2145
+ upInfoHeight: "50px",
2146
+ dynamicCardRight: "37px",
2147
+ dynamicCardTop: "5px"
2148
+ }
2149
+ };
2150
+ BG_COLOR = {
2151
+ [blive_message_listener.GuardLevel.None]: ["#4ebcec", "#F9CCDF"],
2152
+ [blive_message_listener.GuardLevel.Jianzhang]: ["#4ebcec", "#b494e5"],
2153
+ [blive_message_listener.GuardLevel.Tidu]: ["#d8a0e6", "#b494e5"],
2154
+ [blive_message_listener.GuardLevel.Zongdu]: ["#f2a053", "#ef5f5f"]
2155
+ };
2156
+ generateCardStyle(isLargeFont, cardColorStart, cardColorEnd, cardBasePlateBorder, cardBasePlateColor, dynamicCardColor) {
2157
+ const style = isLargeFont ? this.CARD_STYLES.large : this.CARD_STYLES.normal;
2158
+ return `
2159
+ * {
2160
+ margin: 0;
2161
+ padding: 0;
2162
+ box-sizing: border-box;
2163
+ font-family: "${this.config.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2164
+ }
2165
+
2166
+ html {
2167
+ width: 800px;
2168
+ height: auto;
2169
+ }
2170
+
2171
+ .background {
2172
+ width: 100%;
2173
+ height: auto;
2174
+ padding: 15px;
2175
+ background: linear-gradient(to right bottom, ${cardColorStart}, ${cardColorEnd});
2176
+ overflow: hidden;
2177
+ }
2178
+
2179
+ .base-plate {
2180
+ width: 100%;
2181
+ height: auto;
2182
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
2183
+ padding: ${cardBasePlateBorder};
2184
+ border-radius: 10px;
2185
+ background-color: ${cardBasePlateColor};
2186
+ }
2187
+
2188
+ .card {
2189
+ width: 100%;
2190
+ height: auto;
2191
+ border-radius: 5px;
2192
+ padding: 15px;
2193
+ overflow: hidden;
2194
+ background-color: #fff;
2195
+ }
2196
+
2197
+ .card-body {
2198
+ display: flex;
2199
+ padding: 15px;
2200
+ }
2201
+
2202
+ .card .anchor-avatar {
2203
+ max-width: ${style.avatarSize};
2204
+ max-height: ${style.avatarSize};
2205
+ margin-right: 20px;
2206
+ border-radius: 10px;
2207
+ }
2208
+
2209
+ .card .card-body .card-content {
2210
+ width: 100%;
2211
+ }
2212
+
2213
+ .card .card-body .card-content .card-header {
2214
+ width: 100%;
2215
+ display: flex;
2216
+ justify-content: space-between;
2217
+ }
2218
+
2219
+ .card .up-info {
2220
+ display: flex;
2221
+ flex-direction: column;
2222
+ justify-content: space-between;
2223
+ height: ${style.upInfoHeight};
2224
+ }
2225
+
2226
+ .card .up-info .up-name {
2227
+ font-size: ${style.upNameFont};
2228
+ }
2229
+
2230
+ .card .pub-time {
2231
+ font-size: ${style.pubTimeFont};
2232
+ color: grey;
2233
+ }
2234
+
2235
+ .card .card-header img {
2236
+ height: 50px;
2237
+ }
2238
+
2239
+ .card .dress-up {
2240
+ position: relative;
2241
+ font-size: ${style.dressUpFont};
2242
+ }
2243
+
2244
+ .card .dress-up img {
2245
+ max-width: 100%;
2246
+ max-height: 100%;
2247
+ }
2248
+
2249
+ .card .dress-up span {
2250
+ position: absolute;
2251
+ color: ${dynamicCardColor};
2252
+ right: ${style.dynamicCardRight};
2253
+ top: ${style.dynamicCardTop};
2254
+ }
2255
+
2256
+ .card .dyn-title {
2257
+ font-size: ${style.dynTitleFont};
2258
+ margin-bottom: 10px;
2259
+ }
2260
+
2261
+ .card .card-topic {
2262
+ display: flex;
2263
+ align-items: center;
2264
+ margin-top: 10px;
2265
+ font-size: 20px;
2266
+ color: #008AC5;
2267
+ gap: 3px;
2268
+ }
2994
2269
 
2995
- //#endregion
2996
- //#region src/core/dynamic.ts
2997
- var BilibiliNotifyDynamic = class extends koishi.Service {
2998
- static inject = [
2999
- "bilibili-notify-api",
3000
- "bilibili-notify-generate-img",
3001
- "bilibili-notify-push"
3002
- ];
3003
- dynamicJob;
3004
- dynamicSubManager;
3005
- dynamicTimelineManager;
3006
- constructor(ctx, config) {
3007
- super(ctx, "bilibili-notify-dynamic");
3008
- this.config = config;
3009
- this.logger.level = config.logLevel;
3010
- }
3011
- start() {
3012
- this.dynamicTimelineManager = /* @__PURE__ */ new Map();
3013
- }
3014
- stop() {
3015
- if (this.dynamicJob) {
3016
- this.dynamicJob.stop();
3017
- this.logger.info("动态检测任务已停止");
3018
- }
3019
- }
3020
- startDynamicDetector(subManager) {
3021
- if (this.dynamicJob) {
3022
- this.logger.warn("动态检测任务已存在,跳过创建新的任务");
3023
- return;
3024
- }
3025
- if (subManager.size === 0) {
3026
- this.logger.warn("没有订阅对象,跳过创建动态检测任务");
3027
- return;
3028
- }
3029
- const dynamicSubManager = /* @__PURE__ */ new Map();
3030
- for (const [uid, sub] of subManager) if (sub.dynamic) {
3031
- this.dynamicTimelineManager.set(uid, Math.floor(luxon.DateTime.now().toSeconds()));
3032
- dynamicSubManager.set(uid, sub);
3033
- }
3034
- this.dynamicSubManager = dynamicSubManager;
3035
- this.dynamicJob = new cron.CronJob(this.config.dynamicCron, this.dynamicDetector());
3036
- this.dynamicJob.start();
3037
- this.logger.info("动态检测任务已启动");
2270
+ .card .card-details {
2271
+ margin-top: 5px;
2272
+ margin-bottom: 15px;
2273
+ font-size: ${style.cardDetailsFont};
2274
+ width: 90%;
2275
+ }
2276
+
2277
+ .card .card-major {
2278
+ display: flex;
2279
+ flex-wrap: wrap;
2280
+ gap: 5px;
2281
+ }
2282
+
2283
+ .card .card-major .photo-item {
2284
+ border-radius: 10px;
2285
+ overflow: hidden;
2286
+ width: 170px;
2287
+ height: 170px;
2288
+ object-fit: cover;
2289
+ }
2290
+
2291
+ .card .card-major .single-photo-mask {
2292
+ position: absolute;
2293
+ text-align: center;
2294
+ width: 100%;
2295
+ height: 100%;
2296
+ top: 0;
2297
+ left: 0;
2298
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, transparent 30%);
2299
+ }
2300
+
2301
+ .card .card-major .single-photo-mask-text {
2302
+ position: absolute;
2303
+ color: #fff;
2304
+ font-size: 24px;
2305
+ right: 0;
2306
+ bottom: 66px;
2307
+ left: 0;
2308
+ text-align: center;
2309
+ }
2310
+
2311
+ .card .card-major .single-photo-mask-arrow {
2312
+ position: absolute;
2313
+ width: 70px;
2314
+ height: 70px;
2315
+ bottom: 7px;
2316
+ left: 50%;
2317
+ transform: translateX(-50%);
2318
+ }
2319
+
2320
+ .card .card-major .single-photo-container {
2321
+ position: relative;
2322
+ max-width: 500px;
2323
+ max-height: 1000px;
2324
+ border-radius: 10px;
2325
+ overflow: hidden;
2326
+ }
2327
+
2328
+ .card .card-major .single-photo-item {
2329
+ max-width: 500px;
2330
+ border-radius: 10px;
2331
+ overflow: hidden;
2332
+ }
2333
+
2334
+ .card .card-major .four-photo-item {
2335
+ width: 170px;
2336
+ height: 170px;
2337
+ object-fit: cover;
2338
+ border-radius: 10px;
2339
+ overflow: hidden;
2340
+ flex-basis: 20%;
2341
+ }
2342
+
2343
+ .card .card-stat {
2344
+ display: flex;
2345
+ justify-content: space-between;
2346
+ width: 90%;
2347
+ margin-top: 15px;
2348
+ color: gray;
2349
+ font-size: 14px;
2350
+ }
2351
+
2352
+ .card .card-stat .stat-item {
2353
+ display: flex;
2354
+ align-items: center;
2355
+ gap: 3px;
2356
+ }
2357
+
2358
+ .card .card-video {
2359
+ display: flex;
2360
+ overflow: hidden;
2361
+ border-radius: 5px 0 0 5px;
2362
+ margin-top: 10px;
2363
+ height: ${style.videoCardHeight};
2364
+ }
2365
+
2366
+ .card .video-cover {
2367
+ position: relative;
2368
+ flex: 2;
2369
+ overflow: hidden;
2370
+ }
2371
+
2372
+ .card .video-cover img {
2373
+ width: 236px;
2374
+ }
2375
+
2376
+ .card .cover-mask {
2377
+ position: absolute;
2378
+ width: 100%;
2379
+ height: 100%;
2380
+ top: 0;
2381
+ left: 0;
2382
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.5) 0%, transparent 30%);
2383
+ }
2384
+
2385
+ .card .video-cover span {
2386
+ position: absolute;
2387
+ color: #fff;
2388
+ font-size: 14px;
2389
+ right: 10px;
2390
+ bottom: 8px;
2391
+ }
2392
+
2393
+ .card .video-info {
2394
+ display: flex;
2395
+ justify-content: space-between;
2396
+ flex-direction: column;
2397
+ flex: 3;
2398
+ border: #e5e7e9 1px solid;
2399
+ border-left: none;
2400
+ border-radius: 0 5px 5px 0;
2401
+ padding: 12px 16px 10px;
2402
+ background-color: #fff;
2403
+ }
2404
+
2405
+ .card .video-info-header .video-title {
2406
+ font-size: 16px;
2407
+ }
2408
+
2409
+ .card .video-info-header .video-introduction {
2410
+ margin-top: 5px;
2411
+ font-size: 12px;
2412
+ color: #AAA;
2413
+ display: -webkit-box;
2414
+ -webkit-box-orient: vertical;
2415
+ -webkit-line-clamp: 2;
2416
+ overflow: hidden;
2417
+ }
2418
+
2419
+ .card .video-stat {
2420
+ font-size: 12px;
2421
+ color: #AAA;
2422
+ display: flex;
2423
+ gap: 35px
2424
+ }
2425
+
2426
+ .card .video-stat .video-stat-item {
2427
+ display: flex;
2428
+ align-items: center;
2429
+ gap: 3px;
2430
+ }
2431
+
2432
+ .card .card-forward {
2433
+ border-radius: 5px;
2434
+ padding: 12px 10px 14px 10px;
2435
+ background-color: #F6F7F8;
2436
+ }
2437
+
2438
+ .card-forward .forward-userinfo {
2439
+ display: flex;
2440
+ align-items: center;
2441
+ gap: 5px;
2442
+ height: ${style.forwardUserinfoHeight};
2443
+ }
2444
+
2445
+ .forward-userinfo img {
2446
+ width: ${style.forwardAvatarSize};
2447
+ height: ${style.forwardAvatarSize};
2448
+ border-radius: 50%;
2449
+ }
2450
+
2451
+ .forward-userinfo span {
2452
+ color: #61666D;
2453
+ font-size: ${style.forwardUsernameFont};
2454
+ }
2455
+
2456
+ .card .card-reserve {
2457
+ display: flex;
2458
+ justify-content: space-between;
2459
+ align-items: center;
2460
+ padding: 10px 20px 10px 20px;
2461
+ margin-top: 10px;
2462
+ border-radius: 10px;
2463
+ background-color: #F6F7F8;
2464
+ }
2465
+
2466
+ .card-reserve .reserve-title {
2467
+ font-size: 14px;
2468
+ color: #18191C;
2469
+ }
2470
+
2471
+ .card-reserve .reserve-desc {
2472
+ margin-top: 7px;
2473
+ font-size: 12px;
2474
+ color: #9499A0;
2475
+ }
2476
+
2477
+ .reserve-info .reserve-time {
2478
+ margin-right: 7px;
2479
+ }
2480
+
2481
+ .card-reserve .reserve-prize {
2482
+ display: flex;
2483
+ align-items: center;
2484
+ margin-top: 3px;
2485
+ gap: 3px;
2486
+ color: #00AEEC;
2487
+ }
2488
+
2489
+ .card .card-reserve .reserve-button button {
2490
+ border: none;
2491
+ height: 30px;
2492
+ width: 72px;
2493
+ font-size: 13px;
2494
+ border-radius: 7px;
2495
+ }
2496
+
2497
+ .card .card-reserve .reserve-button .reserve-button-end {
2498
+ display: flex;
2499
+ align-items: center;
2500
+ justify-content: center;
2501
+ color: #9499A0;
2502
+ background-color: #E3E5E7;
2503
+ }
2504
+
2505
+ .card .card-reserve .reserve-button .reserve-button-ing {
2506
+ display: flex;
2507
+ align-items: center;
2508
+ justify-content: center;
2509
+ color: #FFF;
2510
+ background-color: #00A0D8;
2511
+ }
2512
+ `;
3038
2513
  }
3039
- dynamicDetector() {
3040
- const handler = async () => {
3041
- const currentPushDyn = {};
3042
- this.logger.debug(`开始获取动态信息`);
3043
- const content = await withRetry(async () => {
3044
- return await this.ctx["bilibili-notify-api"].getAllDynamic();
3045
- }, 1).catch((e) => {
3046
- this.logger.error(`获取动态失败:${e.message}`);
3047
- });
3048
- if (!content) return;
3049
- if (content.code !== 0) switch (content.code) {
3050
- case -101:
3051
- this.logger.error(`账号未登录,插件已停止工作,请先登录`);
3052
- await this.ctx["bilibili-notify-push"].sendPrivateMsg(`账号未登录,插件已停止工作,请先登录`);
3053
- await this.ctx["bilibili-notify"].disposePlugin();
3054
- break;
3055
- case -352:
3056
- this.logger.error("账号被风控,插件已停止工作,请使用 `bili cap` 指令解除风控");
3057
- await this.ctx["bilibili-notify-push"].sendPrivateMsg("账号被风控,插件已停止工作,请使用 `bili cap` 指令解除风控");
3058
- await this.ctx["bilibili-notify"].disposePlugin();
3059
- break;
3060
- default:
3061
- this.logger.error(`获取动态信息失败,错误码:${content.code},错误信息:${content.message}`);
3062
- await this.ctx["bilibili-notify-push"].sendPrivateMsg(`获取动态信息失败,错误码:${content.code}`);
3063
- await this.ctx["bilibili-notify"].disposePlugin();
3064
- break;
3065
- }
3066
- this.logger.debug("成功获取动态信息,开始处理");
3067
- const items = content.data.items;
3068
- for (const item of items) {
3069
- if (!item) continue;
3070
- const postTime = item.modules.module_author.pub_ts;
3071
- const uid = item.modules.module_author.mid.toString();
3072
- const name$2 = item.modules.module_author.name;
3073
- this.logger.debug(`获取动态信息:UP主=${name$2}, UID=${uid}, 发布时间=${luxon.DateTime.fromSeconds(postTime).toFormat("yyyy-MM-dd HH:mm:ss")}`);
3074
- if (this.dynamicTimelineManager.has(uid)) {
3075
- this.logger.debug("已订阅该UP主,检查动态时间线");
3076
- const timeline = this.dynamicTimelineManager.get(uid);
3077
- this.logger.debug(`上次推送时间线:${luxon.DateTime.fromSeconds(timeline).toFormat("yyyy-MM-dd HH:mm:ss")}`);
3078
- if (timeline < postTime) {
3079
- this.logger.debug("该动态需要推送");
3080
- const sub = this.dynamicSubManager.get(uid);
3081
- this.logger.debug("开始渲染推送卡片");
3082
- const buffer = await withRetry(async () => {
3083
- return await this.ctx["bilibili-notify-generate-img"].generateDynamicImg(item, sub.customCardStyle.enable ? sub.customCardStyle : void 0);
3084
- }, 1).catch(async (e) => {
3085
- if (e.message === "直播开播动态,不做处理") return;
3086
- if (e.message === "出现关键词,屏蔽该动态") {
3087
- if (this.config.filter.notify) await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, (0, koishi.h)("message", `${name$2}发布了一条含有屏蔽关键字的动态`), PushType.Dynamic);
3088
- return;
3089
- }
3090
- if (e.message === "已屏蔽转发动态") {
3091
- if (this.config.filter.notify) await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, (0, koishi.h)("message", `${name$2}转发了一条动态,已屏蔽`), PushType.Dynamic);
3092
- return;
3093
- }
3094
- if (e.message === "已屏蔽专栏动态") {
3095
- if (this.config.filter.notify) await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, (0, koishi.h)("message", `${name$2}投稿了一条专栏,已屏蔽`), PushType.Dynamic);
3096
- return;
3097
- }
3098
- this.logger.error(`生成动态图片失败:${e.message}`);
3099
- await this.ctx["bilibili-notify-push"].sendPrivateMsgAndStopService();
3100
- });
3101
- if (!buffer) continue;
3102
- this.logger.debug("渲染推送卡片成功");
3103
- let dUrl = "";
3104
- if (this.config.dynamicUrl) {
3105
- this.logger.debug("生成动态链接");
3106
- if (item.type === "DYNAMIC_TYPE_AV") if (this.config.dynamicVideoUrlToBV) {
3107
- const bv = item.modules.module_dynamic.major.archive.jump_url.match(/BV[0-9A-Za-z]+/);
3108
- dUrl = bv ? bv[0] : "";
3109
- } else dUrl = `${name$2}发布了新视频:https:${item.modules.module_dynamic.major.archive.jump_url}`;
3110
- else dUrl = `${name$2}发布了一条动态:https://t.bilibili.com/${item.id_str}`;
3111
- this.logger.debug("生成动态链接成功");
3112
- }
3113
- this.logger.debug("推送动态");
3114
- await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, (0, koishi.h)("message", [koishi.h.image(buffer, "image/jpeg"), koishi.h.text(dUrl)]), PushType.Dynamic);
3115
- if (this.config.pushImgsInDynamic) {
3116
- this.logger.debug("发送动态中的图片");
3117
- if (item.type === "DYNAMIC_TYPE_DRAW") {
3118
- const pics = item.modules?.module_dynamic?.major?.opus?.pics;
3119
- if (pics) {
3120
- const picsMsg = (0, koishi.h)("message", { forward: true }, pics.map((pic) => koishi.h.img(pic.url)));
3121
- await this.ctx["bilibili-notify-push"].broadcastToTargets(uid, picsMsg, PushType.Dynamic);
3122
- }
3123
- }
3124
- this.logger.debug("动态中的图片发送完毕");
3125
- }
3126
- if (!currentPushDyn[uid]) currentPushDyn[uid] = item;
3127
- this.logger.debug("动态推送完成");
3128
- }
3129
- }
2514
+ async imgHandler(html) {
2515
+ const htmlPath = `file://${__dirname.replaceAll("\\", "/")}/page/0.html`;
2516
+ const page = await this.ctx.puppeteer.page();
2517
+ await page.goto(htmlPath);
2518
+ await page.setContent(html, { waitUntil: "networkidle0" });
2519
+ const elementHandle = await page.$("html");
2520
+ const boundingBox = await elementHandle.boundingBox();
2521
+ const buffer = await page.screenshot({
2522
+ type: "jpeg",
2523
+ clip: {
2524
+ x: boundingBox.x,
2525
+ y: boundingBox.y,
2526
+ width: boundingBox.width,
2527
+ height: boundingBox.height
3130
2528
  }
3131
- this.logger.debug("动态信息处理完毕");
3132
- for (const uid in currentPushDyn) {
3133
- const postTime = currentPushDyn[uid].modules.module_author.pub_ts;
3134
- this.dynamicTimelineManager.set(uid, postTime);
3135
- this.logger.debug(`更新时间线:UP主=${uid}, 时间线=${luxon.DateTime.fromSeconds(postTime).toFormat("yyyy-MM-dd HH:mm:ss")}`);
2529
+ });
2530
+ await elementHandle.dispose();
2531
+ await page.close();
2532
+ return buffer;
2533
+ }
2534
+ async generateLiveImg(data, username, userface, liveData, liveStatus, { cardColorStart = this.config.cardColorStart, cardColorEnd = this.config.cardColorEnd, cardBasePlateColor = this.config.cardBasePlateColor, cardBasePlateBorder = this.config.cardBasePlateBorder } = {}) {
2535
+ const [titleStatus, liveTime, cover] = await this.getLiveStatus(data.live_time, liveStatus);
2536
+ const html = `
2537
+ <!DOCTYPE html>
2538
+ <html>
2539
+ <head>
2540
+ <title>直播通知</title>
2541
+ <style>
2542
+ * {
2543
+ margin: 0;
2544
+ padding: 0;
2545
+ box-sizing: border-box;
2546
+ font-family: "${this.config.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2547
+ }
2548
+
2549
+ html {
2550
+ width: 800px;
2551
+ height: auto;
2552
+ }
2553
+
2554
+ .background {
2555
+ width: 100%;
2556
+ height: auto;
2557
+ padding: 15px;
2558
+ background: linear-gradient(to right bottom, ${cardColorStart}, ${cardColorEnd});
2559
+ overflow: hidden;
2560
+ }
2561
+
2562
+ .base-plate {
2563
+ width: 100%;
2564
+ height: auto;
2565
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
2566
+ padding: ${cardBasePlateBorder};
2567
+ border-radius: 10px;
2568
+ background-color: ${cardBasePlateColor};
2569
+ }
2570
+
2571
+ .card {
2572
+ width: 100%;
2573
+ height: auto;
2574
+ border-radius: 5px;
2575
+ padding: 15px;
2576
+ overflow: hidden;
2577
+ background-color: #fff;
2578
+ }
2579
+
2580
+ .card img {
2581
+ border-radius: 5px 5px 0 0;
2582
+ max-width: 100%;
2583
+ /* 设置最大宽度为容器宽度的100% */
2584
+ max-height: 80%;
2585
+ /* 设置最大高度为容器高度的90% */
2586
+ }
2587
+
2588
+ .card-header {
2589
+ display: flex;
2590
+ justify-content: space-between;
2591
+ align-items: center;
2592
+ margin-top: 5px;
2593
+ margin-bottom: 10px;
2594
+ }
2595
+
2596
+ .card-title {
2597
+ line-height: 50px;
2598
+ }
2599
+
2600
+ .card-body {
2601
+ padding: 2px 16px;
2602
+ margin-bottom: 10px;
2603
+ }
2604
+
2605
+ .live-broadcast-info {
2606
+ display: flex;
2607
+ align-items: center;
2608
+ margin-bottom: 10px;
2609
+ }
2610
+
2611
+ .anchor-avatar {
2612
+ width: 50px;
2613
+ /* 主播头像大小 */
2614
+ height: auto;
2615
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
2616
+ }
2617
+
2618
+ .broadcast-message {
2619
+ display: inline-block;
2620
+ margin-left: 10px;
2621
+ font-size: 20px;
2622
+ color: #333;
2623
+ }
2624
+
2625
+ .card-text {
2626
+ color: grey;
2627
+ font-size: 20px;
2628
+ }
2629
+
2630
+ .card-link {
2631
+ display: flex;
2632
+ justify-content: space-between;
2633
+ text-decoration: none;
2634
+ font-size: 20px;
2635
+ margin-top: 10px;
2636
+ margin-bottom: 10px;
2637
+ }
2638
+ </style>
2639
+ </head>
2640
+ <body>
2641
+ <div class="background">
2642
+ <div ${this.config.removeBorder ? "" : "class=\"base-plate\""}>
2643
+ <div class="card">
2644
+ <img src="${cover ? data.user_cover : data.keyframe}"
2645
+ alt="封面">
2646
+ <div class="card-body">
2647
+ <div class="card-header">
2648
+ <h1 class="card-title">${data.title}</h1>
2649
+ <div class="live-broadcast-info">
2650
+ <!-- 主播头像 -->
2651
+ <img style="border-radius: 10px; margin-left: 10px" class="anchor-avatar"
2652
+ src="${userface}" alt="主播头像">
2653
+ <span class="broadcast-message">${username}${titleStatus}</span>
2654
+ </div>
2655
+ </div>
2656
+ ${this.config.hideDesc ? "" : `<p class="card-text">${data.description ? data.description : "这个主播很懒,什么简介都没写"}</p>`}
2657
+ <p class="card-link">
2658
+ <span>${liveStatus === 3 ? `本场直播点赞数:${this.numberToStr(+liveData.likedNum)}` : `人气:${this.numberToStr(data.online)}`}</span>
2659
+ <span>分区名称:${data.area_name}</span>
2660
+ </p>
2661
+ <p class="card-link">
2662
+ <span>${liveTime}</span>
2663
+ ${this.config.followerDisplay ? `
2664
+ <span>
2665
+ ${liveStatus === 1 ? `当前粉丝数:${liveData.fansNum || "暂未获取到"}` : liveStatus === 2 ? `${liveData.watchedNum !== "API" ? `累计观看人数:${liveData.watchedNum}` : ""}` : liveStatus === 3 ? `粉丝数变化:${liveData.fansChanged}` : ""}
2666
+ </span>` : ""}
2667
+ </p>
2668
+ </div>
2669
+ </div>
2670
+ </div>
2671
+ </div>
2672
+ </body>
2673
+ </html>
2674
+ `;
2675
+ return await withRetry(() => this.imgHandler(html)).catch((e) => {
2676
+ throw new Error(`生成图片失败!错误: ${e.toString()}`);
2677
+ });
2678
+ }
2679
+ async generateBoardingImg(captainImgUrl, { guardLevel, uname, face, isAdmin }, { masterAvatarUrl, masterName }) {
2680
+ const bgColor = this.BG_COLOR[guardLevel];
2681
+ const desc = {
2682
+ [blive_message_listener.GuardLevel.Jianzhang]: () => {
2683
+ return `"${uname}号"加入<br/>"${masterName}"大航海舰队!`;
2684
+ },
2685
+ [blive_message_listener.GuardLevel.Tidu]: () => {
2686
+ return `"${uname}"就任<br/>"${masterName}"大航海舰队提督!`;
2687
+ },
2688
+ [blive_message_listener.GuardLevel.Zongdu]: () => {
2689
+ return `"${uname}"上任<br/>"${masterName}"大航海舰队总督!`;
3136
2690
  }
3137
- this.logger.debug(`推送的动态数量:${Object.keys(currentPushDyn).length} 条`);
3138
2691
  };
3139
- return withLock(handler);
3140
- }
3141
- };
3142
- (function(_BilibiliNotifyDynamic) {
3143
- _BilibiliNotifyDynamic.Config = koishi.Schema.object({
3144
- logLevel: koishi.Schema.number().required(),
3145
- filter: koishi.Schema.object({
3146
- enable: koishi.Schema.boolean(),
3147
- notify: koishi.Schema.boolean(),
3148
- regex: koishi.Schema.string(),
3149
- keywords: koishi.Schema.array(String)
3150
- }),
3151
- dynamicUrl: koishi.Schema.boolean().required(),
3152
- dynamicCron: koishi.Schema.string().required(),
3153
- dynamicVideoUrlToBV: koishi.Schema.boolean().required(),
3154
- pushImgsInDynamic: koishi.Schema.boolean().required()
3155
- });
3156
- })(BilibiliNotifyDynamic || (BilibiliNotifyDynamic = {}));
3157
- var dynamic_default = BilibiliNotifyDynamic;
2692
+ const html = `
2693
+ <!DOCTYPE html>
2694
+ <html>
3158
2695
 
3159
- //#endregion
3160
- //#region src/core/push.ts
3161
- var BilibiliNotifyPush = class extends koishi.Service {
3162
- privateBot;
3163
- rebootCount = 0;
3164
- pushArrMapInitializing = false;
3165
- pushArrMap;
3166
- constructor(ctx, config) {
3167
- super(ctx, "bilibili-notify-push");
3168
- this.config = config;
3169
- this.logger.level = config.logLevel;
3170
- }
3171
- start() {
3172
- this.privateBot = this.ctx.bots.find((bot) => bot.platform === this.config.master.platform);
3173
- if (!this.privateBot) this.ctx.notifier.create({ content: "未配置管理员账号,无法推送插件运行状态,请尽快配置" });
3174
- }
3175
- getBot(pf, selfId) {
3176
- if (!selfId || selfId === "") return this.ctx.bots.find((bot) => bot.platform === pf);
3177
- return this.ctx.bots.find((bot) => bot.platform === pf && bot.selfId === selfId);
2696
+ <head>
2697
+ <title>上舰通知</title>
2698
+ <style>
2699
+ * {
2700
+ margin: 0;
2701
+ padding: 0;
2702
+ box-sizing: border-box;
2703
+ font-family: "${this.config.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
2704
+ }
2705
+
2706
+ html {
2707
+ width: 430px;
2708
+ height: auto;
2709
+ }
2710
+
2711
+ .bg {
2712
+ display: flex;
2713
+ justify-content: center;
2714
+ align-items: center;
2715
+ width: 430px;
2716
+ height: 220px;
2717
+ background: linear-gradient(to right bottom, ${bgColor[0]}, ${bgColor[1]});
2718
+ }
2719
+
2720
+ .baseplate {
2721
+ display: flex;
2722
+ justify-content: space-between;
2723
+ align-items: center;
2724
+ border-radius: 10px;
2725
+ width: 410px;
2726
+ height: 200px;
2727
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
2728
+ background-color: rgba(255, 255, 255, 0.65);
2729
+ backdrop-filter: blur(10px);
2730
+ }
2731
+
2732
+ .info {
2733
+ flex: 1;
2734
+ height: 100%;
2735
+ display: flex;
2736
+ flex-direction: column;
2737
+ justify-content: space-between;
2738
+ padding: 10px 0 10px 10px;
2739
+ }
2740
+
2741
+ .user {
2742
+ display: flex;
2743
+ gap: 10px;
2744
+ }
2745
+
2746
+ .avatar {
2747
+ height: 90px;
2748
+ width: 90px;
2749
+ border-radius: 50%;
2750
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
2751
+ }
2752
+
2753
+ .avatar img {
2754
+ width: 100%;
2755
+ height: 100%;
2756
+ border-radius: 50%;
2757
+ border: 3px solid white;
2758
+ }
2759
+
2760
+ .user-info {
2761
+ display: flex;
2762
+ flex-direction: column;
2763
+ align-items: flex-start;
2764
+ gap: 7px;
2765
+ margin-top: 10px;
2766
+ }
2767
+
2768
+ .name-badge {
2769
+ display: flex;
2770
+ align-items: center;
2771
+ height: 30px;
2772
+ background-color: ${bgColor[0]};
2773
+ border-radius: 25px;
2774
+ color: white;
2775
+ padding: 0 10px;
2776
+ border: solid 2px white;
2777
+ overflow: hidden;
2778
+ }
2779
+
2780
+ .name-badge span {
2781
+ max-width: 100px;
2782
+ white-space: nowrap;
2783
+ text-overflow: ellipsis;
2784
+ overflow: hidden;
2785
+ font-weight: bold;
2786
+ font-size: 12px;
2787
+ }
2788
+
2789
+ .accompany {
2790
+ display: flex;
2791
+ gap: 5px;
2792
+ align-items: center;
2793
+ height: 25px;
2794
+ background-color: ${bgColor[0]};
2795
+ border-radius: 25px;
2796
+ border: solid 2px white;
2797
+ overflow: hidden;
2798
+ }
2799
+
2800
+ .master-avatar {
2801
+ width: 25px;
2802
+ height: 25px;
2803
+ border-radius: 50%;
2804
+ background: url("${masterAvatarUrl}") no-repeat center;
2805
+ background-size: cover;
2806
+ }
2807
+
2808
+ .accompany span {
2809
+ max-width: 85px;
2810
+ white-space: nowrap;
2811
+ text-overflow: ellipsis;
2812
+ overflow: hidden;
2813
+ color: white;
2814
+ font-size: 10px;
2815
+ font-weight: bold;
2816
+ margin-right: 5px;
2817
+ }
2818
+
2819
+ .desc {
2820
+ margin-bottom: 10px;
2821
+ font-size: 16px;
2822
+ font-weight: bold;
2823
+ font-style: italic;
2824
+ color: #333;
2825
+ }
2826
+
2827
+ .captain {
2828
+ width: 175px;
2829
+ height: 175px;
2830
+ background: url("${captainImgUrl}") no-repeat center;
2831
+ background-size: cover;
2832
+ }
2833
+ </style>
2834
+ </head>
2835
+
2836
+ <body>
2837
+ <div class="bg">
2838
+ <div class="baseplate">
2839
+ <div class="info">
2840
+ <div class="user">
2841
+ <div class="avatar">
2842
+ <img src="${face}" alt="用户头像">
2843
+ </div>
2844
+ <div class="user-info">
2845
+ <div class="name-badge">
2846
+ <span>${uname}</span>
2847
+ </div>
2848
+ <div class="accompany">
2849
+ <div class="master-avatar"></div><span>${isAdmin ? "房管" : masterName}</span>
2850
+ </div>
2851
+ </div>
2852
+ </div>
2853
+ <div class="desc">
2854
+ ${desc[guardLevel]()}
2855
+ </div>
2856
+ </div>
2857
+ <div class="captain"></div>
2858
+ </div>
2859
+ </div>
2860
+ </body>
2861
+
2862
+ </html>
2863
+ `;
2864
+ return await withRetry(() => this.imgHandler(html)).catch((e) => {
2865
+ throw new Error(`生成图片失败!错误: ${e.toString()}`);
2866
+ });
3178
2867
  }
3179
- async sendPrivateMsg(content) {
3180
- if (this.config.master.enable) {
3181
- if (this.privateBot?.status !== koishi.Universal.Status.ONLINE) {
3182
- this.logger.warn(`${this.privateBot.platform} 机器人未初始化,暂时无法推送`);
3183
- return;
2868
+ richTextParser(rt, title) {
2869
+ const richText = rt.reduce((accumulator, currentValue) => {
2870
+ if (currentValue.emoji) return `${accumulator}<img style="width:17px; height:17px;" src="${currentValue.emoji.icon_url}"/>`;
2871
+ return accumulator + currentValue.text;
2872
+ }, "");
2873
+ if (this.config.filter.enable) {
2874
+ if (this.config.filter.regex) {
2875
+ if (new RegExp(this.config.filter.regex).test(richText)) throw new Error("出现关键词,屏蔽该动态");
3184
2876
  }
3185
- if (this.config.master.masterAccountGuildId) await this.privateBot.sendPrivateMessage(this.config.master.masterAccount, content, this.config.master.masterAccountGuildId);
3186
- else await this.privateBot.sendPrivateMessage(this.config.master.masterAccount, content);
2877
+ if (this.config.filter.keywords.length !== 0 && this.config.filter.keywords.some((keyword) => richText.includes(keyword))) throw new Error("出现关键词,屏蔽该动态");
3187
2878
  }
2879
+ const text = richText.replace(/\n/g, "<br>");
2880
+ return `
2881
+ <div class="card-details">
2882
+ ${title ? `<h1 class="dyn-title">${title}</h1>` : ""}
2883
+ ${text}
2884
+ </div>
2885
+ `;
3188
2886
  }
3189
- async sendPrivateMsgAndRebootService() {
3190
- if (this.rebootCount >= 3) {
3191
- this.logger.error("已重启插件3次,请检查机器人状态后使用 `bn start` 启动插件");
3192
- await this.sendPrivateMsg("已重启插件3次,请检查机器人状态后使用 `bn start` 启动插件");
3193
- await this.ctx["bilibili-notify"].disposePlugin();
3194
- return;
3195
- }
3196
- this.rebootCount++;
3197
- this.logger.info("插件出现未知错误,正在重启插件");
3198
- if (await this.ctx["bilibili-notify"].restartPlugin()) this.logger.info("插件重启成功");
3199
- else {
3200
- this.logger.error("插件重启失败,请检查机器人状态后使用 `bn start` 启动插件");
3201
- await this.sendPrivateMsg("插件重启失败,请检查机器人状态后使用 `bn start` 启动插件");
3202
- await this.ctx["bilibili-notify"].disposePlugin();
2887
+ async generateDynamicImg(data, { cardColorStart = this.config.cardColorStart, cardColorEnd = this.config.cardColorEnd, cardBasePlateColor = this.config.cardBasePlateColor, cardBasePlateBorder = this.config.cardBasePlateBorder } = {}) {
2888
+ const module_author = data.modules.module_author;
2889
+ const avatarUrl = module_author.face;
2890
+ const upName = module_author.name;
2891
+ let pubTime = this.unixTimestampToString(module_author.pub_ts);
2892
+ let dynamicCardUrl;
2893
+ let dynamicCardId;
2894
+ let dynamicCardColor;
2895
+ if (module_author.decorate) {
2896
+ dynamicCardUrl = module_author.decorate.card_url;
2897
+ dynamicCardId = module_author.decorate.fan.num_str;
2898
+ dynamicCardColor = module_author.decorate.fan.color;
3203
2899
  }
3204
- }
3205
- async sendPrivateMsgAndStopService() {
3206
- await this.sendPrivateMsg("插件发生未知错误,请检查机器人状态后使用 `bn start` 启动插件");
3207
- this.logger.error("插件发生未知错误,请检查机器人状态后使用 `bn start` 启动插件");
3208
- await this.ctx["bilibili-notify"].disposePlugin();
3209
- }
3210
- async sendMessageWithRetry(bot, channelId, content) {
3211
- withRetry(async () => await bot.sendMessage(channelId, content), 1).catch(async (e) => {
3212
- if (e.message === "this._request is not a function") {
3213
- this.ctx.setTimeout(async () => {
3214
- await this.sendMessageWithRetry(bot, channelId, content);
3215
- }, 2e3);
3216
- return;
2900
+ const module_stat = data.modules.module_stat;
2901
+ const comment = module_stat.comment.count;
2902
+ const forward = module_stat.forward.count;
2903
+ const like = module_stat.like.count;
2904
+ const topic = data.modules.module_dynamic.topic ? data.modules.module_dynamic.topic.name : "";
2905
+ const getDynamicMajor = async (dynamic, forward$1) => {
2906
+ let main$1 = "";
2907
+ let forwardInfo;
2908
+ const basicDynamic = () => {
2909
+ const module_dynamic = dynamic.modules.module_dynamic;
2910
+ if (module_dynamic?.desc?.rich_text_nodes) {
2911
+ const content = this.richTextParser(module_dynamic.desc.rich_text_nodes);
2912
+ main$1 += content;
2913
+ }
2914
+ if (module_dynamic?.major?.opus?.summary?.rich_text_nodes) {
2915
+ const content = this.richTextParser(module_dynamic.major.opus.summary.rich_text_nodes, module_dynamic.major.opus.title);
2916
+ main$1 += content;
2917
+ }
2918
+ let major = "";
2919
+ const arrowImg = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "img/arrow.png"));
2920
+ if (module_dynamic?.major?.opus?.pics) {
2921
+ if (module_dynamic.major.opus.pics.length === 1) if (module_dynamic.major.opus.pics[0].height > 3e3) major += `
2922
+ <div class="single-photo-container">
2923
+ <img class="single-photo-item" src="${module_dynamic.major.opus.pics[0].url}"/>
2924
+ <div class="single-photo-mask">
2925
+ <span class="single-photo-mask-text">点击链接浏览全部</span>
2926
+ </div>
2927
+ <img class="single-photo-mask-arrow" src="${arrowImg}"/>
2928
+ </div>
2929
+ `;
2930
+ else major += `
2931
+ <div class="single-photo-container">
2932
+ <img class="single-photo-item" src="${module_dynamic.major.opus.pics[0].url}"/>
2933
+ </div>
2934
+ `;
2935
+ else if (module_dynamic.major.opus.pics.length === 4) major += module_dynamic.major.opus.pics.reduce((acc, cV) => {
2936
+ return `${acc}<img class="four-photo-item" src="${cV.url}"/>`;
2937
+ }, "");
2938
+ else major += module_dynamic.major.opus.pics.reduce((acc, cV) => {
2939
+ return `${acc}<img class="photo-item" src="${cV.url}"/>`;
2940
+ }, "");
2941
+ main$1 += `
2942
+ <div class="card-major">
2943
+ ${major}
2944
+ </div>
2945
+ `;
2946
+ }
2947
+ };
2948
+ switch (dynamic.type) {
2949
+ case DYNAMIC_TYPE_WORD:
2950
+ case DYNAMIC_TYPE_DRAW:
2951
+ case DYNAMIC_TYPE_FORWARD:
2952
+ basicDynamic();
2953
+ if (dynamic.type === DYNAMIC_TYPE_FORWARD) {
2954
+ if (this.config.filter.enable && this.config.filter.forward) throw new Error("已屏蔽转发动态");
2955
+ const forward_module_author = dynamic.orig.modules.module_author;
2956
+ const forwardUserAvatarUrl = forward_module_author.face;
2957
+ const forwardUserName = forward_module_author.name;
2958
+ const [forwardMain, forwardInfo$1] = await getDynamicMajor(dynamic.orig, true);
2959
+ main$1 += `
2960
+ <div class="card-forward">
2961
+ <div class="forward-userinfo">
2962
+ <img class="forward-avatar" src="${forwardUserAvatarUrl}" alt="avatar">
2963
+ <span class="forward-username">${forwardUserName} ${forwardInfo$1 ? forwardInfo$1 : ""}</span>
2964
+ </div>
2965
+ <div class="forward-main">
2966
+ ${forwardMain}
2967
+ </div>
2968
+ </div>
2969
+ `;
2970
+ }
2971
+ if (dynamic.modules.module_dynamic.additional) {
2972
+ const additional = dynamic.modules.module_dynamic.additional;
2973
+ switch (additional.type) {
2974
+ case ADDITIONAL_TYPE_RESERVE: {
2975
+ const reserve = additional.reserve;
2976
+ let button;
2977
+ if (reserve.button.uncheck.text === "已结束") button = `
2978
+ <button class="reserve-button-end">
2979
+ <span>${reserve.button.uncheck.text}</span>
2980
+ </button>
2981
+ `;
2982
+ else button = `
2983
+ <button class="reserve-button-ing">
2984
+ <svg class="bili-dyn-card-reserve__action__icon" style="width: 16px; height: 16px;"
2985
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
2986
+ viewBox="0 0 16 16" width="16" height="16">
2987
+ <path
2988
+ d="M3.0000133333333334 6.999199999999999C3.0000133333333334 4.23776 5.2385866666666665 1.9991866666666667 8 1.9991866666666667C10.761433333333333 1.9991866666666667 13 4.23776 13 6.999199999999999L13 9.860933333333332C13 9.923533333333333 13.024899999999999 9.983633333333334 13.069199999999999 10.027933333333333L13.588366666666666 10.5471C14.389533333333333 11.348299999999998 13.914133333333334 12.734533333333333 12.754199999999999 12.8183C11.535999999999998 12.906233333333333 9.818933333333334 12.999199999999998 8 12.999199999999998C6.181073333333334 12.999199999999998 4.464026666666666 12.906233333333333 3.2458266666666664 12.8183C2.0859066666666664 12.734533333333333 1.61046 11.348299999999998 2.4116466666666665 10.547133333333333L2.93084 10.027933333333333C2.975133333333333 9.983633333333334 3.0000133333333334 9.923533333333333 3.0000133333333334 9.860933333333332L3.0000133333333334 6.999199999999999zM8 2.9991866666666667C5.790873333333334 2.9991866666666667 4.000013333333333 4.790046666666666 4.000013333333333 6.999199999999999L4.000013333333333 9.860933333333332C4.000013333333333 10.1888 3.8697733333333333 10.5032 3.6379466666666667 10.735033333333334L3.1187466666666666 11.254233333333334C2.911966666666667 11.461 3.0317600000000002 11.800199999999998 3.317833333333333 11.820899999999998C4.5211266666666665 11.907766666666667 6.212726666666666 11.999199999999998 8 11.999199999999998C9.787266666666666 11.999199999999998 11.4789 11.907733333333333 12.682199999999998 11.820899999999998C12.968233333333332 11.800199999999998 13.088033333333332 11.461 12.881266666666665 11.254233333333334L12.362066666666665 10.735033333333334C12.130233333333333 10.5032 12 10.1888 12 9.860933333333332L12 6.999199999999999C12 4.790046666666666 10.209166666666667 2.9991866666666667 8 2.9991866666666667z"
2989
+ fill="currentColor"></path>
2990
+ <path
2991
+ d="M8.720066666666666 2.0260466666666668C8.720066666666666 2.42372 8.397666666666666 2.746093333333333 8 2.746093333333333C7.602333333333332 2.746093333333333 7.279933333333333 2.42372 7.279933333333333 2.0260466666666668C7.279933333333333 1.6283666666666667 7.602333333333332 1.3059866666666666 8 1.3059866666666666C8.397666666666666 1.3059866666666666 8.720066666666666 1.6283666666666667 8.720066666666666 2.0260466666666668z"
2992
+ fill="currentColor"></path>
2993
+ <path
2994
+ d="M6.791266666666666 12.499199999999998C6.791266666666666 13.173966666666667 7.335266666666667 13.715866666666665 8 13.715866666666665C8.664766666666665 13.715866666666665 9.208733333333333 13.173966666666667 9.208733333333333 12.499199999999998L10.208733333333333 12.499199999999998C10.208733333333333 13.720566666666667 9.2227 14.715866666666665 8 14.715866666666665C6.777346666666666 14.715866666666665 5.791273333333333 13.720566666666667 5.791273333333333 12.499199999999998L6.791266666666666 12.499199999999998z"
2995
+ fill="currentColor"></path>
2996
+ </svg>
2997
+ <span>${reserve.button.uncheck.text}</span>
2998
+ </button>
2999
+ `;
3000
+ main$1 += `
3001
+ <div class="card-reserve">
3002
+ <div class="reserve-main">
3003
+ <div class="reserve-title">
3004
+ ${reserve.title}
3005
+ </div>
3006
+ <div class="reserve-desc">
3007
+ <div class="reserve-info">
3008
+ <span class="reserve-time">${reserve.desc1.text}</span>
3009
+ <span class="reserve-num">${reserve.desc2.text}</span>
3010
+ </div>
3011
+ ${reserve.desc3 ? `<div class="reserve-prize">
3012
+ <svg class="bili-dyn-card-reserve__lottery__icon"
3013
+ style="width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg"
3014
+ xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" width="16"
3015
+ height="16">
3016
+ <path
3017
+ d="M2.99998 7.785666666666666C3.2761266666666664 7.785666666666666 3.49998 8.0095 3.49998 8.285666666666666L3.49998 12.285666666666666C3.49998 12.719566666666667 3.8517599999999996 13.071333333333332 4.285693333333333 13.071333333333332L11.714266666666667 13.071333333333332C12.1482 13.071333333333332 12.5 12.719566666666667 12.5 12.285666666666666L12.5 8.285666666666666C12.5 8.0095 12.723833333333333 7.785666666666666 13 7.785666666666666C13.276133333333334 7.785666666666666 13.5 8.0095 13.5 8.285666666666666L13.5 12.285666666666666C13.5 13.271866666666668 12.7005 14.071333333333332 11.714266666666667 14.071333333333332L4.285693333333333 14.071333333333332C3.2994733333333333 14.071333333333332 2.49998 13.271866666666668 2.49998 12.285666666666666L2.49998 8.285666666666666C2.49998 8.0095 2.7238399999999996 7.785666666666666 2.99998 7.785666666666666z"
3018
+ fill="currentColor"></path>
3019
+ <path
3020
+ d="M1.9285533333333333 5.857139999999999C1.9285533333333333 5.107613333333333 2.5361666666666665 4.5 3.285693333333333 4.5L12.714266666666667 4.5C13.463799999999999 4.5 14.071399999999999 5.107613333333333 14.071399999999999 5.857139999999999L14.071399999999999 7.134066666666667C14.071399999999999 7.793799999999999 13.590066666666667 8.373766666666667 12.905000000000001 8.4432C12.058933333333332 8.528966666666665 10.470166666666666 8.642866666666666 8 8.642866666666666C5.529819999999999 8.642866666666666 3.9410399999999997 8.528966666666665 3.09498 8.4432C2.4099066666666666 8.373766666666667 1.9285533333333333 7.793799999999999 1.9285533333333333 7.134066666666667L1.9285533333333333 5.857139999999999zM3.285693333333333 5.5C3.088453333333333 5.5 2.9285533333333333 5.6599 2.9285533333333333 5.857139999999999L2.9285533333333333 7.134066666666667C2.9285533333333333 7.3082 3.0432666666666663 7.432833333333333 3.1958066666666665 7.4483C4.00544 7.530366666666667 5.560420000000001 7.6428666666666665 8 7.6428666666666665C10.439566666666666 7.6428666666666665 11.994533333333333 7.530366666666667 12.804133333333333 7.4483C12.9567 7.432833333333333 13.071399999999999 7.3082 13.071399999999999 7.134066666666667L13.071399999999999 5.857139999999999C13.071399999999999 5.6599 12.911499999999998 5.5 12.714266666666667 5.5L3.285693333333333 5.5z"
3021
+ fill="currentColor"></path>
3022
+ <path
3023
+ d="M4.357126666666666 3.5714733333333335C4.357126666666666 2.506353333333333 5.220573333333333 1.6429066666666667 6.285693333333333 1.6429066666666667C7.350833333333332 1.6429066666666667 8.214266666666667 2.506353333333333 8.214266666666667 3.5714733333333335L8.214266666666667 5.500046666666666L6.285693333333333 5.500046666666666C5.220573333333333 5.500046666666666 4.357126666666666 4.636593333333333 4.357126666666666 3.5714733333333335zM6.285693333333333 2.6429066666666667C5.77286 2.6429066666666667 5.357126666666667 3.0586399999999996 5.357126666666667 3.5714733333333335C5.357126666666667 4.084313333333333 5.77286 4.500046666666666 6.285693333333333 4.500046666666666L7.214266666666667 4.500046666666666L7.214266666666667 3.5714733333333335C7.214266666666667 3.0586399999999996 6.798533333333333 2.6429066666666667 6.285693333333333 2.6429066666666667z"
3024
+ fill="currentColor"></path>
3025
+ <path
3026
+ d="M7.785666666666666 3.5714733333333335C7.785666666666666 2.506353333333333 8.649133333333332 1.6429066666666667 9.714266666666667 1.6429066666666667C10.779399999999999 1.6429066666666667 11.642866666666666 2.506353333333333 11.642866666666666 3.5714733333333335C11.642866666666666 4.636593333333333 10.779399999999999 5.500046666666666 9.714266666666667 5.500046666666666L7.785666666666666 5.500046666666666L7.785666666666666 3.5714733333333335zM9.714266666666667 2.6429066666666667C9.201433333333332 2.6429066666666667 8.785666666666666 3.0586399999999996 8.785666666666666 3.5714733333333335L8.785666666666666 4.500046666666666L9.714266666666667 4.500046666666666C10.2271 4.500046666666666 10.642866666666666 4.084313333333333 10.642866666666666 3.5714733333333335C10.642866666666666 3.0586399999999996 10.2271 2.6429066666666667 9.714266666666667 2.6429066666666667z"
3027
+ fill="currentColor"></path>
3028
+ <path
3029
+ d="M8 3.7856466666666666C8.276133333333332 3.7856466666666666 8.5 4.009499999999999 8.5 4.285646666666667L8.5 13.142800000000001C8.5 13.418933333333332 8.276133333333332 13.642800000000001 8 13.642800000000001C7.723833333333333 13.642800000000001 7.5 13.418933333333332 7.5 13.142800000000001L7.5 4.285646666666667C7.5 4.009499999999999 7.723833333333333 3.7856466666666666 8 3.7856466666666666z"
3030
+ fill="currentColor"></path>
3031
+ </svg>
3032
+ <span>${reserve.desc3.text}</span>
3033
+ <svg style="width: 12px; height: 12px;" xmlns="http://www.w3.org/2000/svg"
3034
+ xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 12 12" width="12"
3035
+ height="12">
3036
+ <path
3037
+ d="M4.359835 1.609835C4.21339 1.756285 4.21339 1.99372 4.359835 2.140165L8.0429 5.823225C8.140525 5.920875 8.140525 6.079125 8.0429 6.176775L4.359835 9.859825C4.21339 10.006275 4.21339 10.243725 4.359835 10.390175C4.506285 10.5366 4.743725 10.5366 4.89017 10.390175L8.573225 6.7071C8.96375 6.316575 8.96375 5.683425 8.573225 5.2929L4.89017 1.609835C4.743725 1.46339 4.506285 1.46339 4.359835 1.609835z"
3038
+ fill="currentColor"></path>
3039
+ </svg>
3040
+ </div>` : ""}
3041
+ </div>
3042
+ </div>
3043
+ <div class="reserve-button">
3044
+ ${button}
3045
+ </div>
3046
+ </div>
3047
+ `;
3048
+ }
3049
+ }
3050
+ }
3051
+ break;
3052
+ case DYNAMIC_TYPE_AV: {
3053
+ basicDynamic();
3054
+ const archive = dynamic.modules.module_dynamic.major.archive;
3055
+ if (archive.badge.text === "投稿视频") if (forward$1) forwardInfo = "投稿了视频";
3056
+ else pubTime = `${pubTime} · 投稿了视频`;
3057
+ main$1 += `
3058
+ <div class="card-video">
3059
+ <div class="video-cover">
3060
+ <img src="${archive.cover}"
3061
+ alt="">
3062
+ <div class="cover-mask"></div>
3063
+ <span>${archive.duration_text}</span>
3064
+ </div>
3065
+ <div class="video-info">
3066
+ <div class="video-info-header">
3067
+ <div class="video-title">
3068
+ ${archive.title}
3069
+ </div>
3070
+ <div class="video-introduction">
3071
+ ${archive.desc}
3072
+ </div>
3073
+ </div>
3074
+ <div class="video-stat">
3075
+ <div class="video-stat-item">
3076
+ <svg style="width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg"
3077
+ xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" width="16"
3078
+ height="16">
3079
+ <path
3080
+ d="M8 3.3320333333333334C6.321186666666667 3.3320333333333334 4.855333333333333 3.4174399999999996 3.820593333333333 3.5013466666666666C3.1014733333333333 3.5596599999999996 2.5440733333333334 4.109013333333333 2.48 4.821693333333333C2.4040466666666664 5.666533333333334 2.333333333333333 6.780666666666666 2.333333333333333 7.998666666666666C2.333333333333333 9.216733333333334 2.4040466666666664 10.330866666666665 2.48 11.175699999999999C2.5440733333333334 11.888366666666666 3.1014733333333333 12.437733333333334 3.820593333333333 12.496066666666666C4.855333333333333 12.579933333333333 6.321186666666667 12.665333333333333 8 12.665333333333333C9.678999999999998 12.665333333333333 11.144933333333334 12.579933333333333 12.179733333333333 12.496033333333333C12.898733333333332 12.4377 13.456 11.888533333333331 13.520066666666667 11.176033333333333C13.595999999999998 10.331533333333333 13.666666666666666 9.217633333333332 13.666666666666666 7.998666666666666C13.666666666666666 6.779766666666667 13.595999999999998 5.665846666666667 13.520066666666667 4.821366666666666C13.456 4.108866666666666 12.898733333333332 3.55968 12.179733333333333 3.5013666666666663C11.144933333333334 3.417453333333333 9.678999999999998 3.3320333333333334 8 3.3320333333333334zM3.7397666666666667 2.50462C4.794879999999999 2.41906 6.288386666666666 2.3320333333333334 8 2.3320333333333334C9.7118 2.3320333333333334 11.2054 2.4190733333333334 12.260533333333331 2.5046399999999998C13.458733333333331 2.6018133333333333 14.407866666666665 3.5285199999999994 14.516066666666667 4.73182C14.593933333333332 5.597933333333334 14.666666666666666 6.7427 14.666666666666666 7.998666666666666C14.666666666666666 9.2547 14.593933333333332 10.399466666666665 14.516066666666667 11.2656C14.407866666666665 12.468866666666665 13.458733333333331 13.395566666666667 12.260533333333331 13.492766666666665C11.2054 13.578333333333333 9.7118 13.665333333333333 8 13.665333333333333C6.288386666666666 13.665333333333333 4.794879999999999 13.578333333333333 3.7397666666666667 13.492799999999999C2.541373333333333 13.395599999999998 1.5922066666666668 12.468633333333333 1.4840200000000001 11.265266666666665C1.4061199999999998 10.3988 1.3333333333333333 9.253866666666667 1.3333333333333333 7.998666666666666C1.3333333333333333 6.743533333333333 1.4061199999999998 5.598579999999999 1.4840200000000001 4.732153333333333C1.5922066666666668 3.5287466666666667 2.541373333333333 2.601793333333333 3.7397666666666667 2.50462z"
3081
+ fill="currentColor"></path>
3082
+ <path
3083
+ d="M9.8092 7.3125C10.338433333333333 7.618066666666666 10.338433333333333 8.382 9.809166666666666 8.687533333333333L7.690799999999999 9.910599999999999C7.161566666666666 10.216133333333332 6.5 9.8342 6.500006666666666 9.223066666666666L6.500006666666666 6.776999999999999C6.500006666666666 6.165873333333334 7.161566666666666 5.783913333333333 7.690799999999999 6.089479999999999L9.8092 7.3125z"
3084
+ fill="currentColor"></path>
3085
+ </svg>
3086
+ <span>${archive.stat.play}</span>
3087
+ </div>
3088
+ <div class="video-stat-item">
3089
+ <svg style="width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg"
3090
+ xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" width="16"
3091
+ height="16">
3092
+ <path
3093
+ d="M8 3.3320333333333334C6.321186666666667 3.3320333333333334 4.855333333333333 3.4174399999999996 3.820593333333333 3.5013466666666666C3.1014733333333333 3.5596599999999996 2.5440733333333334 4.109013333333333 2.48 4.821693333333333C2.4040466666666664 5.666533333333334 2.333333333333333 6.780666666666666 2.333333333333333 7.998666666666666C2.333333333333333 9.216733333333334 2.4040466666666664 10.330866666666665 2.48 11.175699999999999C2.5440733333333334 11.888366666666666 3.1014733333333333 12.437733333333334 3.820593333333333 12.496066666666666C4.855333333333333 12.579933333333333 6.321186666666667 12.665333333333333 8 12.665333333333333C9.678999999999998 12.665333333333333 11.144933333333334 12.579933333333333 12.179733333333333 12.496033333333333C12.898733333333332 12.4377 13.456 11.888533333333331 13.520066666666667 11.176033333333333C13.595999999999998 10.331533333333333 13.666666666666666 9.217633333333332 13.666666666666666 7.998666666666666C13.666666666666666 6.779766666666667 13.595999999999998 5.665846666666667 13.520066666666667 4.821366666666666C13.456 4.108866666666666 12.898733333333332 3.55968 12.179733333333333 3.5013666666666663C11.144933333333334 3.417453333333333 9.678999999999998 3.3320333333333334 8 3.3320333333333334zM3.7397666666666667 2.50462C4.794879999999999 2.41906 6.288386666666666 2.3320333333333334 8 2.3320333333333334C9.7118 2.3320333333333334 11.2054 2.4190733333333334 12.260533333333331 2.5046399999999998C13.458733333333331 2.6018133333333333 14.407866666666665 3.5285199999999994 14.516066666666667 4.73182C14.593933333333332 5.597933333333334 14.666666666666666 6.7427 14.666666666666666 7.998666666666666C14.666666666666666 9.2547 14.593933333333332 10.399466666666665 14.516066666666667 11.2656C14.407866666666665 12.468866666666665 13.458733333333331 13.395566666666667 12.260533333333331 13.492766666666665C11.2054 13.578333333333333 9.7118 13.665333333333333 8 13.665333333333333C6.288386666666666 13.665333333333333 4.794879999999999 13.578333333333333 3.7397666666666667 13.492799999999999C2.541373333333333 13.395599999999998 1.5922066666666668 12.468633333333333 1.4840200000000001 11.265266666666665C1.4061199999999998 10.3988 1.3333333333333333 9.253866666666667 1.3333333333333333 7.998666666666666C1.3333333333333333 6.743533333333333 1.4061199999999998 5.598579999999999 1.4840200000000001 4.732153333333333C1.5922066666666668 3.5287466666666667 2.541373333333333 2.601793333333333 3.7397666666666667 2.50462z"
3094
+ fill="currentColor"></path>
3095
+ <path
3096
+ d="M10.583333333333332 7.166666666666666L6.583333333333333 7.166666666666666C6.307193333333332 7.166666666666666 6.083333333333333 6.942799999999999 6.083333333333333 6.666666666666666C6.083333333333333 6.390526666666666 6.307193333333332 6.166666666666666 6.583333333333333 6.166666666666666L10.583333333333332 6.166666666666666C10.859466666666666 6.166666666666666 11.083333333333332 6.390526666666666 11.083333333333332 6.666666666666666C11.083333333333332 6.942799999999999 10.859466666666666 7.166666666666666 10.583333333333332 7.166666666666666z"
3097
+ fill="currentColor"></path>
3098
+ <path
3099
+ d="M11.583333333333332 9.833333333333332L7.583333333333333 9.833333333333332C7.3072 9.833333333333332 7.083333333333333 9.609466666666666 7.083333333333333 9.333333333333332C7.083333333333333 9.0572 7.3072 8.833333333333332 7.583333333333333 8.833333333333332L11.583333333333332 8.833333333333332C11.859466666666666 8.833333333333332 12.083333333333332 9.0572 12.083333333333332 9.333333333333332C12.083333333333332 9.609466666666666 11.859466666666666 9.833333333333332 11.583333333333332 9.833333333333332z"
3100
+ fill="currentColor"></path>
3101
+ <path
3102
+ d="M5.25 6.666666666666666C5.25 6.942799999999999 5.02614 7.166666666666666 4.75 7.166666666666666L4.416666666666666 7.166666666666666C4.140526666666666 7.166666666666666 3.9166666666666665 6.942799999999999 3.9166666666666665 6.666666666666666C3.9166666666666665 6.390526666666666 4.140526666666666 6.166666666666666 4.416666666666666 6.166666666666666L4.75 6.166666666666666C5.02614 6.166666666666666 5.25 6.390526666666666 5.25 6.666666666666666z"
3103
+ fill="currentColor"></path>
3104
+ <path
3105
+ d="M6.25 9.333333333333332C6.25 9.609466666666666 6.02614 9.833333333333332 5.75 9.833333333333332L5.416666666666666 9.833333333333332C5.140526666666666 9.833333333333332 4.916666666666666 9.609466666666666 4.916666666666666 9.333333333333332C4.916666666666666 9.0572 5.140526666666666 8.833333333333332 5.416666666666666 8.833333333333332L5.75 8.833333333333332C6.02614 8.833333333333332 6.25 9.0572 6.25 9.333333333333332z"
3106
+ fill="currentColor"></path>
3107
+ </svg>
3108
+ <span>${archive.stat.danmaku}</span>
3109
+ </div>
3110
+ </div>
3111
+ </div>
3112
+ </div>
3113
+ `;
3114
+ break;
3115
+ }
3116
+ case DYNAMIC_TYPE_LIVE: return [`${upName}发起了直播预约,我暂时无法渲染,请自行查看`];
3117
+ case DYNAMIC_TYPE_MEDIALIST: return [`${upName}分享了收藏夹,我暂时无法渲染,请自行查看`];
3118
+ case DYNAMIC_TYPE_PGC: return [`${upName}发布了剧集(番剧、电影、纪录片),我暂时无法渲染,请自行查看`];
3119
+ case DYNAMIC_TYPE_ARTICLE:
3120
+ if (this.config.filter.enable && this.config.filter.article) throw new Error("已屏蔽专栏动态");
3121
+ return [`${upName}投稿了新专栏,我暂时无法渲染,请自行查看`];
3122
+ case DYNAMIC_TYPE_MUSIC: return [`${upName}发行了新歌,我暂时无法渲染,请自行查看`];
3123
+ case DYNAMIC_TYPE_COMMON_SQUARE: return [`${upName}发布了装扮|剧集|点评|普通分享,我暂时无法渲染,请自行查看`];
3124
+ case DYNAMIC_TYPE_COURSES_SEASON: return [`${upName}发布了新课程,我暂时无法渲染,请自行查看`];
3125
+ case DYNAMIC_TYPE_UGC_SEASON: return [`${upName}更新了合集,我暂时无法渲染,请自行查看`];
3126
+ case DYNAMIC_TYPE_NONE: return [`${upName}发布了一条无效动态`];
3127
+ case DYNAMIC_TYPE_LIVE_RCMD: throw new Error("直播开播动态,不做处理");
3128
+ default: return [`${upName}发布了一条我无法识别的动态,请自行查看`];
3217
3129
  }
3218
- this.logger.error(`发送消息失败,群组ID: ${channelId},错误:${e.message}`);
3219
- await this.sendPrivateMsg(`发送消息失败,群组ID: ${channelId}`);
3130
+ return [main$1, forwardInfo];
3131
+ };
3132
+ const [main] = await getDynamicMajor(data, false);
3133
+ const html = `
3134
+ <!DOCTYPE html>
3135
+ <html>
3136
+ <head>
3137
+ <title>动态通知</title>
3138
+ <style>
3139
+ ${this.generateCardStyle(this.config.enableLargeFont, cardColorStart, cardColorEnd, cardBasePlateBorder, cardBasePlateColor, dynamicCardColor ?? "#FFFFFF")}
3140
+ </style>
3141
+ </head>
3142
+ <body>
3143
+ <div class="background">
3144
+ <div ${this.config.removeBorder ? "" : "class=\"base-plate\""}>
3145
+ <div class="card">
3146
+ <div class="card-body">
3147
+ <!-- 主播头像 -->
3148
+ <img class="anchor-avatar"
3149
+ src="${avatarUrl}"
3150
+ alt="主播头像">
3151
+ <div class="card-content">
3152
+ <div class="card-header">
3153
+ <div class="up-info">
3154
+ <div class="up-name" style="${module_author.vip.type !== 0 ? "color: #FB7299" : ""}">${upName}</div>
3155
+ <div class="pub-time">${pubTime}</div>
3156
+ </div>
3157
+ ${module_author.decorate ? `
3158
+ <div class="dress-up">
3159
+ <img src="${dynamicCardUrl}" />
3160
+ <span>${dynamicCardId}</span>
3161
+ </div>
3162
+ ` : ""}
3163
+ </div>
3164
+ <div class="card-topic">
3165
+ ${topic ? `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"
3166
+ class="bili-dyn-topic__icon">
3167
+ <path fill-rule="evenodd" clip-rule="evenodd"
3168
+ d="M11.4302 2.57458C11.4416 2.51023 11.4439 2.43974 11.4218 2.3528C11.3281 1.98196 10.9517 1.72037 10.5284 1.7527C10.432 1.76018 10.3599 1.78383 10.297 1.81376C10.2347 1.84398 10.1832 1.88155 10.1401 1.92465C10.1195 1.94485 10.1017 1.96692 10.0839 1.98897L10.0808 1.99289L10.0237 2.06277L9.91103 2.2033C9.76177 2.39141 9.61593 2.58191 9.47513 2.77556C9.33433 2.96936 9.19744 3.16585 9.06672 3.36638C9.00275 3.46491 8.93968 3.56401 8.87883 3.66461L8.56966 3.6613C8.00282 3.6574 7.43605 3.65952 6.86935 3.67034C6.80747 3.56778 6.74325 3.46677 6.67818 3.3664C6.54732 3.16585 6.41045 2.96934 6.26968 2.77568C6.12891 2.58186 5.98309 2.39134 5.83387 2.20322L5.72122 2.06268L5.66416 1.99279L5.6622 1.99036C5.64401 1.96783 5.62586 1.94535 5.60483 1.92454C5.56192 1.88144 5.51022 1.84388 5.44797 1.81364C5.38522 1.78386 5.31305 1.76006 5.21665 1.75273C4.80555 1.72085 4.4203 1.97094 4.32341 2.35273C4.30147 2.43968 4.30358 2.51018 4.31512 2.57453C4.32715 2.63859 4.34975 2.69546 4.38112 2.74649C4.39567 2.77075 4.41283 2.79315 4.42999 2.81557C4.43104 2.81694 4.43209 2.81831 4.43314 2.81968L4.48759 2.89122L4.59781 3.03355C4.74589 3.22242 4.89739 3.40905 5.05377 3.59254C5.09243 3.63788 5.13136 3.68306 5.17057 3.72785C4.99083 3.73681 4.81112 3.7467 4.63143 3.75756C4.41278 3.771 4.19397 3.78537 3.97547 3.80206L3.64757 3.82786L3.48362 3.84177L3.39157 3.85181C3.36984 3.8543 3.34834 3.8577 3.32679 3.86111C3.31761 3.86257 3.30843 3.86402 3.29921 3.86541C3.05406 3.90681 2.81526 3.98901 2.59645 4.10752C2.37765 4.22603 2.17867 4.38039 2.00992 4.56302C1.84117 4.74565 1.70247 4.95593 1.60144 5.18337C1.50025 5.4105 1.43687 5.65447 1.41362 5.90153C1.33103 6.77513 1.27663 7.6515 1.25742 8.5302C1.23758 9.40951 1.25835 10.2891 1.3098 11.1655C1.32266 11.3846 1.33738 11.6035 1.35396 11.8223L1.38046 12.1505L1.39472 12.3144L1.39658 12.335L1.39906 12.3583L1.40417 12.4048C1.40671 12.4305 1.41072 12.4558 1.41473 12.4811C1.41561 12.4866 1.41648 12.4922 1.41734 12.4977C1.45717 12.7449 1.53806 12.9859 1.65567 13.2074C1.77314 13.4289 1.92779 13.6304 2.11049 13.8022C2.29319 13.974 2.50441 14.1159 2.73329 14.2197C2.96201 14.3235 3.2084 14.3901 3.45836 14.4135C3.47066 14.415 3.48114 14.4159 3.49135 14.4167C3.49477 14.417 3.49817 14.4173 3.50159 14.4176L3.5425 14.4212L3.62448 14.4283L3.78843 14.4417L4.11633 14.4674C4.33514 14.4831 4.55379 14.4983 4.7726 14.5111C6.52291 14.6145 8.27492 14.6346 10.0263 14.5706C10.4642 14.5547 10.9019 14.5332 11.3396 14.5062C11.5584 14.4923 11.7772 14.4776 11.9959 14.4604L12.3239 14.434L12.4881 14.4196L12.5813 14.4093C12.6035 14.4065 12.6255 14.403 12.6474 14.3995C12.6565 14.3981 12.6655 14.3966 12.6746 14.3952C12.9226 14.3527 13.1635 14.2691 13.3844 14.1486C13.6052 14.0284 13.8059 13.8716 13.9759 13.6868C14.1463 13.5022 14.2861 13.2892 14.3874 13.0593C14.4381 12.9444 14.4793 12.8253 14.5108 12.7037C14.519 12.6734 14.5257 12.6428 14.5322 12.612L14.5421 12.566L14.55 12.5196C14.5556 12.4887 14.5607 12.4578 14.5641 12.4266C14.5681 12.3959 14.5723 12.363 14.5746 12.3373C14.6642 11.4637 14.7237 10.5864 14.7435 9.70617C14.764 8.825 14.7347 7.94337 14.6719 7.06715C14.6561 6.8479 14.6385 6.62896 14.6183 6.41033L14.5867 6.08246L14.5697 5.91853L14.5655 5.87758C14.5641 5.86445 14.5618 5.8473 14.5599 5.83231C14.5588 5.8242 14.5578 5.81609 14.5567 5.80797C14.5538 5.78514 14.5509 5.76229 14.5466 5.7396C14.5064 5.49301 14.4252 5.25275 14.3067 5.03242C14.1886 4.81208 14.0343 4.61153 13.8519 4.44095C13.6695 4.27038 13.4589 4.12993 13.2311 4.02733C13.0033 3.92458 12.7583 3.85907 12.5099 3.83636C12.4974 3.83492 12.4865 3.83394 12.4759 3.833C12.4729 3.83273 12.4698 3.83246 12.4668 3.83219L12.4258 3.82879L12.3438 3.82199L12.1798 3.80886L11.8516 3.78413C11.633 3.76915 11.4143 3.75478 11.1955 3.74288C10.993 3.73147 10.7904 3.72134 10.5878 3.71243L10.6914 3.59236C10.8479 3.40903 10.9992 3.22242 11.1473 3.03341L11.2576 2.89124L11.312 2.81971C11.3136 2.81773 11.3151 2.81575 11.3166 2.81377C11.3333 2.79197 11.3501 2.77013 11.3641 2.74653C11.3954 2.6955 11.418 2.63863 11.4302 2.57458ZM9.33039 5.49268C9.38381 5.16945 9.67705 4.95281 9.98536 5.00882L9.98871 5.00944C10.2991 5.06783 10.5063 5.37802 10.4524 5.70377L10.2398 6.99039L11.3846 6.9904C11.7245 6.9904 12 7.27925 12 7.63557C12 7.99188 11.7245 8.28073 11.3846 8.28073L10.0266 8.28059L9.7707 9.82911L11.0154 9.82913C11.3553 9.82913 11.6308 10.118 11.6308 10.4743C11.6308 10.8306 11.3553 11.1195 11.0154 11.1195L9.55737 11.1195L9.32807 12.5073C9.27465 12.8306 8.98141 13.0472 8.6731 12.9912L8.66975 12.9906C8.35937 12.9322 8.1522 12.622 8.20604 12.2962L8.40041 11.1195H6.89891L6.66961 12.5073C6.61619 12.8306 6.32295 13.0472 6.01464 12.9912L6.01129 12.9906C5.7009 12.9322 5.49374 12.622 5.54758 12.2962L5.74196 11.1195L4.61538 11.1195C4.27552 11.1195 4 10.8306 4 10.4743C4 10.118 4.27552 9.82913 4.61538 9.82913L5.95514 9.82911L6.21103 8.28059L4.98462 8.28073C4.64475 8.28073 4.36923 7.99188 4.36923 7.63557C4.36923 7.27925 4.64475 6.9904 4.98462 6.9904L6.42421 6.99039L6.67193 5.49268C6.72535 5.16945 7.01859 4.95281 7.3269 5.00882L7.33025 5.00944C7.64063 5.06783 7.8478 5.37802 7.79396 5.70377L7.58132 6.99039H9.08281L9.33039 5.49268ZM8.61374 9.82911L8.86963 8.28059H7.36813L7.11225 9.82911H8.61374Z"
3169
+ fill="currentColor"></path>
3170
+ </svg>
3171
+ ${topic}` : ""}
3172
+ </div>
3173
+ ${main}
3174
+ <div class="card-stat">
3175
+ <div class="stat-item">
3176
+ <svg style="width: 18px; height: 18px;" xmlns="http://www.w3.org/2000/svg"
3177
+ xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 18 18" width="18"
3178
+ height="18">
3179
+ <path
3180
+ d="M9.789075 2.2956175C8.97235 1.6308450000000003 7.74999 2.212005 7.74999 3.26506L7.74999 5.3915500000000005C6.642015000000001 5.5780325 5.3073725 6.040405 4.141735000000001 7.11143C2.809155 8.335825 1.751515 10.3041 1.45716 13.404099999999998C1.409905 13.9018 1.7595399999999999 14.22505 2.105415 14.317499999999999C2.442215 14.40755 2.8807175 14.314625 3.127745 13.92915C3.9664525 12.620249999999999 4.89282 11.894575 5.765827499999999 11.50585C6.4628049999999995 11.19545 7.14528 11.093125 7.74999 11.0959L7.74999 13.235025C7.74999 14.2881 8.97235 14.869250000000001 9.789075 14.2045L15.556199999999999 9.510425000000001C16.355075 8.860149999999999 16.355075 7.640124999999999 15.556199999999999 6.989840000000001L9.789075 2.2956175zM9.165099999999999 3.0768275000000003L14.895025 7.739050000000001C15.227975 7.980475 15.235775 8.468875 14.943874999999998 8.7142L9.17615 13.416800000000002C8.979474999999999 13.562024999999998 8.75 13.4269 8.75 13.227375000000002L8.75 10.638175C8.75 10.326975000000001 8.542125 10.134725 8.2544 10.1118C7.186765 10.02955 6.1563175 10.2037 5.150895 10.69295C4.14982 11.186925 3.2102250000000003 12.096525 2.573625 13.00995C2.54981 13.046975 2.52013 13.046025 2.5211725 12.986C2.8971525 10.0573 3.9373475 8.652125 4.807025 7.85305C5.87747 6.8694775 7.213197500000001 6.444867500000001 8.2272 6.33056C8.606525 6.287802500000001 8.74805 6.0849325 8.74805 5.7032275L8.74805 3.2615475C8.74805 3.0764875000000007 8.993175 2.9321925 9.165099999999999 3.0768275000000003z"
3181
+ fill="currentColor"></path>
3182
+ </svg>
3183
+ <span>${forward}</span>
3184
+ </div>
3185
+ <div class="stat-item">
3186
+ <svg style="width: 18px; height: 18px;" xmlns="http://www.w3.org/2000/svg"
3187
+ xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 18 18" width="18"
3188
+ height="18">
3189
+ <path
3190
+ d="M1.5625 7.875C1.5625 4.595807499999999 4.220807499999999 1.9375 7.5 1.9375L10.5 1.9375C13.779175 1.9375 16.4375 4.595807499999999 16.4375 7.875C16.4375 11.0504 13.944675 13.6435 10.809275 13.80405C10.097025 14.722974999999998 8.920875 15.880675 7.267095 16.331325C6.9735075 16.4113 6.704762499999999 16.286224999999998 6.55411 16.092325C6.40789 15.904149999999998 6.3561 15.634350000000001 6.4652449999999995 15.383025C6.72879 14.776249999999997 6.776465 14.221025000000001 6.7340175 13.761800000000001C3.8167675 13.387125 1.5625 10.894475 1.5625 7.875zM7.5 2.9375C4.773095 2.9375 2.5625 5.148095 2.5625 7.875C2.5625 10.502575 4.61524 12.651075000000002 7.2041924999999996 12.8038C7.4305875 12.817174999999999 7.619625000000001 12.981200000000001 7.664724999999999 13.203475C7.772575 13.734575000000001 7.8012 14.405425000000001 7.5884275 15.148399999999999C8.748325 14.6682 9.606 13.759825 10.151275 13.016475C10.24445 12.889475 10.392050000000001 12.8138 10.54955 12.812275C13.253575 12.785725 15.4375 10.58535 15.4375 7.875C15.4375 5.148095 13.226899999999999 2.9375 10.5 2.9375L7.5 2.9375z"
3191
+ fill="currentColor"></path>
3192
+ </svg>
3193
+ <span>${comment}</span>
3194
+ </div>
3195
+ <div class="stat-item">
3196
+ <svg style="width: 18px; height: 18px;" xmlns="http://www.w3.org/2000/svg"
3197
+ xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 18 18" width="18"
3198
+ height="18">
3199
+ <path
3200
+ d="M10.4511 2.2220125C10.218425 2.194885 10.002175 2.2953725 9.884175 2.433395C9.4264 2.9688525 9.321875 3.7501399999999996 8.978575 4.3581725C8.533574999999999 5.146395 8.1198 5.6213375 7.609775000000001 6.068507499999999C7.1751375 6.449565 6.738407499999999 6.697442499999999 6.3125 6.8050575L6.3125 14.854575C6.9198900000000005 14.868174999999999 7.572900000000001 14.876875 8.25 14.876875C9.936425 14.876875 11.367025 14.823325 12.33115 14.773699999999998C13.03235 14.737575 13.646025000000002 14.390075 13.966750000000001 13.81945C14.401900000000001 13.04535 14.9387 11.909650000000001 15.264174999999998 10.571200000000001C15.56665 9.327275 15.704699999999999 8.304325 15.766675 7.582224999999999C15.7988 7.208262500000001 15.50165 6.875019999999999 15.059999999999999 6.875019999999999L11.323274999999999 6.875019999999999C11.156575 6.875019999999999 11.000800000000002 6.791952499999999 10.907975 6.653499999999999C10.783725 6.468192500000001 10.82855 6.2670175 10.9037 6.07485C11.059 5.675084999999999 11.29355 4.9974475 11.382425000000001 4.4018275C11.470875000000001 3.80917 11.450999999999999 3.32219 11.212050000000001 2.86913C10.9571 2.3857825 10.66065 2.2464475 10.4511 2.2220125zM12.034300000000002 5.87502L15.059999999999999 5.87502C16.02035 5.87502 16.850875 6.64489 16.763 7.667825C16.697100000000002 8.435525 16.55155 9.5092 16.235825000000002 10.807500000000001C15.882625 12.259950000000002 15.3035 13.482225 14.838450000000002 14.309474999999999C14.32695 15.2194 13.377475 15.721150000000002 12.38255 15.772375C11.405125 15.822725 9.956949999999999 15.876875000000002 8.25 15.876875000000002C6.5961925 15.876875000000002 5.0846825 15.826025000000001 4.0136674999999995 15.77715C2.8370825 15.723474999999999 1.8519999999999999 14.850000000000001 1.725645 13.654824999999999C1.6404649999999998 12.849274999999999 1.5625 11.80725 1.5625 10.689375C1.5625 9.665175000000001 1.6279400000000002 8.736175 1.7045524999999997 7.998975C1.8351224999999998 6.7427075 2.9137075 5.87502 4.130655 5.87502L5.8125 5.87502C6.072015 5.87502 6.457235 5.7490675 6.9505175 5.316582499999999C7.377705000000001 4.942045 7.7193000000000005 4.5546075 8.107775 3.8665374999999997C8.492075 3.18585 8.605825 2.389785 9.124075 1.783595C9.452975 1.3988800000000001 9.99475 1.162025 10.5669 1.228745C11.16225 1.29816 11.717425 1.683875 12.09655 2.4025825000000003C12.478275 3.1262375000000002 12.474075 3.8618225 12.371500000000001 4.54938C12.302149999999997 5.0139949999999995 12.155425000000001 5.510059999999999 12.034300000000002 5.87502zM5.3125 14.82705L5.3125 6.875019999999999L4.130655 6.875019999999999C3.3792199999999997 6.875019999999999 2.77211 7.400795 2.6991975000000004 8.10235C2.6253525 8.812875 2.5625 9.70665 2.5625 10.689375C2.5625 11.762875 2.6374975 12.768475 2.7200975 13.549700000000001C2.7919925 14.229675 3.3521950000000005 14.74595 4.05924 14.778224999999999C4.4278775 14.795 4.849985 14.812050000000001 5.3125 14.82705z"
3201
+ fill="currentColor"></path>
3202
+ </svg>
3203
+ <span>${like}</span>
3204
+ </div>
3205
+ </div>
3206
+ </div>
3207
+ </div>
3208
+ </div>
3209
+ </div>
3210
+ </div>
3211
+ </body>
3212
+ </html>
3213
+ `;
3214
+ return await withRetry(() => this.imgHandler(html)).catch((e) => {
3215
+ throw new Error(`生成图片失败!错误: ${e.toString()}`);
3220
3216
  });
3221
3217
  }
3222
- async pushMessage(targets, content) {
3223
- const t = {};
3224
- for (const target of targets) {
3225
- const [platform, channleId] = target.split(":");
3226
- if (!t[platform]) t[platform] = [channleId];
3227
- else t[platform].push(channleId);
3228
- }
3229
- for (const platform of Object.keys(t)) {
3230
- const bots = [];
3231
- for (const bot of this.ctx.bots) if (bot.platform === platform) bots.push(bot);
3232
- let num = 0;
3233
- const sendMessageByBot = async (channelId, botIndex = 0, retry = 3e3) => {
3234
- if (!bots[botIndex]) {
3235
- this.logger.warn(`${platform} 没有配置对应机器人,无法推送`);
3236
- return;
3237
- }
3238
- if (bots[botIndex].status !== koishi.Universal.Status.ONLINE) {
3239
- if (retry >= 3e3 * 2 ** 5) {
3240
- this.logger.error(`${platform} 机器人未初始化,已重试5次,放弃推送`);
3241
- await this.sendPrivateMsg(`${platform} 机器人未初始化,已重试5次,放弃推送`);
3242
- return;
3243
- }
3244
- this.logger.warn(`${platform} 机器人未初始化,${retry / 1e3} 秒后重试`);
3245
- await this.ctx.sleep(retry);
3246
- await sendMessageByBot(channelId, botIndex, retry * 2);
3247
- return;
3248
- }
3249
- try {
3250
- await bots[botIndex].sendMessage(channelId, content);
3251
- num++;
3252
- await this.ctx.sleep(500);
3253
- } catch (e) {
3254
- this.logger.error(`发送消息失败:${e}`);
3255
- if (bots.length > 1) await sendMessageByBot(channelId, botIndex++);
3256
- }
3257
- };
3258
- for (const channelId of t[platform]) await sendMessageByBot(channelId);
3259
- this.logger.info(`成功推送 ${num} 条消息`);
3260
- }
3218
+ async generateWordCloudImg(words, masterName) {
3219
+ const wordcloudJS = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "static/wordcloud2.min.js"));
3220
+ const renderFunc = (0, node_url.pathToFileURL)((0, node_path.resolve)(__dirname, "static/render.js"));
3221
+ const html = `
3222
+ <!DOCTYPE html>
3223
+ <html lang="zh-CN">
3224
+
3225
+ <head>
3226
+ <meta charset="UTF-8">
3227
+ <title>高清词云展示</title>
3228
+ <style>
3229
+ * {
3230
+ margin: 0;
3231
+ padding: 0;
3232
+ box-sizing: border-box;
3233
+ font-family: "${this.config.font}", "Microsoft YaHei", "Source Han Sans", "Noto Sans CJK", sans-serif;
3234
+ }
3235
+
3236
+ html {
3237
+ width: 720px;
3238
+ height: 520px;
3239
+ }
3240
+
3241
+ .wordcloud-bg {
3242
+ width: 720px;
3243
+ height: 520px;
3244
+ background: linear-gradient(to right, #e0eafc, #cfdef3);
3245
+ font-family: 'Quicksand', sans-serif;
3246
+ display: flex;
3247
+ justify-content: center;
3248
+ align-items: center;
3249
+ }
3250
+
3251
+ .wordcloud-card {
3252
+ width: 700px;
3253
+ height: 500px;
3254
+ backdrop-filter: blur(10px);
3255
+ background: rgba(255, 255, 255, 0.25);
3256
+ border-radius: 20px;
3257
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
3258
+ padding: 20px;
3259
+ display: flex;
3260
+ flex-direction: column;
3261
+ align-items: center;
3262
+ justify-content: center;
3263
+ }
3264
+
3265
+ h2 {
3266
+ margin: 0 0 10px;
3267
+ color: #333;
3268
+ font-size: 24px;
3269
+ }
3270
+
3271
+ canvas {
3272
+ width: 100%;
3273
+ height: 100%;
3274
+ display: block;
3275
+ }
3276
+ </style>
3277
+ </head>
3278
+
3279
+ <body>
3280
+ <div class="wordcloud-bg">
3281
+ <div class="wordcloud-card">
3282
+ <h2>${masterName}直播弹幕词云</h2>
3283
+ <canvas id="wordCloudCanvas"></canvas>
3284
+ </div>
3285
+ </div>
3286
+
3287
+ <script src="${wordcloudJS}"><\/script>
3288
+ <script src="${renderFunc}"><\/script>
3289
+ <script>
3290
+ const canvas = document.getElementById('wordCloudCanvas');
3291
+ const ctx = canvas.getContext('2d');
3292
+
3293
+ // 获取 CSS 大小
3294
+ const style = getComputedStyle(canvas);
3295
+ const cssWidth = parseInt(style.width);
3296
+ const cssHeight = parseInt(style.height);
3297
+ const ratio = window.devicePixelRatio || 1;
3298
+
3299
+ // 设置 canvas 分辨率 & 缩放
3300
+ canvas.width = cssWidth * ratio;
3301
+ canvas.height = cssHeight * ratio;
3302
+ ctx.scale(ratio, ratio);
3303
+
3304
+ const words = ${JSON.stringify(words)}
3305
+
3306
+ renderAutoFitWordCloud(canvas, words, {
3307
+ maxFontSize: 60,
3308
+ minFontSize: 12,
3309
+ densityTarget: 0.3,
3310
+ weightExponent: 0.4
3311
+ });
3312
+ <\/script>
3313
+ </body>
3314
+
3315
+ </html>
3316
+ `;
3317
+ return await withRetry(() => this.imgHandler(html)).catch((e) => {
3318
+ throw new Error(`生成图片失败!错误: ${e.toString()}`);
3319
+ });
3261
3320
  }
3262
- async broadcastToTargets(uid, content, type) {
3263
- if (!this.pushArrMapInitializing) {
3264
- this.logger.warn(`推送对象信息尚未初始化完毕,等待5秒钟后重试推送,推送对象: ${uid}, 推送类型: ${PushTypeMsg[type]}`);
3265
- await this.ctx.sleep(5e3);
3266
- return this.broadcastToTargets(uid, content, type);
3267
- }
3268
- const record = this.pushArrMap.get(uid);
3269
- if (!record) return;
3270
- if (!(type === PushType.StartBroadcasting && record.liveAtAllArr?.length > 0 || type === PushType.Dynamic && (record.dynamicArr?.length > 0 || record.dynamicAtAllArr?.length > 0) || (type === PushType.Live || type === PushType.StartBroadcasting) && record.liveArr?.length > 0 || type === PushType.LiveGuardBuy && record.liveGuardBuyArr?.length > 0 || type === PushType.Superchat && record.superchatArr?.length > 0 || type === PushType.WordCloudAndLiveSummary && (record.wordcloudArr?.length > 0 || record.liveSummaryArr?.length > 0))) return;
3271
- this.logger.info(`推送对象: ${uid}, 推送类型: ${PushTypeMsg[type]}`);
3272
- if (type === PushType.StartBroadcasting && record.liveAtAllArr?.length > 0) {
3273
- this.logger.debug(`推送给 @全体,对象列表:${record.liveAtAllArr}`);
3274
- const atAllArr = structuredClone(record.liveAtAllArr);
3275
- await withRetry(() => this.pushMessage(atAllArr, koishi.h.at("all")), 1);
3276
- }
3277
- if (type === PushType.Dynamic && record.dynamicArr?.length > 0) {
3278
- if (record.dynamicAtAllArr?.length > 0) {
3279
- this.logger.debug(`推送动态给 @全体,对象列表:${record.dynamicAtAllArr}`);
3280
- const dynamicAtAllArr = structuredClone(record.dynamicAtAllArr);
3281
- await withRetry(() => this.pushMessage(dynamicAtAllArr, koishi.h.at("all")), 1);
3282
- }
3283
- this.logger.debug(`推送动态,对象列表:${record.dynamicArr}`);
3284
- const dynamicArr = structuredClone(record.dynamicArr);
3285
- await withRetry(() => this.pushMessage(dynamicArr, (0, koishi.h)("message", content)), 1);
3286
- }
3287
- if ((type === PushType.Live || type === PushType.StartBroadcasting) && record.liveArr?.length > 0) {
3288
- this.logger.debug(`推送直播,对象列表:${record.liveArr}`);
3289
- const liveArr = structuredClone(record.liveArr);
3290
- await withRetry(() => this.pushMessage(liveArr, (0, koishi.h)("message", content)), 1);
3291
- }
3292
- if (type === PushType.LiveGuardBuy && record.liveGuardBuyArr?.length > 0) {
3293
- this.logger.debug(`推送直播守护购买消息,对象列表:${record.liveGuardBuyArr}`);
3294
- const liveGuardBuyArr = structuredClone(record.liveGuardBuyArr);
3295
- await withRetry(() => this.pushMessage(liveGuardBuyArr, (0, koishi.h)("message", content)), 1);
3296
- }
3297
- if (type === PushType.Superchat && record.superchatArr?.length > 0) {
3298
- this.logger.debug(`推送 SC 消息,对象列表:${record.superchatArr}`);
3299
- const superchatArr = structuredClone(record.superchatArr);
3300
- await withRetry(() => this.pushMessage(superchatArr, (0, koishi.h)("message", content)), 1);
3301
- }
3302
- if (type === PushType.WordCloudAndLiveSummary) {
3303
- const wordcloudArr = structuredClone(record.wordcloudArr);
3304
- const liveSummaryArr = structuredClone(record.liveSummaryArr);
3305
- const wordcloudAndLiveSummaryArr = wordcloudArr.filter((item) => liveSummaryArr.includes(item));
3306
- const wordcloudOnlyArr = wordcloudArr.filter((item) => !liveSummaryArr.includes(item));
3307
- const liveSummaryOnlyArr = liveSummaryArr.filter((item) => !wordcloudArr.includes(item));
3308
- if (wordcloudAndLiveSummaryArr.length > 0) {
3309
- this.logger.debug(`推送词云和直播总结,对象列表:${wordcloudAndLiveSummaryArr}`);
3310
- const msgs = content.filter(Boolean);
3311
- if (msgs.length > 0) await withRetry(() => this.pushMessage(wordcloudAndLiveSummaryArr, (0, koishi.h)("message", msgs)), 1);
3312
- }
3313
- if (content[0] && wordcloudOnlyArr.length > 0) {
3314
- this.logger.debug(`推送词云,对象列表:${wordcloudOnlyArr}`);
3315
- await withRetry(() => this.pushMessage(wordcloudOnlyArr, (0, koishi.h)("message", content[0])), 1);
3316
- }
3317
- if (content[1] && liveSummaryOnlyArr.length > 0) {
3318
- this.logger.debug(`推送直播总结,对象列表:${liveSummaryOnlyArr}`);
3319
- await withRetry(() => this.pushMessage(liveSummaryOnlyArr, (0, koishi.h)("message", content[1])), 1);
3320
- }
3321
+ async getLiveStatus(time, liveStatus) {
3322
+ let titleStatus;
3323
+ let liveTime;
3324
+ let cover;
3325
+ switch (liveStatus) {
3326
+ case 0:
3327
+ titleStatus = "未直播";
3328
+ liveTime = "未开播";
3329
+ cover = true;
3330
+ break;
3331
+ case 1:
3332
+ titleStatus = "开播啦";
3333
+ liveTime = `开播时间:${time}`;
3334
+ cover = true;
3335
+ break;
3336
+ case 2:
3337
+ titleStatus = "正在直播";
3338
+ liveTime = `直播时长:${await this.getTimeDifference(time)}`;
3339
+ cover = false;
3340
+ break;
3341
+ case 3:
3342
+ titleStatus = "下播啦";
3343
+ liveTime = `开播时间:${time}`;
3344
+ cover = true;
3345
+ break;
3321
3346
  }
3347
+ return [
3348
+ titleStatus,
3349
+ liveTime,
3350
+ cover
3351
+ ];
3352
+ }
3353
+ async getTimeDifference(dateString) {
3354
+ const apiDateTime = luxon.DateTime.fromFormat(dateString, "yyyy-MM-dd HH:mm:ss", { zone: "UTC+8" });
3355
+ const diff = luxon.DateTime.now().diff(apiDateTime, [
3356
+ "years",
3357
+ "months",
3358
+ "days",
3359
+ "hours",
3360
+ "minutes",
3361
+ "seconds"
3362
+ ]);
3363
+ const { years, months, days, hours, minutes, seconds } = diff.toObject();
3364
+ const parts = [];
3365
+ if (years !== 0) parts.push(`${Math.abs(years)}年`);
3366
+ if (months !== 0) parts.push(`${Math.abs(months)}个月`);
3367
+ if (days !== 0) parts.push(`${Math.abs(days)}天`);
3368
+ if (hours !== 0) parts.push(`${Math.abs(hours)}小时`);
3369
+ if (minutes !== 0) parts.push(`${Math.abs(minutes)}分`);
3370
+ if (seconds !== 0) parts.push(`${Math.round(Math.abs(seconds))}秒`);
3371
+ const sign = diff.as("seconds") < 0 ? "-" : "";
3372
+ return parts.length > 0 ? `${sign}${parts.join("")}` : "0秒";
3373
+ }
3374
+ unixTimestampToString(timestamp) {
3375
+ const date = /* @__PURE__ */ new Date(timestamp * 1e3);
3376
+ return `${date.getFullYear()}年${`0${date.getMonth() + 1}`.slice(-2)}月${`0${date.getDate()}`.slice(-2)}日 ${`0${date.getHours()}`.slice(-2)}:${`0${date.getMinutes()}`.slice(-2)}:${`0${date.getSeconds()}`.slice(-2)}`;
3322
3377
  }
3323
3378
  };
3324
- (function(_BilibiliNotifyPush) {
3325
- _BilibiliNotifyPush.Config = koishi.Schema.object({
3379
+ (function(_BilibiliNotifyGenerateImg) {
3380
+ _BilibiliNotifyGenerateImg.Config = koishi.Schema.object({
3326
3381
  logLevel: koishi.Schema.number().required(),
3327
- master: koishi.Schema.object({
3382
+ filter: koishi.Schema.object({
3328
3383
  enable: koishi.Schema.boolean(),
3329
- platform: koishi.Schema.string(),
3330
- masterAccount: koishi.Schema.string(),
3331
- masterAccountGuildId: koishi.Schema.string()
3332
- })
3384
+ notify: koishi.Schema.boolean(),
3385
+ regex: koishi.Schema.string(),
3386
+ keywords: koishi.Schema.array(String),
3387
+ forward: koishi.Schema.boolean(),
3388
+ article: koishi.Schema.boolean()
3389
+ }),
3390
+ removeBorder: koishi.Schema.boolean(),
3391
+ cardColorStart: koishi.Schema.string(),
3392
+ cardColorEnd: koishi.Schema.string(),
3393
+ cardBasePlateColor: koishi.Schema.string(),
3394
+ cardBasePlateBorder: koishi.Schema.string(),
3395
+ enableLargeFont: koishi.Schema.boolean(),
3396
+ font: koishi.Schema.string(),
3397
+ hideDesc: koishi.Schema.boolean(),
3398
+ followerDisplay: koishi.Schema.boolean()
3333
3399
  });
3334
- })(BilibiliNotifyPush || (BilibiliNotifyPush = {}));
3335
- var push_default = BilibiliNotifyPush;
3400
+ })(BilibiliNotifyGenerateImg || (BilibiliNotifyGenerateImg = {}));
3401
+ var generate_img_default = BilibiliNotifyGenerateImg;
3336
3402
 
3337
3403
  //#endregion
3338
3404
  //#region src/api.ts
@@ -4018,132 +4084,68 @@ var BilibiliNotifyAPI = class extends koishi.Service {
4018
4084
  var api_default = BilibiliNotifyAPI;
4019
4085
 
4020
4086
  //#endregion
4021
- //#region src/database.ts
4022
- var database_exports = /* @__PURE__ */ __exportAll({
4023
- apply: () => apply$1,
4024
- name: () => name$1
4025
- });
4026
- const name$1 = "Database";
4027
- function apply$1(ctx) {
4028
- ctx.model.extend("loginBili", {
4029
- id: "unsigned",
4030
- bili_cookies: "text",
4031
- bili_refresh_token: "text",
4032
- dynamic_group_id: "string"
4033
- });
4034
- }
4035
-
4036
- //#endregion
4037
- //#region src/index.ts
4038
- const inject = [
4039
- "puppeteer",
4040
- "database",
4041
- "notifier",
4042
- "console"
4043
- ];
4044
- const name = "bilibili-notify";
4045
- const usage = `
4046
- <h1>Bilibili-Notify</h1>
4047
- <p>使用问题请加群咨询 801338523</p>
4048
-
4049
- ---
4050
-
4051
- 主人好呀~我是笨笨女仆小助手哒 (〃∀〃)♡
4052
- 专门帮主人管理 B 站订阅和直播推送的!
4053
- 女仆虽然笨笨的,但是会尽力不出错哦~
4054
- 主人,只要按照女仆的提示一步一步设置,女仆就可以乖乖帮您工作啦!
4055
-
4056
- 首先呢~请主人仔细阅读订阅相关的 subs 的填写说明 (>ω<)b
4057
- 【主人账号部分非必填】然后再告诉女仆您的 主人账号 (///▽///),并选择您希望女仆服务的平台~
4058
- 接着,请认真填写 主人的 ID 和 群组 ID,确保信息完全正确~
4059
- 这样女仆才能顺利找到您并准确汇报动态呢 (≧▽≦)
4060
-
4061
- 不用着急,女仆会一直在这里陪着您,一步一步完成设置~
4062
- 主人只要乖乖填好这些信息,就能让女仆变得超级听话、超级勤快啦 (>///<)♡
4063
-
4064
- 想要重新登录的话,只需要点击个人名片的“Bilibili”Logo哦~
4065
-
4066
- 主人~注意事项要仔细看呀 (>_<)♡
4067
- - 如果主人使用的是 onebot 机器人,平台名请填写 onebot,而不是 qq 哦~
4068
- - 同样的呀,如果是 onebot 机器人,请务必填写 onebot,不要写成 qq 哦~
4069
- - 女仆再提醒一次~onebot 机器人就填 onebot,千万不要写 qq 哦~
4070
-
4071
- 乖乖遵守这些规则,女仆才能顺利帮主人工作呢 (*>ω<)b
4072
-
4073
- ---
4074
- `;
4075
- let globalConfig;
4076
- var ServerManager = class extends koishi.Service {
4087
+ //#region src/server_manager.ts
4088
+ var BilibiliNotifyServerManager = class extends koishi.Service {
4077
4089
  servers = [];
4078
- constructor(ctx) {
4090
+ constructor(ctx, config) {
4079
4091
  super(ctx, "bilibili-notify");
4080
- const sysCom = ctx.command("bn", "bilibili-notify 插件运行相关指令", { permissions: ["authority:5"] });
4081
- sysCom.subcommand(".restart", "重启插件").usage("重启插件").example("bn restart").action(async () => {
4082
- if (await this.restartPlugin()) return "主人~女仆成功重启插件啦~乖乖继续为主人服务呢 (>ω<)♡";
4083
- return "主人呜呜 (;>_<) 女仆重启插件失败啦~请主人检查一下再试哦 (>ω<)♡";
4084
- });
4085
- sysCom.subcommand(".stop", "停止插件").usage("停止插件").example("bn stop").action(async () => {
4086
- if (await this.disposePlugin()) return "主人~女仆已经停止插件啦~休息一下先 (>ω<)♡";
4087
- return "主人呜呜 (;>_<) 女仆停止插件失败啦~请主人检查一下再试哦 (>ω<)♡";
4088
- });
4089
- sysCom.subcommand(".start", "启动插件").usage("启动插件").example("bn start").action(async () => {
4090
- if (await this.registerPlugin()) return "主人~女仆成功启动插件啦~准备好乖乖为主人工作呢 (>ω<)♡";
4091
- return "主人呜呜 (;>_<) 女仆启动插件失败啦~请主人检查一下再试哦 (>ω<)♡";
4092
- });
4092
+ this.logger.level = config.logLevel;
4093
+ this.config = config;
4093
4094
  }
4094
4095
  start() {
4095
4096
  if (!this.registerPlugin()) this.logger.error("主人呜呜 (;>_<) 女仆启动插件失败啦~请主人检查一下再试哦 (>ω<)♡");
4097
+ sys_default.call(this);
4096
4098
  }
4097
4099
  registerPlugin = () => {
4098
4100
  if (this.servers.length !== 0) return false;
4099
4101
  try {
4100
4102
  const ba = this.ctx.plugin(api_default, {
4101
- logLevel: globalConfig.logLevel,
4102
- userAgent: globalConfig.userAgent,
4103
- key: globalConfig.key,
4104
- ai: globalConfig.ai
4103
+ logLevel: this.config.logLevel,
4104
+ userAgent: this.config.userAgent,
4105
+ key: this.config.key,
4106
+ ai: this.config.ai
4105
4107
  });
4106
4108
  const gi = this.ctx.plugin(generate_img_default, {
4107
- logLevel: globalConfig.logLevel,
4108
- filter: globalConfig.filter,
4109
- removeBorder: globalConfig.removeBorder,
4110
- cardColorStart: globalConfig.cardColorStart,
4111
- cardColorEnd: globalConfig.cardColorEnd,
4112
- cardBasePlateColor: globalConfig.cardBasePlateColor,
4113
- cardBasePlateBorder: globalConfig.cardBasePlateBorder,
4114
- hideDesc: globalConfig.hideDesc,
4115
- enableLargeFont: globalConfig.enableLargeFont,
4116
- font: globalConfig.font,
4117
- followerDisplay: globalConfig.followerDisplay
4109
+ logLevel: this.config.logLevel,
4110
+ filter: this.config.filter,
4111
+ removeBorder: this.config.removeBorder,
4112
+ cardColorStart: this.config.cardColorStart,
4113
+ cardColorEnd: this.config.cardColorEnd,
4114
+ cardBasePlateColor: this.config.cardBasePlateColor,
4115
+ cardBasePlateBorder: this.config.cardBasePlateBorder,
4116
+ hideDesc: this.config.hideDesc,
4117
+ enableLargeFont: this.config.enableLargeFont,
4118
+ font: this.config.font,
4119
+ followerDisplay: this.config.followerDisplay
4118
4120
  });
4119
4121
  const ps = this.ctx.plugin(push_default, {
4120
- logLevel: globalConfig.logLevel,
4121
- master: globalConfig.master
4122
+ logLevel: this.config.logLevel,
4123
+ master: this.config.master
4122
4124
  });
4123
4125
  const dy = this.ctx.plugin(dynamic_default, {
4124
- logLevel: globalConfig.logLevel,
4125
- filter: globalConfig.filter,
4126
- dynamicUrl: globalConfig.dynamicUrl,
4127
- dynamicCron: globalConfig.dynamicCron,
4128
- pushImgsInDynamic: globalConfig.pushImgsInDynamic,
4129
- dynamicVideoUrlToBV: globalConfig.dynamicVideoUrlToBV
4126
+ logLevel: this.config.logLevel,
4127
+ filter: this.config.filter,
4128
+ dynamicUrl: this.config.dynamicUrl,
4129
+ dynamicCron: this.config.dynamicCron,
4130
+ pushImgsInDynamic: this.config.pushImgsInDynamic,
4131
+ dynamicVideoUrlToBV: this.config.dynamicVideoUrlToBV
4130
4132
  });
4131
4133
  const bl = this.ctx.plugin(live_default, {
4132
- logLevel: globalConfig.logLevel,
4133
- wordcloudStopWords: globalConfig.wordcloudStopWords,
4134
- ai: globalConfig.ai,
4135
- restartPush: globalConfig.restartPush,
4136
- pushTime: globalConfig.pushTime
4134
+ logLevel: this.config.logLevel,
4135
+ wordcloudStopWords: this.config.wordcloudStopWords,
4136
+ ai: this.config.ai,
4137
+ restartPush: this.config.restartPush,
4138
+ pushTime: this.config.pushTime
4137
4139
  });
4138
- const cr = this.ctx.plugin(core_default, {
4139
- logLevel: globalConfig.logLevel,
4140
- advancedSub: globalConfig.advancedSub,
4141
- subs: globalConfig.subs,
4142
- liveSummary: globalConfig.liveSummary,
4143
- customLiveStart: globalConfig.customLiveStart,
4144
- customLive: globalConfig.customLive,
4145
- customLiveEnd: globalConfig.customLiveEnd,
4146
- customGuardBuyImg: globalConfig.customGuardBuy
4140
+ const cr = this.ctx.plugin(sub_default, {
4141
+ logLevel: this.config.logLevel,
4142
+ advancedSub: this.config.advancedSub,
4143
+ subs: this.config.subs,
4144
+ liveSummary: this.config.liveSummary,
4145
+ customLiveStart: this.config.customLiveStart,
4146
+ customLive: this.config.customLive,
4147
+ customLiveEnd: this.config.customLiveEnd,
4148
+ customGuardBuyImg: this.config.customGuardBuy
4147
4149
  });
4148
4150
  this.servers.push(ba, gi, ps, dy, bl, cr);
4149
4151
  } catch (e) {
@@ -4180,10 +4182,50 @@ var ServerManager = class extends koishi.Service {
4180
4182
  });
4181
4183
  };
4182
4184
  };
4185
+ var server_manager_default = BilibiliNotifyServerManager;
4186
+
4187
+ //#endregion
4188
+ //#region src/index.ts
4189
+ const inject = [
4190
+ "puppeteer",
4191
+ "database",
4192
+ "notifier",
4193
+ "console"
4194
+ ];
4195
+ const name = "bilibili-notify";
4196
+ const usage = `
4197
+ <h1>Bilibili-Notify</h1>
4198
+ <p>使用问题请加群咨询 801338523</p>
4199
+
4200
+ ---
4201
+
4202
+ 主人好呀~我是笨笨女仆小助手哒 (〃∀〃)♡
4203
+ 专门帮主人管理 B 站订阅和直播推送的!
4204
+ 女仆虽然笨笨的,但是会尽力不出错哦~
4205
+ 主人,只要按照女仆的提示一步一步设置,女仆就可以乖乖帮您工作啦!
4206
+
4207
+ 首先呢~请主人仔细阅读订阅相关的 subs 的填写说明 (>ω<)b
4208
+ 【主人账号部分非必填】然后再告诉女仆您的 主人账号 (///▽///),并选择您希望女仆服务的平台~
4209
+ 接着,请认真填写 主人的 ID 和 群组 ID,确保信息完全正确~
4210
+ 这样女仆才能顺利找到您并准确汇报动态呢 (≧▽≦)
4211
+
4212
+ 不用着急,女仆会一直在这里陪着您,一步一步完成设置~
4213
+ 主人只要乖乖填好这些信息,就能让女仆变得超级听话、超级勤快啦 (>///<)♡
4214
+
4215
+ 想要重新登录的话,只需要点击个人名片的“Bilibili”Logo哦~
4216
+
4217
+ 主人~注意事项要仔细看呀 (>_<)♡
4218
+ - 如果主人使用的是 onebot 机器人,平台名请填写 onebot,而不是 qq 哦~
4219
+ - 同样的呀,如果是 onebot 机器人,请务必填写 onebot,不要写成 qq 哦~
4220
+ - 女仆再提醒一次~onebot 机器人就填 onebot,千万不要写 qq 哦~
4221
+
4222
+ 乖乖遵守这些规则,女仆才能顺利帮主人工作呢 (*>ω<)b
4223
+
4224
+ ---
4225
+ `;
4183
4226
  function apply(ctx, config) {
4184
- globalConfig = config;
4185
4227
  ctx.plugin(database_exports);
4186
- ctx.plugin(ServerManager);
4228
+ ctx.plugin(server_manager_default, config);
4187
4229
  ctx.plugin(BilibiliNotifyDataServer);
4188
4230
  ctx.console.addEntry({
4189
4231
  dev: (0, node_path.resolve)(__dirname, "../client/index.ts"),