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 +2 -1
- package/lib/index.js +127 -54
- 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}
|
|
@@ -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
|
-
|
|
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:
|
|
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:
|
|
385
|
-
margin-bottom:
|
|
386
|
-
font-weight:
|
|
443
|
+
font-size: 36px;
|
|
444
|
+
margin-bottom: 12px;
|
|
445
|
+
font-weight: 900;
|
|
387
446
|
}
|
|
388
447
|
.header .subtitle {
|
|
389
|
-
font-size:
|
|
448
|
+
font-size: 21px;
|
|
390
449
|
color: #7f8c8d;
|
|
391
450
|
}
|
|
392
451
|
.apps-container {
|
|
393
452
|
background: white;
|
|
394
|
-
border-radius:
|
|
395
|
-
box-shadow: 0
|
|
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:
|
|
464
|
+
font-size: 24px;
|
|
406
465
|
font-weight: 600;
|
|
407
466
|
color: #34495e;
|
|
408
|
-
padding:
|
|
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:
|
|
472
|
+
gap: 12px;
|
|
414
473
|
}
|
|
415
474
|
.app-title::before {
|
|
416
475
|
content: "▸";
|
|
417
|
-
font-size:
|
|
476
|
+
font-size: 21px;
|
|
418
477
|
color: #3498db;
|
|
419
478
|
}
|
|
420
479
|
.grid {
|
|
421
480
|
display: grid;
|
|
422
|
-
grid-template-columns: repeat(
|
|
481
|
+
grid-template-columns: repeat(2, 1fr);
|
|
423
482
|
gap: 0;
|
|
424
483
|
}
|
|
425
484
|
.account-card {
|
|
426
|
-
padding:
|
|
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:
|
|
490
|
+
min-height: 120px;
|
|
432
491
|
display: flex;
|
|
433
492
|
flex-direction: column;
|
|
434
493
|
}
|
|
435
|
-
.account-card:nth-child(
|
|
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(
|
|
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(
|
|
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:
|
|
515
|
+
margin-bottom: 12px;
|
|
455
516
|
flex-wrap: wrap;
|
|
456
517
|
}
|
|
457
518
|
.name {
|
|
458
|
-
font-size:
|
|
459
|
-
font-weight:
|
|
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:
|
|
529
|
+
font-size: 21px;
|
|
469
530
|
color: #5a6c7d;
|
|
470
531
|
font-family: 'Courier New', monospace;
|
|
471
532
|
background: #f8f9fa;
|
|
472
|
-
padding:
|
|
473
|
-
border-radius:
|
|
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:
|
|
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:
|
|
556
|
+
margin-top: 12px;
|
|
496
557
|
flex-grow: 1;
|
|
497
558
|
}
|
|
498
559
|
.alias-container {
|
|
499
560
|
flex: 1;
|
|
500
|
-
max-width: calc(100% -
|
|
561
|
+
max-width: calc(100% - 105px);
|
|
501
562
|
align-self: flex-start;
|
|
502
563
|
}
|
|
503
564
|
.alias {
|
|
504
|
-
font-size:
|
|
565
|
+
font-size: 20px;
|
|
505
566
|
color: #6c757d;
|
|
506
567
|
display: flex;
|
|
507
568
|
flex-wrap: wrap;
|
|
508
|
-
gap:
|
|
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:
|
|
515
|
-
border-radius:
|
|
575
|
+
padding: 3px 9px;
|
|
576
|
+
border-radius: 15px;
|
|
516
577
|
border: 1px solid #a5d8ff;
|
|
517
578
|
white-space: nowrap;
|
|
518
|
-
margin-bottom:
|
|
579
|
+
margin-bottom: 3px;
|
|
519
580
|
}
|
|
520
581
|
.no-alias {
|
|
521
|
-
font-size:
|
|
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:
|
|
589
|
+
margin-left: 12px;
|
|
529
590
|
}
|
|
530
591
|
.status {
|
|
531
592
|
display: inline-flex;
|
|
532
593
|
align-items: center;
|
|
533
|
-
gap:
|
|
534
|
-
padding:
|
|
535
|
-
border-radius:
|
|
536
|
-
font-size:
|
|
537
|
-
font-weight:
|
|
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:
|
|
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
|
|
628
|
-
|
|
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>;
|