koishi-plugin-subscription 0.0.4 → 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 +2 -1
- package/lib/index.js +129 -59
- package/lib/retry.d.ts +1 -0
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
171
|
-
|
|
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: {
|
|
176
|
-
|
|
192
|
+
channel: {
|
|
193
|
+
id: selfChannelId,
|
|
194
|
+
type: import_koishi.Universal.Channel.Type.DIRECT
|
|
195
|
+
},
|
|
196
|
+
user: { id: bot.selfId }
|
|
177
197
|
});
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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]", "
|
|
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 (
|
|
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}
|
|
@@ -281,13 +323,14 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
281
323
|
}
|
|
282
324
|
return result;
|
|
283
325
|
});
|
|
284
|
-
const unsub = ctx.command("subscription.remove <app:string> <account:string>", "删除订阅").alias("删除订阅").alias("取消订阅").userFields(["authority"]).action(async ({ session, options }, app, account) => {
|
|
326
|
+
const unsub = ctx.command("subscription.remove <app:string> <account:string>", "删除订阅").alias("删除订阅").alias("取消订阅").userFields(["authority"]).example("取消推特订阅 爱美").example("取消订阅 twitter aimi_sound").action(async ({ session, options }, app, account) => {
|
|
285
327
|
if (!await this.authCheck(session, config)) {
|
|
286
328
|
return "权限不足";
|
|
287
329
|
}
|
|
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 "请在群聊中使用当前指令";
|
|
@@ -333,9 +376,7 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
333
376
|
}));
|
|
334
377
|
}
|
|
335
378
|
if (!ctx.puppeteer) {
|
|
336
|
-
let result =
|
|
337
|
-
|
|
338
|
-
`;
|
|
379
|
+
let result = ``;
|
|
339
380
|
for (const app in availableAccounts) {
|
|
340
381
|
result += `【${app}】
|
|
341
382
|
`;
|
|
@@ -353,7 +394,23 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
353
394
|
return result;
|
|
354
395
|
}
|
|
355
396
|
const html = generateSubscriptionHTML(groupId, availableAccounts, subscribedByApp);
|
|
356
|
-
|
|
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
|
+
}
|
|
357
414
|
});
|
|
358
415
|
function generateSubscriptionHTML(groupId, availableAccounts, subscribedByApp) {
|
|
359
416
|
return `
|
|
@@ -374,7 +431,7 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
374
431
|
padding: 20px;
|
|
375
432
|
}
|
|
376
433
|
.container {
|
|
377
|
-
max-width:
|
|
434
|
+
max-width: 1000px;
|
|
378
435
|
margin: 0 auto;
|
|
379
436
|
}
|
|
380
437
|
.header {
|
|
@@ -383,18 +440,18 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
383
440
|
color: #2c3e50;
|
|
384
441
|
}
|
|
385
442
|
.header h1 {
|
|
386
|
-
font-size:
|
|
387
|
-
margin-bottom:
|
|
388
|
-
font-weight:
|
|
443
|
+
font-size: 36px;
|
|
444
|
+
margin-bottom: 12px;
|
|
445
|
+
font-weight: 900;
|
|
389
446
|
}
|
|
390
447
|
.header .subtitle {
|
|
391
|
-
font-size:
|
|
448
|
+
font-size: 21px;
|
|
392
449
|
color: #7f8c8d;
|
|
393
450
|
}
|
|
394
451
|
.apps-container {
|
|
395
452
|
background: white;
|
|
396
|
-
border-radius:
|
|
397
|
-
box-shadow: 0
|
|
453
|
+
border-radius: 12px;
|
|
454
|
+
box-shadow: 0 3px 18px rgba(0,0,0,0.08);
|
|
398
455
|
overflow: hidden;
|
|
399
456
|
}
|
|
400
457
|
.app-section {
|
|
@@ -404,46 +461,48 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
404
461
|
border-bottom: none;
|
|
405
462
|
}
|
|
406
463
|
.app-title {
|
|
407
|
-
font-size:
|
|
464
|
+
font-size: 24px;
|
|
408
465
|
font-weight: 600;
|
|
409
466
|
color: #34495e;
|
|
410
|
-
padding:
|
|
467
|
+
padding: 18px 24px;
|
|
411
468
|
background: #f8f9fa;
|
|
412
469
|
border-bottom: 1px solid #eaeaea;
|
|
413
470
|
display: flex;
|
|
414
471
|
align-items: center;
|
|
415
|
-
gap:
|
|
472
|
+
gap: 12px;
|
|
416
473
|
}
|
|
417
474
|
.app-title::before {
|
|
418
475
|
content: "▸";
|
|
419
|
-
font-size:
|
|
476
|
+
font-size: 21px;
|
|
420
477
|
color: #3498db;
|
|
421
478
|
}
|
|
422
479
|
.grid {
|
|
423
480
|
display: grid;
|
|
424
|
-
grid-template-columns: repeat(
|
|
481
|
+
grid-template-columns: repeat(2, 1fr);
|
|
425
482
|
gap: 0;
|
|
426
483
|
}
|
|
427
484
|
.account-card {
|
|
428
|
-
padding:
|
|
485
|
+
padding: 21px;
|
|
429
486
|
border-right: 1px solid #f0f0f0;
|
|
430
487
|
border-bottom: 1px solid #f0f0f0;
|
|
431
488
|
transition: all 0.2s ease;
|
|
432
489
|
position: relative;
|
|
433
|
-
min-height:
|
|
490
|
+
min-height: 120px;
|
|
434
491
|
display: flex;
|
|
435
492
|
flex-direction: column;
|
|
436
493
|
}
|
|
437
|
-
.account-card:nth-child(
|
|
494
|
+
.account-card:nth-child(4n+1),
|
|
495
|
+
.account-card:nth-child(4n+4) {
|
|
438
496
|
background: #f8f9fa;
|
|
439
497
|
}
|
|
440
|
-
.account-card:nth-child(
|
|
498
|
+
.account-card:nth-child(4n+2),
|
|
499
|
+
.account-card:nth-child(4n+3) {
|
|
441
500
|
background: #f0f2f5;
|
|
442
501
|
}
|
|
443
502
|
.account-card:hover {
|
|
444
503
|
background: #e6f3ff !important;
|
|
445
504
|
}
|
|
446
|
-
.account-card:nth-child(
|
|
505
|
+
.account-card:nth-child(2n) {
|
|
447
506
|
border-right: none;
|
|
448
507
|
}
|
|
449
508
|
.account-card:last-child {
|
|
@@ -453,12 +512,12 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
453
512
|
display: flex;
|
|
454
513
|
justify-content: space-between;
|
|
455
514
|
align-items: center;
|
|
456
|
-
margin-bottom:
|
|
515
|
+
margin-bottom: 12px;
|
|
457
516
|
flex-wrap: wrap;
|
|
458
517
|
}
|
|
459
518
|
.name {
|
|
460
|
-
font-size:
|
|
461
|
-
font-weight:
|
|
519
|
+
font-size: 21px;
|
|
520
|
+
font-weight: 900;
|
|
462
521
|
color: #2c3e50;
|
|
463
522
|
line-height: 1.3;
|
|
464
523
|
max-width: 60%;
|
|
@@ -467,12 +526,12 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
467
526
|
white-space: nowrap;
|
|
468
527
|
}
|
|
469
528
|
.id {
|
|
470
|
-
font-size:
|
|
529
|
+
font-size: 21px;
|
|
471
530
|
color: #5a6c7d;
|
|
472
531
|
font-family: 'Courier New', monospace;
|
|
473
532
|
background: #f8f9fa;
|
|
474
|
-
padding:
|
|
475
|
-
border-radius:
|
|
533
|
+
padding: 4.5px 9px;
|
|
534
|
+
border-radius: 4.5px;
|
|
476
535
|
line-height: 1.3;
|
|
477
536
|
max-width: 35%;
|
|
478
537
|
overflow: hidden;
|
|
@@ -485,7 +544,7 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
485
544
|
}
|
|
486
545
|
.name-id-container.vertical .name {
|
|
487
546
|
max-width: 100%;
|
|
488
|
-
margin-bottom:
|
|
547
|
+
margin-bottom: 6px;
|
|
489
548
|
}
|
|
490
549
|
.name-id-container.vertical .id {
|
|
491
550
|
max-width: 100%;
|
|
@@ -494,49 +553,49 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
494
553
|
.alias-status-container {
|
|
495
554
|
display: flex;
|
|
496
555
|
justify-content: space-between;
|
|
497
|
-
margin-top:
|
|
556
|
+
margin-top: 12px;
|
|
498
557
|
flex-grow: 1;
|
|
499
558
|
}
|
|
500
559
|
.alias-container {
|
|
501
560
|
flex: 1;
|
|
502
|
-
max-width: calc(100% -
|
|
561
|
+
max-width: calc(100% - 105px);
|
|
503
562
|
align-self: flex-start;
|
|
504
563
|
}
|
|
505
564
|
.alias {
|
|
506
|
-
font-size:
|
|
565
|
+
font-size: 20px;
|
|
507
566
|
color: #6c757d;
|
|
508
567
|
display: flex;
|
|
509
568
|
flex-wrap: wrap;
|
|
510
|
-
gap:
|
|
569
|
+
gap: 6px;
|
|
511
570
|
align-items: flex-start;
|
|
512
571
|
}
|
|
513
572
|
.alias-tag {
|
|
514
573
|
background: #e8f4fd;
|
|
515
574
|
color: #1971c2;
|
|
516
|
-
padding:
|
|
517
|
-
border-radius:
|
|
575
|
+
padding: 3px 9px;
|
|
576
|
+
border-radius: 15px;
|
|
518
577
|
border: 1px solid #a5d8ff;
|
|
519
578
|
white-space: nowrap;
|
|
520
|
-
margin-bottom:
|
|
579
|
+
margin-bottom: 3px;
|
|
521
580
|
}
|
|
522
581
|
.no-alias {
|
|
523
|
-
font-size:
|
|
582
|
+
font-size: 20px;
|
|
524
583
|
color: #adb5bd;
|
|
525
584
|
font-style: italic;
|
|
526
585
|
}
|
|
527
586
|
.status-container {
|
|
528
587
|
display: flex;
|
|
529
588
|
align-items: flex-end;
|
|
530
|
-
margin-left:
|
|
589
|
+
margin-left: 12px;
|
|
531
590
|
}
|
|
532
591
|
.status {
|
|
533
592
|
display: inline-flex;
|
|
534
593
|
align-items: center;
|
|
535
|
-
gap:
|
|
536
|
-
padding:
|
|
537
|
-
border-radius:
|
|
538
|
-
font-size:
|
|
539
|
-
font-weight:
|
|
594
|
+
gap: 9px;
|
|
595
|
+
padding: 4.5px 15px;
|
|
596
|
+
border-radius: 24px;
|
|
597
|
+
font-size: 20px;
|
|
598
|
+
font-weight: 900;
|
|
540
599
|
white-space: nowrap;
|
|
541
600
|
flex-shrink: 0;
|
|
542
601
|
}
|
|
@@ -554,7 +613,7 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
554
613
|
text-align: center;
|
|
555
614
|
color: #6c757d;
|
|
556
615
|
font-style: italic;
|
|
557
|
-
padding:
|
|
616
|
+
padding: 45px;
|
|
558
617
|
background: #f8f9fa;
|
|
559
618
|
grid-column: 1 / -1;
|
|
560
619
|
}
|
|
@@ -564,7 +623,6 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
564
623
|
<div class="container">
|
|
565
624
|
<div class="header">
|
|
566
625
|
<h1>订阅状态总览</h1>
|
|
567
|
-
<div class="subtitle">群组 ID: ${groupId}</div>
|
|
568
626
|
</div>
|
|
569
627
|
|
|
570
628
|
<div class="apps-container">
|
|
@@ -627,8 +685,20 @@ var SubscriptionService = class extends import_koishi.Service {
|
|
|
627
685
|
if (subscriptions.length === 0) {
|
|
628
686
|
return `群组 ${groupId} 暂无订阅`;
|
|
629
687
|
}
|
|
630
|
-
await
|
|
631
|
-
|
|
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
|
+
}
|
|
632
702
|
});
|
|
633
703
|
ctx.command("subscription.stats", "查看订阅统计", {
|
|
634
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>;
|