koishi-plugin-subscription 0.0.5 → 0.0.6

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.d.ts CHANGED
@@ -41,7 +41,8 @@ declare class SubscriptionService extends Service {
41
41
  constructor(ctx: Context, config: Config);
42
42
  initMap(): void;
43
43
  private getApp;
44
- private getAccount;
44
+ getAccount(app: string, account: string): string;
45
+ getName(app: string, account: string): string;
45
46
  getAvailableAccounts(app: string): string[];
46
47
  getSubscribedGroups(app: string, account: string): Promise<string[]>;
47
48
  broadcast(app: string, account: string, content: Fragment): Promise<void>;
package/lib/index.js CHANGED
@@ -27,6 +27,21 @@ __export(src_exports, {
27
27
  });
28
28
  module.exports = __toCommonJS(src_exports);
29
29
  var import_koishi = require("koishi");
30
+
31
+ // src/retry.ts
32
+ async function retry(retries, fn, delay = 500) {
33
+ try {
34
+ return await fn();
35
+ } catch (err) {
36
+ console.log(`剩余${retries}次尝试`, err);
37
+ if (retries <= 1) throw err;
38
+ await new Promise((r) => setTimeout(r, delay));
39
+ return retry(retries - 1, fn, delay * 2);
40
+ }
41
+ }
42
+ __name(retry, "retry");
43
+
44
+ // src/index.tsx
30
45
  var import_jsx_runtime = require("@satorijs/element/jsx-runtime");
31
46
  var Config = import_koishi.Schema.intersect([
32
47
  import_koishi.Schema.object({
@@ -112,6 +127,10 @@ var SubscriptionService = class extends import_koishi.Service {
112
127
  getAccount(app, account) {
113
128
  return this.accountMap.get((app + account).toLowerCase());
114
129
  }
130
+ getName(app, account) {
131
+ app = this.getApp(app);
132
+ return this.subsConfig.apps[app].allowedAccounts.find((item) => item.id === this.getAccount(app, account))?.name;
133
+ }
115
134
  // 获取对应应用可以订阅的账号
116
135
  getAvailableAccounts(app) {
117
136
  app = this.getApp(app);
@@ -167,18 +186,39 @@ var SubscriptionService = class extends import_koishi.Service {
167
186
  return (await Promise.all(this.ctx.bots.map(async (bot) => {
168
187
  const targets = assignMap[bot.platform]?.[bot.selfId];
169
188
  if (!targets) return Promise.resolve([]);
170
- const messageIds = await bot.sendPrivateMessage(bot.selfId, content);
171
- const forwardContent = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { forward: true, children: messageIds.map((id) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { id: `${id}` })) });
172
- const sessions = targets.map(({ id, guildId, locales }) => {
173
- const session = bot.session({
189
+ try {
190
+ const selfChannelId = `private:${bot.selfId}`, session = bot.session({
174
191
  type: "message",
175
- channel: { id, type: import_koishi.Universal.Channel.Type.TEXT },
176
- guild: { id: guildId }
192
+ channel: {
193
+ id: selfChannelId,
194
+ type: import_koishi.Universal.Channel.Type.DIRECT
195
+ },
196
+ user: { id: bot.selfId }
177
197
  });
178
- session.locales = locales;
179
- return session;
180
- });
181
- return bot.broadcast(sessions, forwardContent);
198
+ const messageIds = Array.isArray(content) ? (await Promise.all(content.map(
199
+ (msg) => {
200
+ try {
201
+ return retry(3, () => bot.sendMessage(selfChannelId, msg, void 0, { session }));
202
+ } catch (e) {
203
+ return Promise.resolve([]);
204
+ }
205
+ }
206
+ ))).flat(1) : await retry(3, () => bot.sendMessage(selfChannelId, content, void 0, { session }));
207
+ const forwardContent = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { forward: true, children: messageIds.map((id) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("message", { id: `${id}` })) });
208
+ const sessions = targets.map(({ id, guildId, locales }) => {
209
+ const session2 = bot.session({
210
+ type: "message",
211
+ channel: { id, type: import_koishi.Universal.Channel.Type.TEXT },
212
+ guild: { id: guildId }
213
+ });
214
+ session2.locales = locales;
215
+ return session2;
216
+ });
217
+ return bot.broadcast(sessions, forwardContent);
218
+ } catch (e) {
219
+ this.ctx.logger("broadcastForward").warn("broadcast error:", bot.selfId, Array.isArray(content) ? content.length : 1, e);
220
+ return Promise.resolve([]);
221
+ }
182
222
  }))).flat(1);
183
223
  }
184
224
  // 添加订阅
@@ -257,19 +297,21 @@ var SubscriptionService = class extends import_koishi.Service {
257
297
  return `${channel.platform}:${channel.id}`;
258
298
  }
259
299
  registerCommands(ctx, config) {
260
- const sub = ctx.command("subscription <app:string> [...accounts]", "添加订阅,格式:订阅 <应用名> <账号>").alias("订阅").alias("添加订阅").userFields(["authority"]).example("推特订阅 爱美").example("订阅 twitter aimi_sound").action(async ({ session, options }, app, ...accounts) => {
300
+ const sub = ctx.command("subscription <app:string> [...accounts]", "添加订阅,账号可以使用 用户名 用户id 或是别名,格式:订阅 <应用名> <账号> [...更多账号]").alias("订阅").alias("添加订阅").userFields(["authority"]).example("推特订阅 爱美 伊藤彩沙").example("订阅 twitter aimi_sound").action(async ({ session, options }, app, ...accounts) => {
261
301
  if (!await this.authCheck(session, config)) {
262
302
  return "权限不足";
263
303
  }
264
304
  if (!app || !accounts || accounts.length == 0) {
265
305
  return "请指定应用名和账号,格式:订阅 <应用名> <账号> [...更多账号]";
266
306
  }
307
+ accounts;
267
308
  const groupId = this.getChannelId(session.channel);
268
309
  if (!groupId) {
269
310
  return "请在群聊中使用当前指令";
270
311
  }
271
312
  let result = "";
272
- for (const account of accounts) {
313
+ for (let account of accounts) {
314
+ app = this.getApp(app), account = this.getName(app, account);
273
315
  const { status, msg } = await this.addSubscription(app, account, groupId);
274
316
  if (status) {
275
317
  result += `成功为群组 ${groupId} 添加订阅:${app} - ${account}
@@ -288,6 +330,7 @@ var SubscriptionService = class extends import_koishi.Service {
288
330
  if (!app || !account) {
289
331
  return "请指定应用名和账号,格式:取消订阅 <应用名> <账号>";
290
332
  }
333
+ app = this.getApp(app), account = this.getName(app, account);
291
334
  const groupId = this.getChannelId(session.channel);
292
335
  if (!groupId) {
293
336
  return "请在群聊中使用当前指令";
@@ -351,7 +394,23 @@ var SubscriptionService = class extends import_koishi.Service {
351
394
  return result;
352
395
  }
353
396
  const html = generateSubscriptionHTML(groupId, availableAccounts, subscribedByApp);
354
- return await ctx.puppeteer.render(html);
397
+ const page = await ctx.puppeteer.page();
398
+ try {
399
+ await page.setViewport({
400
+ width: 1e3,
401
+ height: 800
402
+ });
403
+ await page.setContent(html, {
404
+ waitUntil: "networkidle0"
405
+ });
406
+ const image = await page.screenshot({
407
+ type: "jpeg",
408
+ fullPage: true
409
+ });
410
+ return `<image url="data:image/png;base64,${image.toString("base64")}" />`;
411
+ } finally {
412
+ await page.close();
413
+ }
355
414
  });
356
415
  function generateSubscriptionHTML(groupId, availableAccounts, subscribedByApp) {
357
416
  return `
@@ -372,7 +431,7 @@ var SubscriptionService = class extends import_koishi.Service {
372
431
  padding: 20px;
373
432
  }
374
433
  .container {
375
- max-width: 1200px;
434
+ max-width: 1000px;
376
435
  margin: 0 auto;
377
436
  }
378
437
  .header {
@@ -381,18 +440,18 @@ var SubscriptionService = class extends import_koishi.Service {
381
440
  color: #2c3e50;
382
441
  }
383
442
  .header h1 {
384
- font-size: 24px;
385
- margin-bottom: 8px;
386
- font-weight: 600;
443
+ font-size: 36px;
444
+ margin-bottom: 12px;
445
+ font-weight: 900;
387
446
  }
388
447
  .header .subtitle {
389
- font-size: 14px;
448
+ font-size: 21px;
390
449
  color: #7f8c8d;
391
450
  }
392
451
  .apps-container {
393
452
  background: white;
394
- border-radius: 8px;
395
- box-shadow: 0 2px 12px rgba(0,0,0,0.08);
453
+ border-radius: 12px;
454
+ box-shadow: 0 3px 18px rgba(0,0,0,0.08);
396
455
  overflow: hidden;
397
456
  }
398
457
  .app-section {
@@ -402,46 +461,48 @@ var SubscriptionService = class extends import_koishi.Service {
402
461
  border-bottom: none;
403
462
  }
404
463
  .app-title {
405
- font-size: 16px;
464
+ font-size: 24px;
406
465
  font-weight: 600;
407
466
  color: #34495e;
408
- padding: 12px 16px;
467
+ padding: 18px 24px;
409
468
  background: #f8f9fa;
410
469
  border-bottom: 1px solid #eaeaea;
411
470
  display: flex;
412
471
  align-items: center;
413
- gap: 8px;
472
+ gap: 12px;
414
473
  }
415
474
  .app-title::before {
416
475
  content: "▸";
417
- font-size: 14px;
476
+ font-size: 21px;
418
477
  color: #3498db;
419
478
  }
420
479
  .grid {
421
480
  display: grid;
422
- grid-template-columns: repeat(3, 1fr);
481
+ grid-template-columns: repeat(2, 1fr);
423
482
  gap: 0;
424
483
  }
425
484
  .account-card {
426
- padding: 14px;
485
+ padding: 21px;
427
486
  border-right: 1px solid #f0f0f0;
428
487
  border-bottom: 1px solid #f0f0f0;
429
488
  transition: all 0.2s ease;
430
489
  position: relative;
431
- min-height: 80px;
490
+ min-height: 120px;
432
491
  display: flex;
433
492
  flex-direction: column;
434
493
  }
435
- .account-card:nth-child(odd) {
494
+ .account-card:nth-child(4n+1),
495
+ .account-card:nth-child(4n+4) {
436
496
  background: #f8f9fa;
437
497
  }
438
- .account-card:nth-child(even) {
498
+ .account-card:nth-child(4n+2),
499
+ .account-card:nth-child(4n+3) {
439
500
  background: #f0f2f5;
440
501
  }
441
502
  .account-card:hover {
442
503
  background: #e6f3ff !important;
443
504
  }
444
- .account-card:nth-child(3n) {
505
+ .account-card:nth-child(2n) {
445
506
  border-right: none;
446
507
  }
447
508
  .account-card:last-child {
@@ -451,12 +512,12 @@ var SubscriptionService = class extends import_koishi.Service {
451
512
  display: flex;
452
513
  justify-content: space-between;
453
514
  align-items: center;
454
- margin-bottom: 8px;
515
+ margin-bottom: 12px;
455
516
  flex-wrap: wrap;
456
517
  }
457
518
  .name {
458
- font-size: 14px;
459
- font-weight: 600;
519
+ font-size: 21px;
520
+ font-weight: 900;
460
521
  color: #2c3e50;
461
522
  line-height: 1.3;
462
523
  max-width: 60%;
@@ -465,12 +526,12 @@ var SubscriptionService = class extends import_koishi.Service {
465
526
  white-space: nowrap;
466
527
  }
467
528
  .id {
468
- font-size: 12px;
529
+ font-size: 21px;
469
530
  color: #5a6c7d;
470
531
  font-family: 'Courier New', monospace;
471
532
  background: #f8f9fa;
472
- padding: 3px 6px;
473
- border-radius: 3px;
533
+ padding: 4.5px 9px;
534
+ border-radius: 4.5px;
474
535
  line-height: 1.3;
475
536
  max-width: 35%;
476
537
  overflow: hidden;
@@ -483,7 +544,7 @@ var SubscriptionService = class extends import_koishi.Service {
483
544
  }
484
545
  .name-id-container.vertical .name {
485
546
  max-width: 100%;
486
- margin-bottom: 4px;
547
+ margin-bottom: 6px;
487
548
  }
488
549
  .name-id-container.vertical .id {
489
550
  max-width: 100%;
@@ -492,49 +553,49 @@ var SubscriptionService = class extends import_koishi.Service {
492
553
  .alias-status-container {
493
554
  display: flex;
494
555
  justify-content: space-between;
495
- margin-top: 8px;
556
+ margin-top: 12px;
496
557
  flex-grow: 1;
497
558
  }
498
559
  .alias-container {
499
560
  flex: 1;
500
- max-width: calc(100% - 70px);
561
+ max-width: calc(100% - 105px);
501
562
  align-self: flex-start;
502
563
  }
503
564
  .alias {
504
- font-size: 11px;
565
+ font-size: 20px;
505
566
  color: #6c757d;
506
567
  display: flex;
507
568
  flex-wrap: wrap;
508
- gap: 4px;
569
+ gap: 6px;
509
570
  align-items: flex-start;
510
571
  }
511
572
  .alias-tag {
512
573
  background: #e8f4fd;
513
574
  color: #1971c2;
514
- padding: 2px 6px;
515
- border-radius: 10px;
575
+ padding: 3px 9px;
576
+ border-radius: 15px;
516
577
  border: 1px solid #a5d8ff;
517
578
  white-space: nowrap;
518
- margin-bottom: 2px;
579
+ margin-bottom: 3px;
519
580
  }
520
581
  .no-alias {
521
- font-size: 11px;
582
+ font-size: 20px;
522
583
  color: #adb5bd;
523
584
  font-style: italic;
524
585
  }
525
586
  .status-container {
526
587
  display: flex;
527
588
  align-items: flex-end;
528
- margin-left: 8px;
589
+ margin-left: 12px;
529
590
  }
530
591
  .status {
531
592
  display: inline-flex;
532
593
  align-items: center;
533
- gap: 6px;
534
- padding: 3px 10px;
535
- border-radius: 16px;
536
- font-size: 11px;
537
- font-weight: 600;
594
+ gap: 9px;
595
+ padding: 4.5px 15px;
596
+ border-radius: 24px;
597
+ font-size: 20px;
598
+ font-weight: 900;
538
599
  white-space: nowrap;
539
600
  flex-shrink: 0;
540
601
  }
@@ -552,7 +613,7 @@ var SubscriptionService = class extends import_koishi.Service {
552
613
  text-align: center;
553
614
  color: #6c757d;
554
615
  font-style: italic;
555
- padding: 30px;
616
+ padding: 45px;
556
617
  background: #f8f9fa;
557
618
  grid-column: 1 / -1;
558
619
  }
@@ -624,8 +685,20 @@ var SubscriptionService = class extends import_koishi.Service {
624
685
  if (subscriptions.length === 0) {
625
686
  return `群组 ${groupId} 暂无订阅`;
626
687
  }
627
- await ctx.database.remove("subscription_service", { groupId });
628
- return `已删除群组 ${groupId} 的所有订阅(共 ${subscriptions.length} 个)`;
688
+ const confirm = await session.send(
689
+ `确认要清空当前群聊的所有订阅吗?
690
+ 请输入 "是" 或 "确认" 或 "yes" 来确认删除,输入其他内容取消。`
691
+ );
692
+ const response = await session.prompt(3e4);
693
+ if (!response) {
694
+ return "操作已取消(超时)。";
695
+ }
696
+ if (["是", "确认", "yes", "y"].includes(response.toLowerCase())) {
697
+ await ctx.database.remove("subscription_service", { groupId });
698
+ return `已删除群组 ${groupId} 的所有订阅(共 ${subscriptions.length} 个)`;
699
+ } else {
700
+ return "操作已取消。";
701
+ }
629
702
  });
630
703
  ctx.command("subscription.stats", "查看订阅统计", {
631
704
  permissions: [`authority:${config.minAuthority}`],
package/lib/retry.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function retry<T>(retries: number, fn: () => Promise<T> | T, delay?: number): Promise<T>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-subscription",
3
3
  "description": "给多个应用提供订阅群组管理",
4
- "version": "0.0.5",
4
+ "version": "0.0.6",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [