@bilibili-notify/live 0.0.1-alpha.2 → 0.0.1-alpha.3

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
@@ -168,11 +168,16 @@ var RoomContextBase = class {
168
168
  liveSummaryRequester;
169
169
  danmakuCollector;
170
170
  /**
171
- * 真实注入的渲染器引用,private 是因为外部应通过 `imageRenderer` getter 访问 ——
171
+ * 渲染器 provider —— private 是因为外部应通过 `imageRenderer` getter 访问 ——
172
172
  * 后者会在 `config.imageEnabled === false` 时返回 null,让所有
173
173
  * `if (this.imageRenderer?.generateXxx)` 自然落入文字回退分支。
174
+ * provider 形式让 LiveEngine 的 setImageRenderer 无需逐 RoomContext 推。
175
+ *
176
+ * **不要直接调 `this._getImageRenderer()` 绕过 imageEnabled 门控**,业务路径
177
+ * 必须通过 `this.imageRenderer` getter,否则用户在 dashboard 关掉卡片渲染时
178
+ * 这条路径仍会渲图。
174
179
  */
175
- _imageRenderer;
180
+ _getImageRenderer;
176
181
  emitEngineError;
177
182
  _emitLiveState;
178
183
  _emitViewers;
@@ -199,7 +204,7 @@ var RoomContextBase = class {
199
204
  this.wordcloudGenerator = opts.wordcloudGenerator;
200
205
  this.liveSummaryRequester = opts.liveSummaryRequester;
201
206
  this.danmakuCollector = opts.danmakuCollector;
202
- this._imageRenderer = opts.imageRenderer;
207
+ this._getImageRenderer = opts.getImageRenderer;
203
208
  this.config = opts.config;
204
209
  this.emitEngineError = opts.emitEngineError;
205
210
  this._emitLiveState = opts.emitLiveState;
@@ -219,7 +224,7 @@ var RoomContextBase = class {
219
224
  }
220
225
  /** 受 `config.imageEnabled` 门控的渲染器视图;关闭时返回 null。 */
221
226
  get imageRenderer() {
222
- return this.config.imageEnabled === false ? null : this._imageRenderer;
227
+ return this.config.imageEnabled === false ? null : this._getImageRenderer();
223
228
  }
224
229
  updateConfig(config) {
225
230
  this.config = config;
@@ -1576,11 +1581,11 @@ const WORDCLOUD_TOP_WORDS = 90;
1576
1581
  * platform (e.g. via `LiveContentBuilder.image`).
1577
1582
  */
1578
1583
  var WordcloudGenerator = class {
1579
- imageRenderer;
1584
+ getImageRenderer;
1580
1585
  isImageEnabled;
1581
1586
  logger;
1582
1587
  constructor(opts) {
1583
- this.imageRenderer = opts.imageRenderer;
1588
+ this.getImageRenderer = opts.getImageRenderer;
1584
1589
  this.isImageEnabled = opts.isImageEnabled ?? (() => true);
1585
1590
  this.logger = opts.logger;
1586
1591
  }
@@ -1602,9 +1607,10 @@ var WordcloudGenerator = class {
1602
1607
  this.logger.debug("[wordcloud] cardStyle.enabled=false,跳过词云图片生成");
1603
1608
  return;
1604
1609
  }
1605
- if (!this.imageRenderer?.generateWordCloudImg) return void 0;
1610
+ const renderer = this.getImageRenderer();
1611
+ if (!renderer?.generateWordCloudImg) return void 0;
1606
1612
  try {
1607
- return await this.imageRenderer.generateWordCloudImg(sortedWords.slice(0, 90), masterName, masterAvatarUrl);
1613
+ return await renderer.generateWordCloudImg(sortedWords.slice(0, 90), masterName, masterAvatarUrl);
1608
1614
  } catch (e) {
1609
1615
  this.logger.error(`[wordcloud] 生成词云失败:${e.message}`);
1610
1616
  return;
@@ -1634,14 +1640,22 @@ var LiveEngine = class {
1634
1640
  danmakuCollector;
1635
1641
  liveSummaryRequester;
1636
1642
  config;
1643
+ /**
1644
+ * Image 渲染器的当前引用 —— 单一可变 state,setImageRenderer 在此更新;
1645
+ * 所有子组件(wordcloud / listener / room-context)通过 provider 函数现取,
1646
+ * 无需逐组件 setter 推送。
1647
+ */
1648
+ currentImageRenderer;
1637
1649
  constructor(opts) {
1638
1650
  this.logger = opts.serviceCtx.logger;
1639
1651
  this.config = opts.config;
1652
+ this.currentImageRenderer = opts.imageRenderer ?? null;
1653
+ const getImageRenderer = () => this.currentImageRenderer;
1640
1654
  const stopwords = mergeStopWords(opts.config.wordcloudStopWords);
1641
1655
  this.danmakuCollector = new DanmakuCollector(stopwords);
1642
1656
  const templateRenderer = new LiveTemplateRenderer();
1643
1657
  const wordcloudGenerator = new WordcloudGenerator({
1644
- imageRenderer: opts.imageRenderer ?? null,
1658
+ getImageRenderer,
1645
1659
  isImageEnabled: () => this.config.imageEnabled !== false,
1646
1660
  logger: this.logger
1647
1661
  });
@@ -1661,7 +1675,7 @@ var LiveEngine = class {
1661
1675
  wordcloudGenerator,
1662
1676
  liveSummaryRequester,
1663
1677
  danmakuCollector: this.danmakuCollector,
1664
- imageRenderer: opts.imageRenderer ?? null,
1678
+ getImageRenderer,
1665
1679
  config: toListenerConfig(opts.config),
1666
1680
  emitEngineError: opts.emitEngineError,
1667
1681
  emitLiveState: opts.emitLiveState,
@@ -1744,6 +1758,17 @@ var LiveEngine = class {
1744
1758
  setCommentary(commentary) {
1745
1759
  this.liveSummaryRequester.setCommentary(commentary);
1746
1760
  }
1761
+ /**
1762
+ * 热替换 ImageRenderer 实例。adapter 在 image 服务上下线时调用。子组件 (词云 /
1763
+ * room-context / 卡片渲染) 都通过共享 provider 现取,这里只需更新单一 state。
1764
+ *
1765
+ * 主要给 koishi adapter 用 —— sibling service (-image) 启停时通过 ctx.inject
1766
+ * 后置注入。独立端 imageRenderer 是 engine 同进程一次性 wire,不会动态消失,
1767
+ * 不需要调用本方法 (cardStyle 热更走 imageRenderer.updateConfig)。
1768
+ */
1769
+ setImageRenderer(imageRenderer) {
1770
+ this.currentImageRenderer = imageRenderer;
1771
+ }
1747
1772
  /** Final dispose; the engine instance must not be reused after this. */
1748
1773
  stop() {
1749
1774
  this.listener.disposeAll();
package/lib/index.d.cts CHANGED
@@ -433,11 +433,16 @@ declare const WORDCLOUD_TOP_WORDS = 90;
433
433
  * platform (e.g. via `LiveContentBuilder.image`).
434
434
  */
435
435
  declare class WordcloudGenerator {
436
- private readonly imageRenderer;
436
+ private readonly getImageRenderer;
437
437
  private readonly isImageEnabled;
438
438
  private readonly logger;
439
439
  constructor(opts: {
440
- imageRenderer: ImageRenderer | null;
440
+ /**
441
+ * 渲染器 provider —— 每次 generate() 现取最新引用,使 LiveEngine 在 image
442
+ * 服务上下线时通过 setImageRenderer 替换内部状态,词云生成自动同步,无需子组件
443
+ * 接 setter。
444
+ */
445
+ getImageRenderer: () => ImageRenderer | null;
441
446
  /**
442
447
  * 卡片渲染总开关查询。返回 false 时直接跳过 puppeteer 调用,与缺失 imageRenderer
443
448
  * 等价。Adapter 通常用 `() => globals.defaults.cardStyle.enabled` 填充;缺省 () => true。
@@ -502,7 +507,11 @@ interface RoomContextOptions {
502
507
  wordcloudGenerator: WordcloudGenerator;
503
508
  liveSummaryRequester: LiveSummaryRequester;
504
509
  danmakuCollector: DanmakuCollector;
505
- imageRenderer: ImageRenderer | null;
510
+ /**
511
+ * 渲染器 provider —— LiveEngine 在 image 服务上下线时通过 setImageRenderer
512
+ * 替换内部状态;getter `imageRenderer` 每次现取,所有 RoomContext 自动同步。
513
+ */
514
+ getImageRenderer: () => ImageRenderer | null;
506
515
  config: ListenerManagerConfig;
507
516
  emitEngineError: (message: string) => void;
508
517
  /**
@@ -546,11 +555,16 @@ declare class RoomContextBase {
546
555
  readonly liveSummaryRequester: LiveSummaryRequester;
547
556
  readonly danmakuCollector: DanmakuCollector;
548
557
  /**
549
- * 真实注入的渲染器引用,private 是因为外部应通过 `imageRenderer` getter 访问 ——
558
+ * 渲染器 provider —— private 是因为外部应通过 `imageRenderer` getter 访问 ——
550
559
  * 后者会在 `config.imageEnabled === false` 时返回 null,让所有
551
560
  * `if (this.imageRenderer?.generateXxx)` 自然落入文字回退分支。
561
+ * provider 形式让 LiveEngine 的 setImageRenderer 无需逐 RoomContext 推。
562
+ *
563
+ * **不要直接调 `this._getImageRenderer()` 绕过 imageEnabled 门控**,业务路径
564
+ * 必须通过 `this.imageRenderer` getter,否则用户在 dashboard 关掉卡片渲染时
565
+ * 这条路径仍会渲图。
552
566
  */
553
- private readonly _imageRenderer;
567
+ private readonly _getImageRenderer;
554
568
  readonly emitEngineError: (message: string) => void;
555
569
  private readonly _emitLiveState;
556
570
  private readonly _emitViewers;
@@ -950,6 +964,12 @@ declare class LiveEngine {
950
964
  private readonly danmakuCollector;
951
965
  private readonly liveSummaryRequester;
952
966
  private config;
967
+ /**
968
+ * Image 渲染器的当前引用 —— 单一可变 state,setImageRenderer 在此更新;
969
+ * 所有子组件(wordcloud / listener / room-context)通过 provider 函数现取,
970
+ * 无需逐组件 setter 推送。
971
+ */
972
+ private currentImageRenderer;
953
973
  constructor(opts: LiveEngineOptions);
954
974
  /**
955
975
  * Bootstrap the engine with the initial subscription set. Idempotent —
@@ -973,6 +993,15 @@ declare class LiveEngine {
973
993
  * 配置后调用,引擎随后的直播总结会立即用新实例 (或回退到模板) ,无需重启 server。
974
994
  */
975
995
  setCommentary(commentary: CommentaryGenerator | null): void;
996
+ /**
997
+ * 热替换 ImageRenderer 实例。adapter 在 image 服务上下线时调用。子组件 (词云 /
998
+ * room-context / 卡片渲染) 都通过共享 provider 现取,这里只需更新单一 state。
999
+ *
1000
+ * 主要给 koishi adapter 用 —— sibling service (-image) 启停时通过 ctx.inject
1001
+ * 后置注入。独立端 imageRenderer 是 engine 同进程一次性 wire,不会动态消失,
1002
+ * 不需要调用本方法 (cardStyle 热更走 imageRenderer.updateConfig)。
1003
+ */
1004
+ setImageRenderer(imageRenderer: ImageRenderer | null): void;
976
1005
  /** Final dispose; the engine instance must not be reused after this. */
977
1006
  stop(): void;
978
1007
  /** Diagnostic accessor, used by the koishi shell for `[conn] state` logging. */
package/lib/index.d.mts CHANGED
@@ -433,11 +433,16 @@ declare const WORDCLOUD_TOP_WORDS = 90;
433
433
  * platform (e.g. via `LiveContentBuilder.image`).
434
434
  */
435
435
  declare class WordcloudGenerator {
436
- private readonly imageRenderer;
436
+ private readonly getImageRenderer;
437
437
  private readonly isImageEnabled;
438
438
  private readonly logger;
439
439
  constructor(opts: {
440
- imageRenderer: ImageRenderer | null;
440
+ /**
441
+ * 渲染器 provider —— 每次 generate() 现取最新引用,使 LiveEngine 在 image
442
+ * 服务上下线时通过 setImageRenderer 替换内部状态,词云生成自动同步,无需子组件
443
+ * 接 setter。
444
+ */
445
+ getImageRenderer: () => ImageRenderer | null;
441
446
  /**
442
447
  * 卡片渲染总开关查询。返回 false 时直接跳过 puppeteer 调用,与缺失 imageRenderer
443
448
  * 等价。Adapter 通常用 `() => globals.defaults.cardStyle.enabled` 填充;缺省 () => true。
@@ -502,7 +507,11 @@ interface RoomContextOptions {
502
507
  wordcloudGenerator: WordcloudGenerator;
503
508
  liveSummaryRequester: LiveSummaryRequester;
504
509
  danmakuCollector: DanmakuCollector;
505
- imageRenderer: ImageRenderer | null;
510
+ /**
511
+ * 渲染器 provider —— LiveEngine 在 image 服务上下线时通过 setImageRenderer
512
+ * 替换内部状态;getter `imageRenderer` 每次现取,所有 RoomContext 自动同步。
513
+ */
514
+ getImageRenderer: () => ImageRenderer | null;
506
515
  config: ListenerManagerConfig;
507
516
  emitEngineError: (message: string) => void;
508
517
  /**
@@ -546,11 +555,16 @@ declare class RoomContextBase {
546
555
  readonly liveSummaryRequester: LiveSummaryRequester;
547
556
  readonly danmakuCollector: DanmakuCollector;
548
557
  /**
549
- * 真实注入的渲染器引用,private 是因为外部应通过 `imageRenderer` getter 访问 ——
558
+ * 渲染器 provider —— private 是因为外部应通过 `imageRenderer` getter 访问 ——
550
559
  * 后者会在 `config.imageEnabled === false` 时返回 null,让所有
551
560
  * `if (this.imageRenderer?.generateXxx)` 自然落入文字回退分支。
561
+ * provider 形式让 LiveEngine 的 setImageRenderer 无需逐 RoomContext 推。
562
+ *
563
+ * **不要直接调 `this._getImageRenderer()` 绕过 imageEnabled 门控**,业务路径
564
+ * 必须通过 `this.imageRenderer` getter,否则用户在 dashboard 关掉卡片渲染时
565
+ * 这条路径仍会渲图。
552
566
  */
553
- private readonly _imageRenderer;
567
+ private readonly _getImageRenderer;
554
568
  readonly emitEngineError: (message: string) => void;
555
569
  private readonly _emitLiveState;
556
570
  private readonly _emitViewers;
@@ -950,6 +964,12 @@ declare class LiveEngine {
950
964
  private readonly danmakuCollector;
951
965
  private readonly liveSummaryRequester;
952
966
  private config;
967
+ /**
968
+ * Image 渲染器的当前引用 —— 单一可变 state,setImageRenderer 在此更新;
969
+ * 所有子组件(wordcloud / listener / room-context)通过 provider 函数现取,
970
+ * 无需逐组件 setter 推送。
971
+ */
972
+ private currentImageRenderer;
953
973
  constructor(opts: LiveEngineOptions);
954
974
  /**
955
975
  * Bootstrap the engine with the initial subscription set. Idempotent —
@@ -973,6 +993,15 @@ declare class LiveEngine {
973
993
  * 配置后调用,引擎随后的直播总结会立即用新实例 (或回退到模板) ,无需重启 server。
974
994
  */
975
995
  setCommentary(commentary: CommentaryGenerator | null): void;
996
+ /**
997
+ * 热替换 ImageRenderer 实例。adapter 在 image 服务上下线时调用。子组件 (词云 /
998
+ * room-context / 卡片渲染) 都通过共享 provider 现取,这里只需更新单一 state。
999
+ *
1000
+ * 主要给 koishi adapter 用 —— sibling service (-image) 启停时通过 ctx.inject
1001
+ * 后置注入。独立端 imageRenderer 是 engine 同进程一次性 wire,不会动态消失,
1002
+ * 不需要调用本方法 (cardStyle 热更走 imageRenderer.updateConfig)。
1003
+ */
1004
+ setImageRenderer(imageRenderer: ImageRenderer | null): void;
976
1005
  /** Final dispose; the engine instance must not be reused after this. */
977
1006
  stop(): void;
978
1007
  /** Diagnostic accessor, used by the koishi shell for `[conn] state` logging. */
package/lib/index.mjs CHANGED
@@ -144,11 +144,16 @@ var RoomContextBase = class {
144
144
  liveSummaryRequester;
145
145
  danmakuCollector;
146
146
  /**
147
- * 真实注入的渲染器引用,private 是因为外部应通过 `imageRenderer` getter 访问 ——
147
+ * 渲染器 provider —— private 是因为外部应通过 `imageRenderer` getter 访问 ——
148
148
  * 后者会在 `config.imageEnabled === false` 时返回 null,让所有
149
149
  * `if (this.imageRenderer?.generateXxx)` 自然落入文字回退分支。
150
+ * provider 形式让 LiveEngine 的 setImageRenderer 无需逐 RoomContext 推。
151
+ *
152
+ * **不要直接调 `this._getImageRenderer()` 绕过 imageEnabled 门控**,业务路径
153
+ * 必须通过 `this.imageRenderer` getter,否则用户在 dashboard 关掉卡片渲染时
154
+ * 这条路径仍会渲图。
150
155
  */
151
- _imageRenderer;
156
+ _getImageRenderer;
152
157
  emitEngineError;
153
158
  _emitLiveState;
154
159
  _emitViewers;
@@ -175,7 +180,7 @@ var RoomContextBase = class {
175
180
  this.wordcloudGenerator = opts.wordcloudGenerator;
176
181
  this.liveSummaryRequester = opts.liveSummaryRequester;
177
182
  this.danmakuCollector = opts.danmakuCollector;
178
- this._imageRenderer = opts.imageRenderer;
183
+ this._getImageRenderer = opts.getImageRenderer;
179
184
  this.config = opts.config;
180
185
  this.emitEngineError = opts.emitEngineError;
181
186
  this._emitLiveState = opts.emitLiveState;
@@ -195,7 +200,7 @@ var RoomContextBase = class {
195
200
  }
196
201
  /** 受 `config.imageEnabled` 门控的渲染器视图;关闭时返回 null。 */
197
202
  get imageRenderer() {
198
- return this.config.imageEnabled === false ? null : this._imageRenderer;
203
+ return this.config.imageEnabled === false ? null : this._getImageRenderer();
199
204
  }
200
205
  updateConfig(config) {
201
206
  this.config = config;
@@ -1552,11 +1557,11 @@ const WORDCLOUD_TOP_WORDS = 90;
1552
1557
  * platform (e.g. via `LiveContentBuilder.image`).
1553
1558
  */
1554
1559
  var WordcloudGenerator = class {
1555
- imageRenderer;
1560
+ getImageRenderer;
1556
1561
  isImageEnabled;
1557
1562
  logger;
1558
1563
  constructor(opts) {
1559
- this.imageRenderer = opts.imageRenderer;
1564
+ this.getImageRenderer = opts.getImageRenderer;
1560
1565
  this.isImageEnabled = opts.isImageEnabled ?? (() => true);
1561
1566
  this.logger = opts.logger;
1562
1567
  }
@@ -1578,9 +1583,10 @@ var WordcloudGenerator = class {
1578
1583
  this.logger.debug("[wordcloud] cardStyle.enabled=false,跳过词云图片生成");
1579
1584
  return;
1580
1585
  }
1581
- if (!this.imageRenderer?.generateWordCloudImg) return void 0;
1586
+ const renderer = this.getImageRenderer();
1587
+ if (!renderer?.generateWordCloudImg) return void 0;
1582
1588
  try {
1583
- return await this.imageRenderer.generateWordCloudImg(sortedWords.slice(0, 90), masterName, masterAvatarUrl);
1589
+ return await renderer.generateWordCloudImg(sortedWords.slice(0, 90), masterName, masterAvatarUrl);
1584
1590
  } catch (e) {
1585
1591
  this.logger.error(`[wordcloud] 生成词云失败:${e.message}`);
1586
1592
  return;
@@ -1610,14 +1616,22 @@ var LiveEngine = class {
1610
1616
  danmakuCollector;
1611
1617
  liveSummaryRequester;
1612
1618
  config;
1619
+ /**
1620
+ * Image 渲染器的当前引用 —— 单一可变 state,setImageRenderer 在此更新;
1621
+ * 所有子组件(wordcloud / listener / room-context)通过 provider 函数现取,
1622
+ * 无需逐组件 setter 推送。
1623
+ */
1624
+ currentImageRenderer;
1613
1625
  constructor(opts) {
1614
1626
  this.logger = opts.serviceCtx.logger;
1615
1627
  this.config = opts.config;
1628
+ this.currentImageRenderer = opts.imageRenderer ?? null;
1629
+ const getImageRenderer = () => this.currentImageRenderer;
1616
1630
  const stopwords = mergeStopWords(opts.config.wordcloudStopWords);
1617
1631
  this.danmakuCollector = new DanmakuCollector(stopwords);
1618
1632
  const templateRenderer = new LiveTemplateRenderer();
1619
1633
  const wordcloudGenerator = new WordcloudGenerator({
1620
- imageRenderer: opts.imageRenderer ?? null,
1634
+ getImageRenderer,
1621
1635
  isImageEnabled: () => this.config.imageEnabled !== false,
1622
1636
  logger: this.logger
1623
1637
  });
@@ -1637,7 +1651,7 @@ var LiveEngine = class {
1637
1651
  wordcloudGenerator,
1638
1652
  liveSummaryRequester,
1639
1653
  danmakuCollector: this.danmakuCollector,
1640
- imageRenderer: opts.imageRenderer ?? null,
1654
+ getImageRenderer,
1641
1655
  config: toListenerConfig(opts.config),
1642
1656
  emitEngineError: opts.emitEngineError,
1643
1657
  emitLiveState: opts.emitLiveState,
@@ -1720,6 +1734,17 @@ var LiveEngine = class {
1720
1734
  setCommentary(commentary) {
1721
1735
  this.liveSummaryRequester.setCommentary(commentary);
1722
1736
  }
1737
+ /**
1738
+ * 热替换 ImageRenderer 实例。adapter 在 image 服务上下线时调用。子组件 (词云 /
1739
+ * room-context / 卡片渲染) 都通过共享 provider 现取,这里只需更新单一 state。
1740
+ *
1741
+ * 主要给 koishi adapter 用 —— sibling service (-image) 启停时通过 ctx.inject
1742
+ * 后置注入。独立端 imageRenderer 是 engine 同进程一次性 wire,不会动态消失,
1743
+ * 不需要调用本方法 (cardStyle 热更走 imageRenderer.updateConfig)。
1744
+ */
1745
+ setImageRenderer(imageRenderer) {
1746
+ this.currentImageRenderer = imageRenderer;
1747
+ }
1723
1748
  /** Final dispose; the engine instance must not be reused after this. */
1724
1749
  stop() {
1725
1750
  this.listener.disposeAll();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bilibili-notify/live",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.0.1-alpha.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/Akokk0/bilibili-notify"
@@ -32,8 +32,8 @@
32
32
  "protobufjs": "^7.4.0",
33
33
  "@bilibili-notify/api": "^0.2.0-alpha.2",
34
34
  "@bilibili-notify/ai": "^0.0.1-alpha.1",
35
- "@bilibili-notify/image": "^0.0.1-alpha.2",
36
- "@bilibili-notify/internal": "^0.1.0-alpha.2"
35
+ "@bilibili-notify/internal": "^0.1.0-alpha.2",
36
+ "@bilibili-notify/image": "^0.0.1-alpha.2"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/luxon": "^3.4.2",