koishi-plugin-bilibili-notify 3.0.0-alpha.2 → 3.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,55 +1,41 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
3
  const koishi_1 = require("koishi");
5
- const path_1 = require("path");
6
- const url_1 = require("url");
4
+ const luxon_1 = require("luxon");
5
+ const node_path_1 = require("node:path");
6
+ const node_url_1 = require("node:url");
7
7
  // 动态类型
8
- const DYNAMIC_TYPE_NONE = 'DYNAMIC_TYPE_NONE';
9
- const DYNAMIC_TYPE_FORWARD = 'DYNAMIC_TYPE_FORWARD';
10
- const DYNAMIC_TYPE_AV = 'DYNAMIC_TYPE_AV';
11
- const DYNAMIC_TYPE_PGC = 'DYNAMIC_TYPE_PGC';
12
- const DYNAMIC_TYPE_COURSES = 'DYNAMIC_TYPE_COURSES';
13
- const DYNAMIC_TYPE_WORD = 'DYNAMIC_TYPE_WORD';
14
- const DYNAMIC_TYPE_DRAW = 'DYNAMIC_TYPE_DRAW';
15
- const DYNAMIC_TYPE_ARTICLE = 'DYNAMIC_TYPE_ARTICLE';
16
- const DYNAMIC_TYPE_MUSIC = 'DYNAMIC_TYPE_MUSIC';
17
- const DYNAMIC_TYPE_COMMON_SQUARE = 'DYNAMIC_TYPE_COMMON_SQUARE';
18
- const DYNAMIC_TYPE_COMMON_VERTICAL = 'DYNAMIC_TYPE_COMMON_VERTICAL';
19
- const DYNAMIC_TYPE_LIVE = 'DYNAMIC_TYPE_LIVE';
20
- const DYNAMIC_TYPE_MEDIALIST = 'DYNAMIC_TYPE_MEDIALIST';
21
- const DYNAMIC_TYPE_COURSES_SEASON = 'DYNAMIC_TYPE_COURSES_SEASON';
22
- const DYNAMIC_TYPE_COURSES_BATCH = 'DYNAMIC_TYPE_COURSES_BATCH';
23
- const DYNAMIC_TYPE_AD = 'DYNAMIC_TYPE_AD';
24
- const DYNAMIC_TYPE_APPLET = 'DYNAMIC_TYPE_APPLET';
25
- const DYNAMIC_TYPE_SUBSCRIPTION = 'DYNAMIC_TYPE_SUBSCRIPTION';
26
- const DYNAMIC_TYPE_LIVE_RCMD = 'DYNAMIC_TYPE_LIVE_RCMD';
27
- const DYNAMIC_TYPE_BANNER = 'DYNAMIC_TYPE_BANNER';
28
- const DYNAMIC_TYPE_UGC_SEASON = 'DYNAMIC_TYPE_UGC_SEASON';
29
- const DYNAMIC_TYPE_SUBSCRIPTION_NEW = 'DYNAMIC_TYPE_SUBSCRIPTION_NEW';
8
+ const DYNAMIC_TYPE_NONE = "DYNAMIC_TYPE_NONE";
9
+ const DYNAMIC_TYPE_FORWARD = "DYNAMIC_TYPE_FORWARD";
10
+ const DYNAMIC_TYPE_AV = "DYNAMIC_TYPE_AV";
11
+ const DYNAMIC_TYPE_PGC = "DYNAMIC_TYPE_PGC";
12
+ const DYNAMIC_TYPE_WORD = "DYNAMIC_TYPE_WORD";
13
+ const DYNAMIC_TYPE_DRAW = "DYNAMIC_TYPE_DRAW";
14
+ const DYNAMIC_TYPE_ARTICLE = "DYNAMIC_TYPE_ARTICLE";
15
+ const DYNAMIC_TYPE_MUSIC = "DYNAMIC_TYPE_MUSIC";
16
+ const DYNAMIC_TYPE_COMMON_SQUARE = "DYNAMIC_TYPE_COMMON_SQUARE";
17
+ const DYNAMIC_TYPE_LIVE = "DYNAMIC_TYPE_LIVE";
18
+ const DYNAMIC_TYPE_MEDIALIST = "DYNAMIC_TYPE_MEDIALIST";
19
+ const DYNAMIC_TYPE_COURSES_SEASON = "DYNAMIC_TYPE_COURSES_SEASON";
20
+ const DYNAMIC_TYPE_LIVE_RCMD = "DYNAMIC_TYPE_LIVE_RCMD";
21
+ const DYNAMIC_TYPE_UGC_SEASON = "DYNAMIC_TYPE_UGC_SEASON";
30
22
  // 内容卡片类型
