@bilibili-notify/live 0.0.1-alpha.3 → 0.1.0-alpha.4

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
@@ -499,37 +499,41 @@ var RoomContext = class extends RoomContextBase {
499
499
  * - `customSpecialDanmakuUsers.msgTemplate`
500
500
  * - `customSpecialUsersEnterTheRoom.msgTemplate`
501
501
  *
502
- * The variable syntax follows the existing `-name` / `-time` / `-watched` style
503
- * (NOT the `{key}` syntax used by `@bilibili-notify/internal`'s `interpolate`),
504
- * because that's what users have in their existing Koishi configs and we keep
505
- * 1:1 backward compatibility.
502
+ * 占位符统一 `{name}` / `{time}` / `{watched}` 语法(与 `@bilibili-notify/internal`
503
+ * `interpolate` 同源)。`applyTemplate` 同时接受 koishi 旧存档里的 legacy
504
+ * `-name` / `-time` 写法 —— 老用户已保存的 `-key` 模板继续生效,新默认与文档
505
+ * 一律走 `{key}`,二者不冲突(单遍正则,longest-first)。
506
506
  */
507
507
  /** Defaults applied when neither sub-level nor global config provides a template. */
508
508
  const DEFAULT_LIVE_TEMPLATES = {
509
- liveStart: "-name 开播啦,当前粉丝数:-follower\n-link",
510
- liveOngoing: "-name 正在直播,已播 -time,累计观看:-watched\n-link",
511
- liveEnd: "-name 下播啦,本次直播了 -time,粉丝变化 -follower_change",
509
+ liveStart: "{name} 开播啦,当前粉丝数:{follower}\n{link}",
510
+ liveOngoing: "{name} 正在直播,已播 {time},累计观看:{watched}\n{link}",
511
+ liveEnd: "{name} 下播啦,本次直播了 {time},粉丝变化 {follower_change}",
512
512
  liveSummaryFallback: "弹幕总结"
513
513
  };
514
514
  function escapeRegExp(s) {
515
515
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
516
516
  }
517
517
  /**
518
- * 单遍替换所有变量 token,再把 `\n` 转义展开为真换行。
518
+ * 单遍替换所有变量 token,再把 `\n` 转义展开为真换行。`vars` 以**裸键**(`name`/
519
+ * `follower_change`)给出,每个键同时匹配 `{name}`(主)与 legacy `-name`(兼容)。
519
520
  *
520
521
  * P2:此前 `for…replaceAll` 顺序替换有两个缺陷 ——
521
- * 1. **token 注入**:用户可控值(uname / 弹幕内容)含 `-link`/`-time` 时
522
+ * 1. **token 注入**:用户可控值(uname / 弹幕内容)含 `{link}`/`-link` 时
522
523
  * 会被后续轮次再次替换;
523
- * 2. **前缀吞噬**:`-follower` 先于 `-follower_change` 替换,把后者的
524
+ * 2. **前缀吞噬**:legacy `-follower` 先于 `-follower_change` 替换,把后者的
524
525
  * `-follower` 段吃掉只剩 `_change`。
525
- * 改为基于原始模板的**单遍正则**:token 按长度降序进 alternation(最长优先
526
- * 匹配),每个 token 恰好替换一次且替换值不再被回扫 → 杜绝注入与吞噬。
526
+ * 改为基于原始模板的**单遍正则**:键按长度降序进 alternation(最长优先匹配),
527
+ * 每个 token 恰好替换一次且替换值不再被回扫 → 杜绝注入与吞噬。
527
528
  */
528
529
  function applyTemplate(template, vars) {
529
530
  const keys = Object.keys(vars).sort((a, b) => b.length - a.length);
530
531
  if (keys.length === 0) return template.replaceAll("\\n", "\n");
531
- const re = new RegExp(keys.map(escapeRegExp).join("|"), "g");
532
- return template.replace(re, (m) => vars[m] ?? m).replaceAll("\\n", "\n");
532
+ const alts = keys.flatMap((k) => [`\\{${escapeRegExp(k)}\\}`, `-${escapeRegExp(k)}`]);
533
+ const re = new RegExp(alts.join("|"), "g");
534
+ return template.replace(re, (m) => {
535
+ return vars[m.charCodeAt(0) === 123 ? m.slice(1, -1) : m.slice(1)] ?? m;
536
+ }).replaceAll("\\n", "\n");
533
537
  }
534
538
  /**
535
539
  * Format follower-change as a signed magnitude string with a 1万 (10K) cutoff,
@@ -559,27 +563,27 @@ var LiveTemplateRenderer = class {
559
563
  /** Compose the "开播" notification text for a sub. */
560
564
  renderLiveStart(params) {
561
565
  return applyTemplate(resolveCustomLive(params.sub.customLiveMsg, params.globalCustom, "customLiveStart", DEFAULT_LIVE_TEMPLATES.liveStart), {
562
- "-name": params.master.username,
563
- "-time": params.diffTime,
564
- "-follower": params.followerNum,
565
- "-link": params.roomLink
566
+ name: params.master.username,
567
+ time: params.diffTime,
568
+ follower: params.followerNum,
569
+ link: params.roomLink
566
570
  });
567
571
  }
568
572
  /** Compose the periodic "正在直播" notification text. */
569
573
  renderLiveOngoing(params) {
570
574
  return applyTemplate(resolveCustomLive(params.sub.customLiveMsg, params.globalCustom, "customLive", DEFAULT_LIVE_TEMPLATES.liveOngoing), {
571
- "-name": params.master.username,
572
- "-time": params.diffTime,
573
- "-watched": params.watched,
574
- "-link": params.roomLink
575
+ name: params.master.username,
576
+ time: params.diffTime,
577
+ watched: params.watched,
578
+ link: params.roomLink
575
579
  });
576
580
  }
577
581
  /** Compose the "下播" notification text. */
578
582
  renderLiveEnd(params) {
579
583
  return applyTemplate(resolveCustomLive(params.sub.customLiveMsg, params.globalCustom, "customLiveEnd", DEFAULT_LIVE_TEMPLATES.liveEnd), {
580
- "-name": params.master.username,
581
- "-time": params.diffTime,
582
- "-follower_change": formatFollowerChange(params.followerChange)
584
+ name: params.master.username,
585
+ time: params.diffTime,
586
+ follower_change: formatFollowerChange(params.followerChange)
583
587
  });
584
588
  }
585
589
  /**
@@ -588,24 +592,24 @@ var LiveTemplateRenderer = class {
588
592
  */
589
593
  renderGuardBuy(params) {
590
594
  return applyTemplate(params.guardBuyConfig.guardBuyMsg ?? "", {
591
- "-uname": params.uname,
592
- "-mname": params.master?.username ?? "",
593
- "-guard": params.giftName
595
+ uname: params.uname,
596
+ mname: params.master?.username ?? "",
597
+ guard: params.giftName
594
598
  });
595
599
  }
596
600
  /** Compose the "特别关注弹幕" notification text. */
597
601
  renderSpecialDanmaku(params) {
598
602
  return applyTemplate(params.template, {
599
- "-mastername": params.master?.username ?? "",
600
- "-uname": params.uname,
601
- "-msg": params.content
603
+ mastername: params.master?.username ?? "",
604
+ uname: params.uname,
605
+ msg: params.content
602
606
  });
603
607
  }
604
608
  /** Compose the "特别关注进入直播间" notification text. */
605
609
  renderSpecialUserEnter(params) {
606
610
  return applyTemplate(params.template, {
607
- "-mastername": params.master?.username ?? "",
608
- "-uname": params.uname
611
+ mastername: params.master?.username ?? "",
612
+ uname: params.uname
609
613
  });
610
614
  }
611
615
  /**
@@ -618,19 +622,19 @@ var LiveTemplateRenderer = class {
618
622
  const top = params.topSenders;
619
623
  const at = (i) => top[i] ?? ["", 0];
620
624
  return applyTemplate(params.template, {
621
- "-dmc": `${params.senderCount}`,
622
- "-mdn": params.master?.medalName ?? "",
623
- "-dca": `${params.danmakuCount}`,
624
- "-un1": at(0)[0],
625
- "-dc1": `${at(0)[1]}`,
626
- "-un2": at(1)[0],
627
- "-dc2": `${at(1)[1]}`,
628
- "-un3": at(2)[0],
629
- "-dc3": `${at(2)[1]}`,
630
- "-un4": at(3)[0],
631
- "-dc4": `${at(3)[1]}`,
632
- "-un5": at(4)[0],
633
- "-dc5": `${at(4)[1]}`
625
+ dmc: `${params.senderCount}`,
626
+ mdn: params.master?.medalName ?? "",
627
+ dca: `${params.danmakuCount}`,
628
+ un1: at(0)[0],
629
+ dc1: `${at(0)[1]}`,
630
+ un2: at(1)[0],
631
+ dc2: `${at(1)[1]}`,
632
+ un3: at(2)[0],
633
+ dc3: `${at(2)[1]}`,
634
+ un4: at(3)[0],
635
+ dc4: `${at(3)[1]}`,
636
+ un5: at(4)[0],
637
+ dc5: `${at(4)[1]}`
634
638
  });
635
639
  }
636
640
  };
package/lib/index.d.cts CHANGED
@@ -274,16 +274,16 @@ type LivePushTimerManager = Map<string, () => void>;
274
274
  * - `customSpecialDanmakuUsers.msgTemplate`
275
275
  * - `customSpecialUsersEnterTheRoom.msgTemplate`
276
276
  *
277
- * The variable syntax follows the existing `-name` / `-time` / `-watched` style
278
- * (NOT the `{key}` syntax used by `@bilibili-notify/internal`'s `interpolate`),
279
- * because that's what users have in their existing Koishi configs and we keep
280
- * 1:1 backward compatibility.
277
+ * 占位符统一 `{name}` / `{time}` / `{watched}` 语法(与 `@bilibili-notify/internal`
278
+ * `interpolate` 同源)。`applyTemplate` 同时接受 koishi 旧存档里的 legacy
279
+ * `-name` / `-time` 写法 —— 老用户已保存的 `-key` 模板继续生效,新默认与文档
280
+ * 一律走 `{key}`,二者不冲突(单遍正则,longest-first)。
281
281
  */
282
282
  /** Defaults applied when neither sub-level nor global config provides a template. */
283
283
  declare const DEFAULT_LIVE_TEMPLATES: {
284
- readonly liveStart: "-name 开播啦,当前粉丝数:-follower\n-link";
285
- readonly liveOngoing: "-name 正在直播,已播 -time,累计观看:-watched\n-link";
286
- readonly liveEnd: "-name 下播啦,本次直播了 -time,粉丝变化 -follower_change";
284
+ readonly liveStart: "{name} 开播啦,当前粉丝数:{follower}\n{link}";
285
+ readonly liveOngoing: "{name} 正在直播,已播 {time},累计观看:{watched}\n{link}";
286
+ readonly liveEnd: "{name} 下播啦,本次直播了 {time},粉丝变化 {follower_change}";
287
287
  readonly liveSummaryFallback: "弹幕总结";
288
288
  };
289
289
  /**
package/lib/index.d.mts CHANGED
@@ -274,16 +274,16 @@ type LivePushTimerManager = Map<string, () => void>;
274
274
  * - `customSpecialDanmakuUsers.msgTemplate`
275
275
  * - `customSpecialUsersEnterTheRoom.msgTemplate`
276
276
  *
277
- * The variable syntax follows the existing `-name` / `-time` / `-watched` style
278
- * (NOT the `{key}` syntax used by `@bilibili-notify/internal`'s `interpolate`),
279
- * because that's what users have in their existing Koishi configs and we keep
280
- * 1:1 backward compatibility.
277
+ * 占位符统一 `{name}` / `{time}` / `{watched}` 语法(与 `@bilibili-notify/internal`
278
+ * `interpolate` 同源)。`applyTemplate` 同时接受 koishi 旧存档里的 legacy
279
+ * `-name` / `-time` 写法 —— 老用户已保存的 `-key` 模板继续生效,新默认与文档
280
+ * 一律走 `{key}`,二者不冲突(单遍正则,longest-first)。
281
281
  */
282
282
  /** Defaults applied when neither sub-level nor global config provides a template. */
283
283
  declare const DEFAULT_LIVE_TEMPLATES: {
284
- readonly liveStart: "-name 开播啦,当前粉丝数:-follower\n-link";
285
- readonly liveOngoing: "-name 正在直播,已播 -time,累计观看:-watched\n-link";
286
- readonly liveEnd: "-name 下播啦,本次直播了 -time,粉丝变化 -follower_change";
284
+ readonly liveStart: "{name} 开播啦,当前粉丝数:{follower}\n{link}";
285
+ readonly liveOngoing: "{name} 正在直播,已播 {time},累计观看:{watched}\n{link}";
286
+ readonly liveEnd: "{name} 下播啦,本次直播了 {time},粉丝变化 {follower_change}";
287
287
  readonly liveSummaryFallback: "弹幕总结";
288
288
  };
289
289
  /**
package/lib/index.mjs CHANGED
@@ -475,37 +475,41 @@ var RoomContext = class extends RoomContextBase {
475
475
  * - `customSpecialDanmakuUsers.msgTemplate`
476
476
  * - `customSpecialUsersEnterTheRoom.msgTemplate`
477
477
  *
478
- * The variable syntax follows the existing `-name` / `-time` / `-watched` style
479
- * (NOT the `{key}` syntax used by `@bilibili-notify/internal`'s `interpolate`),
480
- * because that's what users have in their existing Koishi configs and we keep
481
- * 1:1 backward compatibility.
478
+ * 占位符统一 `{name}` / `{time}` / `{watched}` 语法(与 `@bilibili-notify/internal`
479
+ * `interpolate` 同源)。`applyTemplate` 同时接受 koishi 旧存档里的 legacy
480
+ * `-name` / `-time` 写法 —— 老用户已保存的 `-key` 模板继续生效,新默认与文档
481
+ * 一律走 `{key}`,二者不冲突(单遍正则,longest-first)。
482
482
  */
483
483
  /** Defaults applied when neither sub-level nor global config provides a template. */
484
484
  const DEFAULT_LIVE_TEMPLATES = {
485
- liveStart: "-name 开播啦,当前粉丝数:-follower\n-link",
486
- liveOngoing: "-name 正在直播,已播 -time,累计观看:-watched\n-link",
487
- liveEnd: "-name 下播啦,本次直播了 -time,粉丝变化 -follower_change",
485
+ liveStart: "{name} 开播啦,当前粉丝数:{follower}\n{link}",
486
+ liveOngoing: "{name} 正在直播,已播 {time},累计观看:{watched}\n{link}",
487
+ liveEnd: "{name} 下播啦,本次直播了 {time},粉丝变化 {follower_change}",
488
488
  liveSummaryFallback: "弹幕总结"
489
489
  };
490
490
  function escapeRegExp(s) {
491
491
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
492
492
  }
493
493
  /**
494
- * 单遍替换所有变量 token,再把 `\n` 转义展开为真换行。
494
+ * 单遍替换所有变量 token,再把 `\n` 转义展开为真换行。`vars` 以**裸键**(`name`/
495
+ * `follower_change`)给出,每个键同时匹配 `{name}`(主)与 legacy `-name`(兼容)。
495
496
  *
496
497
  * P2:此前 `for…replaceAll` 顺序替换有两个缺陷 ——
497
- * 1. **token 注入**:用户可控值(uname / 弹幕内容)含 `-link`/`-time` 时
498
+ * 1. **token 注入**:用户可控值(uname / 弹幕内容)含 `{link}`/`-link` 时
498
499
  * 会被后续轮次再次替换;
499
- * 2. **前缀吞噬**:`-follower` 先于 `-follower_change` 替换,把后者的
500
+ * 2. **前缀吞噬**:legacy `-follower` 先于 `-follower_change` 替换,把后者的
500
501
  * `-follower` 段吃掉只剩 `_change`。
501
- * 改为基于原始模板的**单遍正则**:token 按长度降序进 alternation(最长优先
502
- * 匹配),每个 token 恰好替换一次且替换值不再被回扫 → 杜绝注入与吞噬。
502
+ * 改为基于原始模板的**单遍正则**:键按长度降序进 alternation(最长优先匹配),
503
+ * 每个 token 恰好替换一次且替换值不再被回扫 → 杜绝注入与吞噬。
503
504
  */
504
505
  function applyTemplate(template, vars) {
505
506
  const keys = Object.keys(vars).sort((a, b) => b.length - a.length);
506
507
  if (keys.length === 0) return template.replaceAll("\\n", "\n");
507
- const re = new RegExp(keys.map(escapeRegExp).join("|"), "g");
508
- return template.replace(re, (m) => vars[m] ?? m).replaceAll("\\n", "\n");
508
+ const alts = keys.flatMap((k) => [`\\{${escapeRegExp(k)}\\}`, `-${escapeRegExp(k)}`]);
509
+ const re = new RegExp(alts.join("|"), "g");
510
+ return template.replace(re, (m) => {
511
+ return vars[m.charCodeAt(0) === 123 ? m.slice(1, -1) : m.slice(1)] ?? m;
512
+ }).replaceAll("\\n", "\n");
509
513
  }
510
514
  /**
511
515
  * Format follower-change as a signed magnitude string with a 1万 (10K) cutoff,
@@ -535,27 +539,27 @@ var LiveTemplateRenderer = class {
535
539
  /** Compose the "开播" notification text for a sub. */
536
540
  renderLiveStart(params) {
537
541
  return applyTemplate(resolveCustomLive(params.sub.customLiveMsg, params.globalCustom, "customLiveStart", DEFAULT_LIVE_TEMPLATES.liveStart), {
538
- "-name": params.master.username,
539
- "-time": params.diffTime,
540
- "-follower": params.followerNum,
541
- "-link": params.roomLink
542
+ name: params.master.username,
543
+ time: params.diffTime,
544
+ follower: params.followerNum,
545
+ link: params.roomLink
542
546
  });
543
547
  }
544
548
  /** Compose the periodic "正在直播" notification text. */
545
549
  renderLiveOngoing(params) {
546
550
  return applyTemplate(resolveCustomLive(params.sub.customLiveMsg, params.globalCustom, "customLive", DEFAULT_LIVE_TEMPLATES.liveOngoing), {
547
- "-name": params.master.username,
548
- "-time": params.diffTime,
549
- "-watched": params.watched,
550
- "-link": params.roomLink
551
+ name: params.master.username,
552
+ time: params.diffTime,
553
+ watched: params.watched,
554
+ link: params.roomLink
551
555
  });
552
556
  }
553
557
  /** Compose the "下播" notification text. */
554
558
  renderLiveEnd(params) {
555
559
  return applyTemplate(resolveCustomLive(params.sub.customLiveMsg, params.globalCustom, "customLiveEnd", DEFAULT_LIVE_TEMPLATES.liveEnd), {
556
- "-name": params.master.username,
557
- "-time": params.diffTime,
558
- "-follower_change": formatFollowerChange(params.followerChange)
560
+ name: params.master.username,
561
+ time: params.diffTime,
562
+ follower_change: formatFollowerChange(params.followerChange)
559
563
  });
560
564
  }
561
565
  /**
@@ -564,24 +568,24 @@ var LiveTemplateRenderer = class {
564
568
  */
565
569
  renderGuardBuy(params) {
566
570
  return applyTemplate(params.guardBuyConfig.guardBuyMsg ?? "", {
567
- "-uname": params.uname,
568
- "-mname": params.master?.username ?? "",
569
- "-guard": params.giftName
571
+ uname: params.uname,
572
+ mname: params.master?.username ?? "",
573
+ guard: params.giftName
570
574
  });
571
575
  }
572
576
  /** Compose the "特别关注弹幕" notification text. */
573
577
  renderSpecialDanmaku(params) {
574
578
  return applyTemplate(params.template, {
575
- "-mastername": params.master?.username ?? "",
576
- "-uname": params.uname,
577
- "-msg": params.content
579
+ mastername: params.master?.username ?? "",
580
+ uname: params.uname,
581
+ msg: params.content
578
582
  });
579
583
  }
580
584
  /** Compose the "特别关注进入直播间" notification text. */
581
585
  renderSpecialUserEnter(params) {
582
586
  return applyTemplate(params.template, {
583
- "-mastername": params.master?.username ?? "",
584
- "-uname": params.uname
587
+ mastername: params.master?.username ?? "",
588
+ uname: params.uname
585
589
  });
586
590
  }
587
591
  /**
@@ -594,19 +598,19 @@ var LiveTemplateRenderer = class {
594
598
  const top = params.topSenders;
595
599
  const at = (i) => top[i] ?? ["", 0];
596
600
  return applyTemplate(params.template, {
597
- "-dmc": `${params.senderCount}`,
598
- "-mdn": params.master?.medalName ?? "",
599
- "-dca": `${params.danmakuCount}`,
600
- "-un1": at(0)[0],
601
- "-dc1": `${at(0)[1]}`,
602
- "-un2": at(1)[0],
603
- "-dc2": `${at(1)[1]}`,
604
- "-un3": at(2)[0],
605
- "-dc3": `${at(2)[1]}`,
606
- "-un4": at(3)[0],
607
- "-dc4": `${at(3)[1]}`,
608
- "-un5": at(4)[0],
609
- "-dc5": `${at(4)[1]}`
601
+ dmc: `${params.senderCount}`,
602
+ mdn: params.master?.medalName ?? "",
603
+ dca: `${params.danmakuCount}`,
604
+ un1: at(0)[0],
605
+ dc1: `${at(0)[1]}`,
606
+ un2: at(1)[0],
607
+ dc2: `${at(1)[1]}`,
608
+ un3: at(2)[0],
609
+ dc3: `${at(2)[1]}`,
610
+ un4: at(3)[0],
611
+ dc4: `${at(3)[1]}`,
612
+ un5: at(4)[0],
613
+ dc5: `${at(4)[1]}`
610
614
  });
611
615
  }
612
616
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bilibili-notify/live",
3
- "version": "0.0.1-alpha.3",
3
+ "version": "0.1.0-alpha.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/Akokk0/bilibili-notify"
@@ -30,10 +30,10 @@
30
30
  "jieba-wasm": "^2.4.0",
31
31
  "luxon": "^3.5.0",
32
32
  "protobufjs": "^7.4.0",
33
- "@bilibili-notify/api": "^0.2.0-alpha.2",
34
33
  "@bilibili-notify/ai": "^0.0.1-alpha.1",
35
- "@bilibili-notify/internal": "^0.1.0-alpha.2",
36
- "@bilibili-notify/image": "^0.0.1-alpha.2"
34
+ "@bilibili-notify/image": "^0.0.1-alpha.2",
35
+ "@bilibili-notify/api": "^0.2.0-alpha.2",
36
+ "@bilibili-notify/internal": "^0.1.0-alpha.3"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/luxon": "^3.4.2",