31
- /* const ADDITIONAL_TYPE_NONE = 'ADDITIONAL_TYPE_NONE'
32
- const ADDITIONAL_TYPE_PGC = 'ADDITIONAL_TYPE_PGC'
33
- const ADDITIONAL_TYPE_GOODS = 'ADDITIONAL_TYPE_GOODS'
34
- const ADDITIONAL_TYPE_VOTE = 'ADDITIONAL_TYPE_VOTE'
35
- const ADDITIONAL_TYPE_COMMON = 'ADDITIONAL_TYPE_COMMON'
36
- const ADDITIONAL_TYPE_MATCH = 'ADDITIONAL_TYPE_MATCH'
37
- const ADDITIONAL_TYPE_UP_RCMD = 'ADDITIONAL_TYPE_UP_RCMD'
38
- const ADDITIONAL_TYPE_UGC = 'ADDITIONAL_TYPE_UGC' */
39
- const ADDITIONAL_TYPE_RESERVE = 'ADDITIONAL_TYPE_RESERVE';
23
+ const ADDITIONAL_TYPE_RESERVE = "ADDITIONAL_TYPE_RESERVE";
40
24
  class GenerateImg extends koishi_1.Service {
41
- static inject = ['puppeteer', 'ba'];
25
+ static inject = ["puppeteer", "ba"];
42
26
  giConfig;
43
27
  constructor(ctx, config) {
44
- super(ctx, 'gi');
28
+ super(ctx, "gi");
45
29
  this.giConfig = config;
46
30
  }
47
- async generateLiveImg(data, username, userface, liveStatus /*0未开播 1刚开播 2已开播 3停止直播*/) {
31
+ async generateLiveImg(
32
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
33
+ data, username, userface, followerDisplay, liveStatus /*0未开播 1刚开播 2已开播 3停止直播*/) {
48
34
  const [titleStatus, liveTime, cover] = await this.getLiveStatus(data.live_time, liveStatus);
49
35
  // 加载字体
50
- const fontURL = (0, url_1.pathToFileURL)((0, path_1.resolve)(__dirname, 'font/HYZhengYuan-75W.ttf'));
36
+ const fontURL = (0, node_url_1.pathToFileURL)((0, node_path_1.resolve)(__dirname, "font/HYZhengYuan-75W.ttf"));
51
37
  // 卡片内容
52
- const html = `
38
+ const html = /* html */ `
53
39
  <!DOCTYPE html>
54
40
  <html>
55
41
  <head>
@@ -160,7 +146,7 @@ class GenerateImg extends koishi_1.Service {
160
146
  </head>
161
147
  <body>
162
148
  <div class="background">
163
- <div ${this.giConfig.removeBorder ? '' : 'class="base-plate"'}>
149
+ <div ${this.giConfig.removeBorder ? "" : 'class="base-plate"'}>
164
150
  <div class="card">
165
151
  <img src="${cover ? data.user_cover : data.keyframe}"
166
152
  alt="封面">
@@ -174,13 +160,25 @@ class GenerateImg extends koishi_1.Service {
174
160
  <span class="broadcast-message">${username}${titleStatus}</span>
175
161
  </div>
176
162
  </div>
177
- ${this.giConfig.hideDesc ? '' : `<p class="card-text">${data.description ? data.description : '这个主播很懒,什么都简介都没写'}</p>`}
163
+ ${this.giConfig.hideDesc ? "" : `<p class="card-text">${data.description ? data.description : "这个主播很懒,什么都简介都没写"}</p>`}
178
164
  <p class="card-link">
179
- ${liveStatus !== 3 ? `<span>人气:${data.online > 10000 ? `${(data.online / 10000).toFixed(1)}万` : data.online}</span>` : ''}
165
+ <span>人气:${data.online > 10000 ? `${(data.online / 10000).toFixed(1)}万` : data.online}</span>
180
166
  <span>分区名称:${data.area_name}</span>
181
167
  </p>
182
168
  <p class="card-link">
183
169
  <span>${liveTime}</span>
170
+ ${this.giConfig.followerDisplay
171
+ ? /* html */ `
172
+ <span>
173
+ ${liveStatus === 1
174
+ ? `当前粉丝数:${followerDisplay}`
175
+ : liveStatus === 2
176
+ ? `累计观看人数:${followerDisplay}`
177
+ : liveStatus === 3
178
+ ? `粉丝数变化:${followerDisplay}`
179
+ : ""}
180
+ </span>`
181
+ : ""}
184
182
  </p>
185
183
  </div>
186
184
  </div>
@@ -194,21 +192,22 @@ class GenerateImg extends koishi_1.Service {
194
192
  for (let i = 0; i < attempts; i++) {
195
193
  try {
196
194
  // 判断渲染方式
197
- if (this.giConfig.renderType) { // 为1则为真,进入page模式
198
- const htmlPath = 'file://' + __dirname.replaceAll('\\', '/') + '/page/0.html';
195
+ if (this.giConfig.renderType) {
196
+ // 为1则为真,进入page模式
197
+ const htmlPath = `file://${__dirname.replaceAll("\\", "/")}/page/0.html`;
199
198
  const page = await this.ctx.puppeteer.page();
200
199
  await page.goto(htmlPath);
201
- await page.setContent(html, { waitUntil: 'networkidle0' });
202
- const elementHandle = await page.$('html');
200
+ await page.setContent(html, { waitUntil: "networkidle0" });
201
+ const elementHandle = await page.$("html");
203
202
  const boundingBox = await elementHandle.boundingBox();
204
203
  const buffer = await page.screenshot({
205
- type: 'png',
204
+ type: "png",
206
205
  clip: {
207
206
  x: boundingBox.x,
208
207
  y: boundingBox.y,
209
208
  width: boundingBox.width,
210
- height: boundingBox.height
211
- }
209
+ height: boundingBox.height,
210
+ },
212
211
  });
213
212
  await elementHandle.dispose();
214
213
  await page.close();
@@ -219,12 +218,14 @@ class GenerateImg extends koishi_1.Service {
219
218
  return { pic };
220
219
  }
221
220
  catch (e) {
222
- if (i === attempts - 1) { // 已尝试三次
223
- throw new Error('生成图片失败!错误: ' + e.toString());
221
+ if (i === attempts - 1) {
222
+ // 已尝试三次
223
+ throw new Error(`生成图片失败!错误: ${e.toString()}`);
224
224
  }
225
225
  }
226
226
  }
227
227
  }
228
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
228
229
  async generateDynamicImg(data) {
229
230
  // module_author
230
231
  const module_author = data.modules.module_author;
@@ -246,11 +247,15 @@ class GenerateImg extends koishi_1.Service {
246
247
  const forward = module_stat.forward.count;
247
248
  const like = module_stat.like.count;
248
249
  // TOPIC
249
- const topic = data.modules.module_dynamic.topic ? data.modules.module_dynamic.topic.name : '';
250
- const getDynamicMajor = async (dynamicMajorData, forward) => {
250
+ const topic = data.modules.module_dynamic.topic
251
+ ? data.modules.module_dynamic.topic.name
252
+ : "";
253
+ const getDynamicMajor = async (
254
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
255
+ dynamicMajorData, forward) => {
251
256
  // 定义返回值
252
- let main = '';
253
- let link = '';
257
+ let main = "";
258
+ let link = "";
254
259
  // 定义forward类型返回值
255
260
  let forwardInfo;
256
261
  // 最基本的图文处理
@@ -259,30 +264,29 @@ class GenerateImg extends koishi_1.Service {
259
264
  if (module_dynamic.desc) {
260
265
  const richText = module_dynamic.desc.rich_text_nodes.reduce((accumulator, currentValue) => {
261
266
  if (currentValue.emoji) {
262
- return accumulator + `<img style="width:28px; height:28px;" src="${currentValue.emoji.icon_url}"/>`;
263
- }
264
- else {
265
- return accumulator + currentValue.text;
267
+ return /* html */ `${accumulator}<img style="width:28px; height:28px;" src="${currentValue.emoji.icon_url}"/>`;
266
268
  }
267
- }, '');
269
+ return accumulator + currentValue.text;
270
+ }, "");
268
271
  // 关键字和正则屏蔽
269
- if (this.giConfig.filter.enable) { // 开启动态屏蔽功能
270
- if (this.giConfig.filter.regex) { // 正则屏蔽
272
+ if (this.giConfig.filter.enable) {
273
+ // 开启动态屏蔽功能
274
+ if (this.giConfig.filter.regex) {
275
+ // 正则屏蔽
271
276
  const reg = new RegExp(this.giConfig.filter.regex);
272
277
  if (reg.test(richText))
273
- throw new Error('出现关键词,屏蔽该动态');
278
+ throw new Error("出现关键词,屏蔽该动态");
274
279
  }
275
280
  if (this.giConfig.filter.keywords.length !== 0 &&
276
- this.giConfig.filter.keywords
277
- .some(keyword => richText.includes(keyword))) {
278
- throw new Error('出现关键词,屏蔽该动态');
281
+ this.giConfig.filter.keywords.some((keyword) => richText.includes(keyword))) {
282
+ throw new Error("出现关键词,屏蔽该动态");
279
283
  }
280
284
  }
281
285
  // 查找\n
282
- const text = richText.replace(/\n/g, '<br>');
286
+ const text = richText.replace(/\n/g, "<br>");
283
287
  // 拼接字符串
284
288
  if (text) {
285
- main += `
289
+ main += /* html */ `
286
290
  <div class="card-details">
287
291
  ${text}
288
292
  </div>
@@ -290,14 +294,14 @@ class GenerateImg extends koishi_1.Service {
290
294
  }
291
295
  }
292
296
  // 图片
293
- let major = '';
294
- const arrowImg = (0, url_1.pathToFileURL)((0, path_1.resolve)(__dirname, 'img/arrow.png'));
295
- if (module_dynamic.major && module_dynamic.major.draw) {
297
+ let major = "";
298
+ const arrowImg = (0, node_url_1.pathToFileURL)((0, node_path_1.resolve)(__dirname, "img/arrow.png"));
299
+ if (module_dynamic.major?.draw) {
296
300
  if (module_dynamic.major.draw.items.length === 1) {
297
301
  const height = module_dynamic.major.draw.items[0].height;
298
302
  console.log(height);
299
303
  if (height > 3000) {
300
- major += `
304
+ major += /* html */ `
301
305
  <div class="single-photo-container">
302
306
  <img class="single-photo-item" src="${module_dynamic.major.draw.items[0].src}"/>
303
307
  <div class="single-photo-mask">
@@ -308,7 +312,7 @@ class GenerateImg extends koishi_1.Service {
308
312
  `;
309
313
  }
310
314
  else {
311
- major += `
315
+ major += /* html */ `
312
316
  <div class="single-photo-container">
313
317
  <img class="single-photo-item" src="${module_dynamic.major.draw.items[0].src}"/>
314
318
  </div>
@@ -317,15 +321,15 @@ class GenerateImg extends koishi_1.Service {
317
321
  }
318
322
  else if (module_dynamic.major.draw.items.length === 4) {
319
323
  major += module_dynamic.major.draw.items.reduce((acc, cV) => {
320
- return acc + `<img class="four-photo-item" src="${cV.src}"/>`;
321
- }, '');
324
+ return /* html */ `${acc}<img class="four-photo-item" src="${cV.src}"/>`;
325
+ }, "");
322
326
  }
323
327
  else {
324
328
  major += module_dynamic.major.draw.items.reduce((acc, cV) => {
325
- return acc + `<img class="photo-item" src="${cV.src}"/>`;
326
- }, '');
329
+ return /* html */ `${acc}<img class="photo-item" src="${cV.src}"/>`;
330
+ }, "");
327
331
  }
328
- main += `
332
+ main += /* html */ `
329
333
  <div class="card-major">
330
334
  ${major}
331
335
  </div>
@@ -343,7 +347,7 @@ class GenerateImg extends koishi_1.Service {
343
347
  if (dynamicMajorData.type === DYNAMIC_TYPE_FORWARD) {
344
348
  //转发动态屏蔽
345
349
  if (this.giConfig.filter.enable && this.giConfig.filter.forward) {
346
- throw new Error('已屏蔽转发动态');
350
+ throw new Error("已屏蔽转发动态");
347
351
  }
348
352
  // User info
349
353
  const forward_module_author = dynamicMajorData.orig.modules.module_author;
@@ -353,11 +357,11 @@ class GenerateImg extends koishi_1.Service {
353
357
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
354
358
  const [forwardMain, _, forwardInfo] = await getDynamicMajor(dynamicMajorData.orig, true);
355
359
  // 拼接main
356
- main += `
360
+ main += /* html */ `
357
361
  <div class="card-forward">
358
362
  <div class="forward-userinfo">
359
363
  <img class="forward-avatar" src="${forwardUserAvatarUrl}" alt="avatar">
360
- <span class="forward-username">${forwardUserName} ${forwardInfo ? forwardInfo : ''}</span>
364
+ <span class="forward-username">${forwardUserName} ${forwardInfo ? forwardInfo : ""}</span>
361
365
  </div>
362
366
  <div class="forward-main">
363
367
  ${forwardMain}
@@ -370,20 +374,21 @@ class GenerateImg extends koishi_1.Service {
370
374
  const additional = dynamicMajorData.modules.module_dynamic.additional;
371
375
  // 有附加信息,判断类型
372
376
  switch (additional.type) {
373
- case ADDITIONAL_TYPE_RESERVE: { // 预约信息
377
+ case ADDITIONAL_TYPE_RESERVE: {
378
+ // 预约信息
374
379
  const reserve = additional.reserve;
375
380
  // 定义按钮
376
381
  let button;
377
382
  // 判断按钮类型
378
- if (reserve.button.uncheck.text === '已结束') {
379
- button = `
383
+ if (reserve.button.uncheck.text === "已结束") {
384
+ button = /* html */ `
380
385
  <button class="reserve-button-end">
381
386
  <span>${reserve.button.uncheck.text}</span>
382
387
  </button>
383
388
  `;
384
389
  }
385
390
  else {
386
- button = `
391
+ button = /* html */ `
387
392
  <button class="reserve-button-ing">
388
393
  <svg class="bili-dyn-card-reserve__action__icon" style="width: 16px; height: 16px;"
389
394
  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
@@ -402,7 +407,7 @@ class GenerateImg extends koishi_1.Service {
402
407
  </button>
403
408
  `;
404
409
  }
405
- main += `
410
+ main += /* html */ `
406
411
  <div class="card-reserve">
407
412
  <div class="reserve-main">
408
413
  <div class="reserve-title">
@@ -413,8 +418,8 @@ class GenerateImg extends koishi_1.Service {
413
418
  <span class="reserve-time">${reserve.desc1.text}</span>
414
419
  <span class="reserve-num">${reserve.desc2.text}</span>
415
420
  </div>
416
- ${reserve.desc3 ?
417
- `<div class="reserve-prize">
421
+ ${reserve.desc3
422
+ ? `<div class="reserve-prize">
418
423
  <svg class="bili-dyn-card-reserve__lottery__icon"
419
424
  style="width: 16px; height: 16px;" xmlns="http://www.w3.org/2000/svg"
420
425
  xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" width="16"
@@ -443,7 +448,8 @@ class GenerateImg extends koishi_1.Service {
443
448
  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"
444
449
  fill="currentColor"></path>
445
450
  </svg>
446
- </div>` : ''}
451
+ </div>`
452
+ : ""}
447
453
  </div>
448
454
  </div>
449
455
  <div class="reserve-button">
@@ -457,19 +463,20 @@ class GenerateImg extends koishi_1.Service {
457
463
  link += `请将$替换为. www$bilibili$com/opus/${dynamicMajorData.id_str}`;
458
464
  break;
459
465
  }
460
- case DYNAMIC_TYPE_AV: { // 投稿新视频
466
+ case DYNAMIC_TYPE_AV: {
467
+ // 投稿新视频
461
468
  // 处理文字
462
469
  basicDynamic();
463
470
  const archive = dynamicMajorData.modules.module_dynamic.major.archive;
464
- if (archive.badge.text === '投稿视频') {
471
+ if (archive.badge.text === "投稿视频") {
465
472
  if (forward) {
466
- forwardInfo = '投稿了视频';
473
+ forwardInfo = "投稿了视频";
467
474
  }
468
475
  else {
469
476
  pubTime = `${pubTime} · 投稿了视频`;
470
477
  }
471
478
  }
472
- main += `
479
+ main += /* html */ `
473
480
  <div class="card-video">
474
481
  <div class="video-cover">
475
482
  <img src="${archive.cover}"
@@ -529,33 +536,42 @@ class GenerateImg extends koishi_1.Service {
529
536
  link = `请将$替换为. www$bilibili$com/video/${archive.bvid}`;
530
537
  break;
531
538
  }
532
- case DYNAMIC_TYPE_LIVE: return [`${upName}发起了直播预约,我暂时无法渲染,请自行查看`, link];
533
- case DYNAMIC_TYPE_MEDIALIST: return [`${upName}分享了收藏夹,我暂时无法渲染,请自行查看`, link];
534
- case DYNAMIC_TYPE_PGC: return [`${upName}发布了剧集(番剧、电影、纪录片),我暂时无法渲染,请自行查看`, link];
535
- case DYNAMIC_TYPE_ARTICLE: return [`${upName}投稿了新专栏,我暂时无法渲染,请自行查看`, link];
536
- case DYNAMIC_TYPE_MUSIC: return [`${upName}发行了新歌,我暂时无法渲染,请自行查看`, link];
537
- case DYNAMIC_TYPE_COMMON_SQUARE: return [`${upName}发布了装扮|剧集|点评|普通分享,我暂时无法渲染,请自行查看`, link];
538
- case DYNAMIC_TYPE_COURSES_SEASON: return [`${upName}发布了新课程,我暂时无法渲染,请自行查看`, link];
539
- case DYNAMIC_TYPE_UGC_SEASON: return [`${upName}更新了合集,我暂时无法渲染,请自行查看`, link];
540
- case DYNAMIC_TYPE_NONE: return [`${upName}发布了一条无效动态`, link];
539
+ case DYNAMIC_TYPE_LIVE:
540
+ return [`${upName}发起了直播预约,我暂时无法渲染,请自行查看`, link];
541
+ case DYNAMIC_TYPE_MEDIALIST:
542
+ return [`${upName}分享了收藏夹,我暂时无法渲染,请自行查看`, link];
543
+ case DYNAMIC_TYPE_PGC:
544
+ return [
545
+ `${upName}发布了剧集(番剧、电影、纪录片),我暂时无法渲染,请自行查看`,
546
+ link,
547
+ ];
548
+ case DYNAMIC_TYPE_ARTICLE:
549
+ return [`${upName}投稿了新专栏,我暂时无法渲染,请自行查看`, link];
550
+ case DYNAMIC_TYPE_MUSIC:
551
+ return [`${upName}发行了新歌,我暂时无法渲染,请自行查看`, link];
552
+ case DYNAMIC_TYPE_COMMON_SQUARE:
553
+ return [
554
+ `${upName}发布了装扮|剧集|点评|普通分享,我暂时无法渲染,请自行查看`,
555
+ link,
556
+ ];
557
+ case DYNAMIC_TYPE_COURSES_SEASON:
558
+ return [`${upName}发布了新课程,我暂时无法渲染,请自行查看`, link];
559
+ case DYNAMIC_TYPE_UGC_SEASON:
560
+ return [`${upName}更新了合集,我暂时无法渲染,请自行查看`, link];
561
+ case DYNAMIC_TYPE_NONE:
562
+ return [`${upName}发布了一条无效动态`, link];
541
563
  // 直播开播,不做处理
542
- case DYNAMIC_TYPE_LIVE_RCMD: throw new Error('直播开播动态,不做处理');
543
- case DYNAMIC_TYPE_SUBSCRIPTION_NEW:
544
- case DYNAMIC_TYPE_BANNER:
545
- case DYNAMIC_TYPE_SUBSCRIPTION:
546
- case DYNAMIC_TYPE_APPLET:
547
- case DYNAMIC_TYPE_AD:
548
- case DYNAMIC_TYPE_COURSES_BATCH:
549
- case DYNAMIC_TYPE_COURSES:
550
- case DYNAMIC_TYPE_COMMON_VERTICAL:
551
- default: return [`${upName}发布了一条我无法识别的动态,请自行查看`, ''];
564
+ case DYNAMIC_TYPE_LIVE_RCMD:
565
+ throw new Error("直播开播动态,不做处理");
566
+ default:
567
+ return [`${upName}发布了一条我无法识别的动态,请自行查看`, ""];
552
568
  }
553
569
  return [main, link, forwardInfo];
554
570
  };
555
571
  // 获取动态主要内容
556
572
  const [main, link] = await getDynamicMajor(data, false);
557
573
  // 加载字体
558
- const fontURL = (0, url_1.pathToFileURL)((0, path_1.resolve)(__dirname, 'font/HYZhengYuan-75W.ttf'));
574
+ const fontURL = (0, node_url_1.pathToFileURL)((0, node_path_1.resolve)(__dirname, "font/HYZhengYuan-75W.ttf"));
559
575
  // 判断是否开启大字体模式
560
576
  let style;
561
577
  if (this.giConfig.enableLargeFont) {
@@ -1290,7 +1306,7 @@ class GenerateImg extends koishi_1.Service {
1290
1306
  `;
1291
1307
  }
1292
1308
  // 定义卡片内容
1293
- const html = `
1309
+ const html = /* html */ `
1294
1310
  <!DOCTYPE html>
1295
1311
  <html>
1296
1312
  <head>
@@ -1301,7 +1317,7 @@ class GenerateImg extends koishi_1.Service {
1301
1317
  </head>
1302
1318
  <body>
1303
1319
  <div class="background">
1304
- <div ${this.giConfig.removeBorder ? '' : 'class="base-plate"'}>
1320
+ <div ${this.giConfig.removeBorder ? "" : 'class="base-plate"'}>
1305
1321
  <div class="card">
1306
1322
  <div class="card-body">
1307
1323
  <!-- 主播头像 -->
@@ -1311,24 +1327,28 @@ class GenerateImg extends koishi_1.Service {
1311
1327
  <div class="card-content">
1312
1328
  <div class="card-header">
1313
1329
  <div class="up-info">
1314
- <div class="up-name" style="${module_author.vip.type !== 0 ? 'color: #FB7299' : ''}">${upName}</div>
1330
+ <div class="up-name" style="${module_author.vip.type !== 0 ? "color: #FB7299" : ""}">${upName}</div>
1315
1331
  <div class="pub-time">${pubTime}</div>
1316
1332
  </div>
1317
- ${module_author.decorate ? `
1333
+ ${module_author.decorate
1334
+ ? `
1318
1335
  <div class="dress-up">
1319
1336
  <img src="${dynamicCardUrl}" />
1320
1337
  <span>${dynamicCardId}</span>
1321
1338
  </div>
1322
- ` : ''}
1339
+ `
1340
+ : ""}
1323
1341
  </div>
1324
1342
  <div class="card-topic">
1325
- ${topic ? `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"
1343
+ ${topic
1344
+ ? `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"
1326
1345
  class="bili-dyn-topic__icon">
1327
1346
  <path fill-rule="evenodd" clip-rule="evenodd"
1328
1347
  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"
1329
1348
  fill="currentColor"></path>
1330
1349
  </svg>
1331
- ${topic}` : ''}
1350
+ ${topic}`
1351
+ : ""}
1332
1352
  </div>
1333
1353
  ${main}
1334
1354
  <div class="card-stat">
@@ -1376,21 +1396,22 @@ class GenerateImg extends koishi_1.Service {
1376
1396
  for (let i = 0; i < attempts; i++) {
1377
1397
  try {
1378
1398
  // 判断渲染方式
1379
- if (this.giConfig.renderType) { // 为1则为真,进入page模式
1380
- const htmlPath = 'file://' + __dirname.replaceAll('\\', '/') + '/page/0.html';
1399
+ if (this.giConfig.renderType) {
1400
+ // 为1则为真,进入page模式
1401
+ const htmlPath = `file://${__dirname.replaceAll("\\", "/")}/page/0.html`;
1381
1402
  const page = await this.ctx.puppeteer.page();
1382
1403
  await page.goto(htmlPath);
1383
- await page.setContent(html, { waitUntil: 'networkidle0' });
1384
- const elementHandle = await page.$('html');
1404
+ await page.setContent(html, { waitUntil: "networkidle0" });
1405
+ const elementHandle = await page.$("html");
1385
1406
  const boundingBox = await elementHandle.boundingBox();
1386
1407
  const buffer = await page.screenshot({
1387
- type: 'png',
1408
+ type: "png",
1388
1409
  clip: {
1389
1410
  x: boundingBox.x,
1390
1411
  y: boundingBox.y,
1391
1412
  width: boundingBox.width,
1392
- height: boundingBox.height
1393
- }
1413
+ height: boundingBox.height,
1414
+ },
1394
1415
  });
1395
1416
  await elementHandle.dispose();
1396
1417
  await page.close();
@@ -1401,8 +1422,9 @@ class GenerateImg extends koishi_1.Service {
1401
1422
  return { pic, link };
1402
1423
  }
1403
1424
  catch (e) {
1404
- if (i === attempts - 1) { // 已尝试三次
1405
- throw new Error('生成图片失败!错误: ' + e.toString());
1425
+ if (i === attempts - 1) {
1426
+ // 已尝试三次
1427
+ throw new Error(`生成图片失败!错误: ${e.toString()}`);
1406
1428
  }
1407
1429
  }
1408
1430
  }
@@ -1413,26 +1435,26 @@ class GenerateImg extends koishi_1.Service {
1413
1435
  let cover;
1414
1436
  switch (liveStatus) {
1415
1437
  case 0: {
1416
- titleStatus = '未直播';
1417
- liveTime = '未开播';
1438
+ titleStatus = "未直播";
1439
+ liveTime = "未开播";
1418
1440
  cover = true;
1419
1441
  break;
1420
1442
  }
1421
1443
  case 1: {
1422
- titleStatus = '开播啦';
1444
+ titleStatus = "开播啦";
1423
1445
  liveTime = `开播时间:${time}`;
1424
1446
  cover = true;
1425
1447
  break;
1426
1448
  }
1427
1449
  case 2: {
1428
- titleStatus = '正在直播';
1450
+ titleStatus = "正在直播";
1429
1451
  liveTime = `直播时长:${await this.getTimeDifference(time)}`;
1430
1452
  cover = false;
1431
1453
  break;
1432
1454
  }
1433
1455
  case 3: {
1434
- titleStatus = '下播啦';
1435
- liveTime = `直播时长:${await this.getTimeDifference(time)}`;
1456
+ titleStatus = "下播啦";
1457
+ liveTime = `开播时间:${time}`;
1436
1458
  cover = true;
1437
1459
  break;
1438
1460
  }
@@ -1441,35 +1463,51 @@ class GenerateImg extends koishi_1.Service {
1441
1463
  }
1442
1464
  async getTimeDifference(dateString) {
1443
1465
  // 将日期字符串转换为Date对象
1444
- const date = new Date(dateString);
1445
- // 获取Unix时间戳(以毫秒为单位)
1446
- const unixTime = date.getTime() / 1000;
1447
- // 获取当前Unix时间戳
1448
- const now = this.ctx.ba.getTimeOfUTC8();
1449
- // 计算时间差(以秒为单位)
1450
- const differenceInSeconds = Math.floor(now - unixTime);
1451
- // 获取yyyy:MM:dd HH:mm:ss
1452
- const days = Math.floor(differenceInSeconds / (24 * 60 * 60));
1453
- const hours = Math.floor((differenceInSeconds % (24 * 60 * 60)) / (60 * 60));
1454
- const minutes = Math.floor((differenceInSeconds % (60 * 60)) / 60);
1455
- const seconds = differenceInSeconds % 60;
1456
- // 返回格式化的字符串
1457
- return days ?
1458
- `${days} ${hours}小时${minutes.toString().padStart(2, '0')}分${seconds.toString().padStart(2, '0')}秒` :
1459
- `${hours}小时${minutes.toString().padStart(2, '0')}分${seconds.toString().padStart(2, '0')}秒`;
1466
+ const apiDateTime = luxon_1.DateTime.fromFormat(dateString, "yyyy-MM-dd HH:mm:ss", {
1467
+ zone: "UTC+8",
1468
+ });
1469
+ // 获取当前时间
1470
+ const currentDateTime = luxon_1.DateTime.now();
1471
+ // 计算时间差
1472
+ const diff = currentDateTime.diff(apiDateTime, [
1473
+ "years",
1474
+ "months",
1475
+ "days",
1476
+ "hours",
1477
+ "minutes",
1478
+ "seconds",
1479
+ ]);
1480
+ const { years, months, days, hours, minutes, seconds } = diff.toObject();
1481
+ // 按单位生成可读字符串(过滤零值)
1482
+ const parts = [];
1483
+ if (years !== 0)
1484
+ parts.push(`${Math.abs(years)}年`);
1485
+ if (months !== 0)
1486
+ parts.push(`${Math.abs(months)}个月`);
1487
+ if (days !== 0)
1488
+ parts.push(`${Math.abs(days)}天`);
1489
+ if (hours !== 0)
1490
+ parts.push(`${Math.abs(hours)}小时`);
1491
+ if (minutes !== 0)
1492
+ parts.push(`${Math.abs(minutes)}分`);
1493
+ if (seconds !== 0)
1494
+ parts.push(`${Math.round(Math.abs(seconds))}秒`);
1495
+ // 处理负值
1496
+ const sign = diff.as("seconds") < 0 ? "-" : "";
1497
+ // 组合结果(如果无差值返回"0秒")
1498
+ return parts.length > 0 ? `${sign}${parts.join("")}` : "0秒";
1460
1499
  }
1461
1500
  unixTimestampToString(timestamp) {
1462
1501
  const date = new Date(timestamp * 1000);
1463
1502
  const year = date.getFullYear();
1464
- const month = ("0" + (date.getMonth() + 1)).slice(-2);
1465
- const day = ("0" + date.getDate()).slice(-2);
1466
- const hours = ("0" + (date.getHours())).slice(-2);
1467
- const minutes = ("0" + date.getMinutes()).slice(-2);
1468
- const seconds = ("0" + date.getSeconds()).slice(-2);
1503
+ const month = `0${date.getMonth() + 1}`.slice(-2);
1504
+ const day = `0${date.getDate()}`.slice(-2);
1505
+ const hours = `0${date.getHours()}`.slice(-2);
1506
+ const minutes = `0${date.getMinutes()}`.slice(-2);
1507
+ const seconds = `0${date.getSeconds()}`.slice(-2);
1469
1508
  return `${year}年${month}月${day}日 ${hours}:${minutes}:${seconds}`;
1470
1509
  }
1471
1510
  }
1472
- // eslint-disable-next-line @typescript-eslint/no-namespace
1473
1511
  (function (GenerateImg) {
1474
1512
  GenerateImg.Config = koishi_1.Schema.object({
1475
1513
  renderType: koishi_1.Schema.number(),
@@ -1478,14 +1516,15 @@ class GenerateImg extends koishi_1.Service {
1478
1516
  notify: koishi_1.Schema.boolean(),
1479
1517
  regex: koishi_1.Schema.string(),
1480
1518
  keywords: koishi_1.Schema.array(String),
1481
- forward: koishi_1.Schema.boolean()
1519
+ forward: koishi_1.Schema.boolean(),
1482
1520
  }),
1483
1521
  removeBorder: koishi_1.Schema.boolean(),
1484
1522
  cardColorStart: koishi_1.Schema.string(),
1485
1523
  cardColorEnd: koishi_1.Schema.string(),
1486
1524
  enableLargeFont: koishi_1.Schema.boolean(),
1487
1525
  font: koishi_1.Schema.string(),
1488
- hideDesc: koishi_1.Schema.boolean()
1526
+ hideDesc: koishi_1.Schema.boolean(),
1527
+ followerDisplay: koishi_1.Schema.boolean(),
1489
1528
  });
1490
1529
  })(GenerateImg || (GenerateImg = {}));
1491
1530
  exports.default = GenerateImg;