koishi-plugin-subscription 0.0.1 → 0.0.2
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 +68 -0
- package/lib/index.js +395 -0
- package/package.json +9 -4
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Context, Dict, Schema, Service, Fragment } from 'koishi';
|
|
2
|
+
interface SubscriptionItem {
|
|
3
|
+
id: number;
|
|
4
|
+
app: string;
|
|
5
|
+
account: string;
|
|
6
|
+
groupId: string;
|
|
7
|
+
createdAt: Date;
|
|
8
|
+
}
|
|
9
|
+
interface AppConfig {
|
|
10
|
+
alias: string[];
|
|
11
|
+
allowedAccounts: {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
alias: string;
|
|
15
|
+
}[];
|
|
16
|
+
}
|
|
17
|
+
export interface Config {
|
|
18
|
+
apps: Dict<AppConfig>;
|
|
19
|
+
minAuthority: number;
|
|
20
|
+
mode: "noAdmin" | "and" | "or";
|
|
21
|
+
}
|
|
22
|
+
export declare const Config: Schema<Config>;
|
|
23
|
+
export declare const name = "subscription";
|
|
24
|
+
export declare const inject: {
|
|
25
|
+
required: string[];
|
|
26
|
+
optional: string[];
|
|
27
|
+
};
|
|
28
|
+
declare module 'koishi' {
|
|
29
|
+
interface Context {
|
|
30
|
+
subscription: SubscriptionService;
|
|
31
|
+
}
|
|
32
|
+
interface Tables {
|
|
33
|
+
subscription_service: SubscriptionItem;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
declare class SubscriptionService extends Service {
|
|
37
|
+
readonly tableName = "subscription_service";
|
|
38
|
+
subsConfig: Config;
|
|
39
|
+
appMap: Map<string, string>;
|
|
40
|
+
accountMap: Map<string, string>;
|
|
41
|
+
constructor(ctx: Context, config: Config);
|
|
42
|
+
initMap(): void;
|
|
43
|
+
private getApp;
|
|
44
|
+
private getAccount;
|
|
45
|
+
getAvailableAccounts(app: string): string[];
|
|
46
|
+
getSubscribedGroups(app: string, account: string): Promise<string[]>;
|
|
47
|
+
broadcast(app: string, account: string, content: Fragment): Promise<void>;
|
|
48
|
+
private getSelfIds;
|
|
49
|
+
private getAssignedChannels;
|
|
50
|
+
broadcastForward(app: string, account: string, content: Fragment): Promise<any[]>;
|
|
51
|
+
addSubscription(app: string, account: string, groupId: string): Promise<{
|
|
52
|
+
status: boolean;
|
|
53
|
+
msg: string;
|
|
54
|
+
}>;
|
|
55
|
+
removeSubscription(app: string, account: string, groupId: string): Promise<boolean>;
|
|
56
|
+
getGroupSubscriptions(groupId: string): Promise<SubscriptionItem[]>;
|
|
57
|
+
getAllSubscriptions(): Promise<SubscriptionItem[]>;
|
|
58
|
+
getSubscriptionStats(): Promise<{
|
|
59
|
+
app: string;
|
|
60
|
+
account: string;
|
|
61
|
+
count: number;
|
|
62
|
+
}[]>;
|
|
63
|
+
private authCheck;
|
|
64
|
+
private getChannelId;
|
|
65
|
+
private registerCommands;
|
|
66
|
+
}
|
|
67
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
68
|
+
export {};
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name2 in all)
|
|
8
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.tsx
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
Config: () => Config,
|
|
24
|
+
apply: () => apply,
|
|
25
|
+
inject: () => inject,
|
|
26
|
+
name: () => name
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(src_exports);
|
|
29
|
+
var import_koishi = require("koishi");
|
|
30
|
+
var import_jsx_runtime = require("@satorijs/element/jsx-runtime");
|
|
31
|
+
var Config = import_koishi.Schema.intersect([
|
|
32
|
+
import_koishi.Schema.object({
|
|
33
|
+
apps: import_koishi.Schema.dict(
|
|
34
|
+
import_koishi.Schema.object({
|
|
35
|
+
alias: import_koishi.Schema.array(import_koishi.Schema.string()).role("table").description("应用别名,如果重复,后面会覆盖前面的"),
|
|
36
|
+
allowedAccounts: import_koishi.Schema.array(
|
|
37
|
+
import_koishi.Schema.object({
|
|
38
|
+
id: import_koishi.Schema.string().required().description("账号id"),
|
|
39
|
+
name: import_koishi.Schema.string().required().description("账号名称,用于订阅列表显示"),
|
|
40
|
+
alias: import_koishi.Schema.string().description("账号别名,使用英文逗号分隔")
|
|
41
|
+
})
|
|
42
|
+
).role("table").description("允许订阅的账号列表,别名如果重复,后面会覆盖前面的").required()
|
|
43
|
+
})
|
|
44
|
+
).description("应用配置列表").required()
|
|
45
|
+
}).description("订阅配置"),
|
|
46
|
+
import_koishi.Schema.object({
|
|
47
|
+
minAuthority: import_koishi.Schema.number().default(3).description("需要的最低用户权限"),
|
|
48
|
+
mode: import_koishi.Schema.union([
|
|
49
|
+
import_koishi.Schema.const("noAdmin").description("不考虑群组管理员权限"),
|
|
50
|
+
import_koishi.Schema.const("and").description("同时需要群组管理员权限和用户权限"),
|
|
51
|
+
import_koishi.Schema.const("or").description("群组管理员权限和用户权限只需满足一个")
|
|
52
|
+
]).default("or").role("radio").description("权限模式")
|
|
53
|
+
}).description("权限配置")
|
|
54
|
+
]);
|
|
55
|
+
var name = "subscription";
|
|
56
|
+
var inject = {
|
|
57
|
+
required: ["database"],
|
|
58
|
+
optional: ["puppeteer"]
|
|
59
|
+
};
|
|
60
|
+
var SubscriptionService = class extends import_koishi.Service {
|
|
61
|
+
static {
|
|
62
|
+
__name(this, "SubscriptionService");
|
|
63
|
+
}
|
|
64
|
+
// 数据表名称
|
|
65
|
+
tableName = "subscription_service";
|
|
66
|
+
subsConfig;
|
|
67
|
+
appMap;
|
|
68
|
+
accountMap;
|
|
69
|
+
constructor(ctx, config) {
|
|
70
|
+
super(ctx, "subscription");
|
|
71
|
+
this.subsConfig = config;
|
|
72
|
+
this.initMap();
|
|
73
|
+
ctx.model.extend(this.tableName, {
|
|
74
|
+
id: "unsigned",
|
|
75
|
+
app: "string",
|
|
76
|
+
account: "string",
|
|
77
|
+
groupId: "string",
|
|
78
|
+
createdAt: "timestamp"
|
|
79
|
+
}, {
|
|
80
|
+
primary: "id",
|
|
81
|
+
autoInc: true
|
|
82
|
+
});
|
|
83
|
+
this.registerCommands(ctx, config);
|
|
84
|
+
}
|
|
85
|
+
initMap() {
|
|
86
|
+
this.appMap = /* @__PURE__ */ new Map();
|
|
87
|
+
this.accountMap = /* @__PURE__ */ new Map();
|
|
88
|
+
for (const app in this.subsConfig.apps) {
|
|
89
|
+
if (this.subsConfig.apps[app].alias?.length > 0)
|
|
90
|
+
for (const appAlias of this.subsConfig.apps[app].alias) {
|
|
91
|
+
this.appMap.set(appAlias.toLowerCase(), app);
|
|
92
|
+
}
|
|
93
|
+
for (const item of this.subsConfig.apps[app].allowedAccounts) {
|
|
94
|
+
if (item.alias?.length > 0)
|
|
95
|
+
for (const accountAlias of item.alias.split(","))
|
|
96
|
+
this.accountMap.set((app + accountAlias).toLowerCase(), item.id);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (const app in this.subsConfig.apps) {
|
|
100
|
+
this.appMap.set(app.toLowerCase(), app);
|
|
101
|
+
for (const item of this.subsConfig.apps[app].allowedAccounts) {
|
|
102
|
+
this.accountMap.set((app + item.id).toLowerCase(), item.id);
|
|
103
|
+
}
|
|
104
|
+
for (const item of this.subsConfig.apps[app].allowedAccounts) {
|
|
105
|
+
this.accountMap.set((app + item.name).toLowerCase(), item.id);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
getApp(app) {
|
|
110
|
+
return this.appMap.get(app.toLowerCase());
|
|
111
|
+
}
|
|
112
|
+
getAccount(app, account) {
|
|
113
|
+
return this.accountMap.get((app + account).toLowerCase());
|
|
114
|
+
}
|
|
115
|
+
// 获取对应应用可以订阅的账号
|
|
116
|
+
getAvailableAccounts(app) {
|
|
117
|
+
app = this.getApp(app);
|
|
118
|
+
const appConfig = this.subsConfig.apps[app];
|
|
119
|
+
return appConfig ? appConfig.allowedAccounts.map((item) => item.id) : [];
|
|
120
|
+
}
|
|
121
|
+
// 根据应用和账号获取订阅了这个账号的所有群组
|
|
122
|
+
async getSubscribedGroups(app, account) {
|
|
123
|
+
app = this.getApp(app), account = this.getAccount(app, account);
|
|
124
|
+
const subscriptions = await this.ctx.database.get(this.tableName, {
|
|
125
|
+
app,
|
|
126
|
+
account
|
|
127
|
+
});
|
|
128
|
+
return subscriptions.map((sub) => sub.groupId);
|
|
129
|
+
}
|
|
130
|
+
async broadcast(app, account, content) {
|
|
131
|
+
app = this.getApp(app), account = this.getAccount(app, account);
|
|
132
|
+
const channelArr = await this.getSubscribedGroups(app, account);
|
|
133
|
+
this.ctx.broadcast(channelArr, content);
|
|
134
|
+
}
|
|
135
|
+
getSelfIds(platforms) {
|
|
136
|
+
const selfIdMap = /* @__PURE__ */ Object.create(null);
|
|
137
|
+
for (const bot of this.ctx.bots) {
|
|
138
|
+
if (platforms && !platforms.includes(bot.platform)) continue;
|
|
139
|
+
(selfIdMap[bot.platform] ||= []).push(bot.selfId);
|
|
140
|
+
}
|
|
141
|
+
return selfIdMap;
|
|
142
|
+
}
|
|
143
|
+
async getAssignedChannels(fields, selfIdMap) {
|
|
144
|
+
return this.ctx.database.get("channel", {
|
|
145
|
+
$or: Object.entries(selfIdMap).map(([platform, assignee]) => ({ platform, assignee }))
|
|
146
|
+
}, fields);
|
|
147
|
+
}
|
|
148
|
+
async broadcastForward(app, account, content) {
|
|
149
|
+
app = this.getApp(app), account = this.getAccount(app, account);
|
|
150
|
+
const channels = await this.getSubscribedGroups(app, account);
|
|
151
|
+
const platforms = channels.map((c) => c.split(":")[0]);
|
|
152
|
+
const selfIdMap = this.getSelfIds(platforms);
|
|
153
|
+
const data = await this.getAssignedChannels(["id", "assignee", "flag", "platform", "guildId", "locales"], selfIdMap);
|
|
154
|
+
const assignMap = {};
|
|
155
|
+
for (const channel of data) {
|
|
156
|
+
const { platform, id, assignee, flag } = channel;
|
|
157
|
+
if (channels) {
|
|
158
|
+
const index = channels?.indexOf(`${platform}:${id}`);
|
|
159
|
+
if (index < 0) continue;
|
|
160
|
+
channels.splice(index, 1);
|
|
161
|
+
}
|
|
162
|
+
((assignMap[platform] ||= {})[assignee] ||= []).push(channel);
|
|
163
|
+
}
|
|
164
|
+
if (channels?.length) {
|
|
165
|
+
this.ctx.logger("app").warn("broadcastForward", "channel not found: ", channels.join(", "));
|
|
166
|
+
}
|
|
167
|
+
return (await Promise.all(this.ctx.bots.map(async (bot) => {
|
|
168
|
+
const targets = assignMap[bot.platform]?.[bot.selfId];
|
|
169
|
+
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({
|
|
174
|
+
type: "message",
|
|
175
|
+
channel: { id, type: import_koishi.Universal.Channel.Type.TEXT },
|
|
176
|
+
guild: { id: guildId }
|
|
177
|
+
});
|
|
178
|
+
session.locales = locales;
|
|
179
|
+
return session;
|
|
180
|
+
});
|
|
181
|
+
return bot.broadcast(sessions, forwardContent);
|
|
182
|
+
}))).flat(1);
|
|
183
|
+
}
|
|
184
|
+
// 添加订阅
|
|
185
|
+
async addSubscription(app, account, groupId) {
|
|
186
|
+
app = this.getApp(app), account = this.getAccount(app, account);
|
|
187
|
+
const appConfig = this.getAvailableAccounts(app);
|
|
188
|
+
if (!appConfig) {
|
|
189
|
+
return { status: false, msg: "应用不存在" };
|
|
190
|
+
}
|
|
191
|
+
if (!appConfig.includes(account)) {
|
|
192
|
+
return { status: false, msg: "账号不在白名单中" };
|
|
193
|
+
}
|
|
194
|
+
const existing = await this.ctx.database.get(this.tableName, {
|
|
195
|
+
app,
|
|
196
|
+
account,
|
|
197
|
+
groupId
|
|
198
|
+
});
|
|
199
|
+
if (existing.length > 0) {
|
|
200
|
+
return { status: false, msg: "已订阅该账号" };
|
|
201
|
+
}
|
|
202
|
+
await this.ctx.database.create(this.tableName, {
|
|
203
|
+
app,
|
|
204
|
+
account,
|
|
205
|
+
groupId,
|
|
206
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
207
|
+
});
|
|
208
|
+
return { status: true, msg: "订阅成功" };
|
|
209
|
+
}
|
|
210
|
+
// 删除订阅
|
|
211
|
+
async removeSubscription(app, account, groupId) {
|
|
212
|
+
app = this.appMap.get(app), account = this.accountMap.get(app + account);
|
|
213
|
+
const result = await this.ctx.database.remove(this.tableName, {
|
|
214
|
+
app,
|
|
215
|
+
account,
|
|
216
|
+
groupId
|
|
217
|
+
});
|
|
218
|
+
return result.removed > 0;
|
|
219
|
+
}
|
|
220
|
+
// 获取群组的所有订阅
|
|
221
|
+
async getGroupSubscriptions(groupId) {
|
|
222
|
+
return await this.ctx.database.get(this.tableName, { groupId });
|
|
223
|
+
}
|
|
224
|
+
// 获取所有订阅(用于管理)
|
|
225
|
+
async getAllSubscriptions() {
|
|
226
|
+
return await this.ctx.database.get(this.tableName, {});
|
|
227
|
+
}
|
|
228
|
+
// 按应用获取订阅统计
|
|
229
|
+
async getSubscriptionStats() {
|
|
230
|
+
const subscriptions = await this.getAllSubscriptions();
|
|
231
|
+
const stats = {};
|
|
232
|
+
subscriptions.forEach((sub) => {
|
|
233
|
+
const key = `${sub.app}-${sub.account}`;
|
|
234
|
+
stats[key] = (stats[key] || 0) + 1;
|
|
235
|
+
});
|
|
236
|
+
return Object.entries(stats).map(([key, count]) => {
|
|
237
|
+
const [app, account] = key.split("-");
|
|
238
|
+
return { app, account, count };
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
async authCheck(session, config) {
|
|
242
|
+
const userAuthority = session.user?.authority || 0;
|
|
243
|
+
if (config.mode == "noAdmin") {
|
|
244
|
+
return userAuthority >= config.minAuthority;
|
|
245
|
+
}
|
|
246
|
+
if (config.mode == "or" && userAuthority >= config.minAuthority)
|
|
247
|
+
return true;
|
|
248
|
+
if (config.mode == "and" && userAuthority < config.minAuthority)
|
|
249
|
+
return false;
|
|
250
|
+
let isGroupAdmin = false;
|
|
251
|
+
const memberInfo = await session.bot.getGuildMember?.(session.guildId, session.userId);
|
|
252
|
+
isGroupAdmin = memberInfo?.roles?.includes("admin") || memberInfo?.roles?.includes("owner");
|
|
253
|
+
return isGroupAdmin;
|
|
254
|
+
}
|
|
255
|
+
getChannelId(channel) {
|
|
256
|
+
if (!channel) return;
|
|
257
|
+
return `${channel.platform}:${channel.id}`;
|
|
258
|
+
}
|
|
259
|
+
registerCommands(ctx, config) {
|
|
260
|
+
const sub = ctx.command("subscription.add <app:string> [...accounts]", "添加订阅").alias("订阅").alias("添加订阅").userFields(["authority"]).action(async ({ session, options }, app, ...accounts) => {
|
|
261
|
+
if (!await this.authCheck(session, config)) {
|
|
262
|
+
return "权限不足";
|
|
263
|
+
}
|
|
264
|
+
if (!app || !accounts || accounts.length == 0) {
|
|
265
|
+
return "请指定应用名和账号,格式:订阅 <应用名> <账号> [...更多账号]";
|
|
266
|
+
}
|
|
267
|
+
const groupId = this.getChannelId(session.channel);
|
|
268
|
+
if (!groupId) {
|
|
269
|
+
return "请在群聊中使用当前指令";
|
|
270
|
+
}
|
|
271
|
+
let result = "";
|
|
272
|
+
for (const account of accounts) {
|
|
273
|
+
const { status, msg } = await this.addSubscription(app, account, groupId);
|
|
274
|
+
if (status) {
|
|
275
|
+
result += `成功为群组 ${groupId} 添加订阅:${app} - ${account}
|
|
276
|
+
`;
|
|
277
|
+
} else {
|
|
278
|
+
result += `添加订阅 ${app} - ${account} 失败,${msg}
|
|
279
|
+
`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return result;
|
|
283
|
+
});
|
|
284
|
+
const unsub = ctx.command("subscription.remove <app:string> <account:string>", "删除订阅").alias("删除订阅").alias("取消订阅").userFields(["authority"]).action(async ({ session, options }, app, account) => {
|
|
285
|
+
if (!await this.authCheck(session, config)) {
|
|
286
|
+
return "权限不足";
|
|
287
|
+
}
|
|
288
|
+
if (!app || !account) {
|
|
289
|
+
return "请指定应用名和账号,格式:取消订阅 <应用名> <账号>";
|
|
290
|
+
}
|
|
291
|
+
const groupId = this.getChannelId(session.channel);
|
|
292
|
+
if (!groupId) {
|
|
293
|
+
return "请在群聊中使用当前指令";
|
|
294
|
+
}
|
|
295
|
+
const success = await this.removeSubscription(app, account, groupId);
|
|
296
|
+
if (success) {
|
|
297
|
+
return `成功为群组 ${groupId} 删除订阅:${app} - ${account}`;
|
|
298
|
+
} else {
|
|
299
|
+
return `删除订阅失败,可能的原因:订阅不存在`;
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
for (const app in config.apps) {
|
|
303
|
+
sub.alias(`${app}订阅`, { args: [app] });
|
|
304
|
+
unsub.alias(`取消${app}订阅`, { args: [app] });
|
|
305
|
+
for (const appAlias of config.apps[app].alias) {
|
|
306
|
+
sub.alias(`${appAlias}订阅`, { args: [app] });
|
|
307
|
+
unsub.alias(`取消${appAlias}订阅`, { args: [app] });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
ctx.command("subscription.list", "查看当前群组的订阅").alias("订阅列表").userFields(["authority"]).action(async ({ session, options }) => {
|
|
311
|
+
if (!await this.authCheck(session, config)) {
|
|
312
|
+
return "权限不足";
|
|
313
|
+
}
|
|
314
|
+
const groupId = this.getChannelId(session.channel);
|
|
315
|
+
if (!groupId) {
|
|
316
|
+
return "请在群聊中使用当前指令";
|
|
317
|
+
}
|
|
318
|
+
const subscriptions = await this.getGroupSubscriptions(groupId);
|
|
319
|
+
const subscribedByApp = {};
|
|
320
|
+
subscriptions.forEach((sub2) => {
|
|
321
|
+
if (!subscribedByApp[sub2.app]) {
|
|
322
|
+
subscribedByApp[sub2.app] = /* @__PURE__ */ new Set();
|
|
323
|
+
}
|
|
324
|
+
subscribedByApp[sub2.app].add(sub2.account);
|
|
325
|
+
});
|
|
326
|
+
const availableAccounts = {};
|
|
327
|
+
const appConfig = this.subsConfig.apps;
|
|
328
|
+
for (const app in appConfig) {
|
|
329
|
+
availableAccounts[app] = appConfig[app].allowedAccounts.map((account) => ({
|
|
330
|
+
id: account.id,
|
|
331
|
+
name: account.name,
|
|
332
|
+
alias: account.alias ? account.alias.split(",") : []
|
|
333
|
+
}));
|
|
334
|
+
}
|
|
335
|
+
let result = `群组 ${groupId} 的订阅状态:
|
|
336
|
+
|
|
337
|
+
`;
|
|
338
|
+
for (const app in availableAccounts) {
|
|
339
|
+
result += `【${app}】
|
|
340
|
+
`;
|
|
341
|
+
const subscribed = subscribedByApp[app] || /* @__PURE__ */ new Set();
|
|
342
|
+
availableAccounts[app].forEach((account) => {
|
|
343
|
+
const isSubscribed = subscribed.has(account.id);
|
|
344
|
+
const status = isSubscribed ? "✅ 已订阅" : "❌ 未订阅";
|
|
345
|
+
const aliases = account.alias.length > 0 ? ` (${account.alias.join(", ")})` : "";
|
|
346
|
+
result += `${status} ${account.name} id:${account.id}
|
|
347
|
+
${aliases}
|
|
348
|
+
`;
|
|
349
|
+
});
|
|
350
|
+
result += "\n";
|
|
351
|
+
}
|
|
352
|
+
return result;
|
|
353
|
+
});
|
|
354
|
+
ctx.command("subscription.clear", "删除群组的所有订阅").alias("清空订阅").userFields(["authority"]).action(async ({ session }) => {
|
|
355
|
+
if (!await this.authCheck(session, config)) {
|
|
356
|
+
return "权限不足";
|
|
357
|
+
}
|
|
358
|
+
const groupId = this.getChannelId(session.channel);
|
|
359
|
+
if (!groupId) {
|
|
360
|
+
return "请在群聊中使用当前指令";
|
|
361
|
+
}
|
|
362
|
+
const subscriptions = await this.getGroupSubscriptions(groupId);
|
|
363
|
+
if (subscriptions.length === 0) {
|
|
364
|
+
return `群组 ${groupId} 暂无订阅`;
|
|
365
|
+
}
|
|
366
|
+
await ctx.database.remove("subscription_service", { groupId });
|
|
367
|
+
return `已删除群组 ${groupId} 的所有订阅(共 ${subscriptions.length} 个)`;
|
|
368
|
+
});
|
|
369
|
+
ctx.command("subscription.stats", "查看订阅统计", {
|
|
370
|
+
permissions: [`authority:${config.minAuthority}`],
|
|
371
|
+
hidden: true
|
|
372
|
+
}).alias("订阅统计").userFields(["authority"]).action(async ({ session }) => {
|
|
373
|
+
const stats = await this.getSubscriptionStats();
|
|
374
|
+
if (stats.length === 0) {
|
|
375
|
+
return "暂无订阅数据";
|
|
376
|
+
}
|
|
377
|
+
const statsList = stats.map(
|
|
378
|
+
(stat) => `${stat.app} - ${stat.account}: ${stat.count} 个群组订阅`
|
|
379
|
+
).join("\n");
|
|
380
|
+
return `订阅统计:
|
|
381
|
+
${statsList}`;
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
function apply(ctx, config) {
|
|
386
|
+
ctx.plugin(SubscriptionService, config);
|
|
387
|
+
}
|
|
388
|
+
__name(apply, "apply");
|
|
389
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
390
|
+
0 && (module.exports = {
|
|
391
|
+
Config,
|
|
392
|
+
apply,
|
|
393
|
+
inject,
|
|
394
|
+
name
|
|
395
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-subscription",
|
|
3
3
|
"description": "给多个应用提供订阅群组管理",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.2",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -16,14 +16,19 @@
|
|
|
16
16
|
],
|
|
17
17
|
"koishi": {
|
|
18
18
|
"service": {
|
|
19
|
-
"required": [
|
|
20
|
-
|
|
19
|
+
"required": [
|
|
20
|
+
"database"
|
|
21
|
+
],
|
|
22
|
+
"optional": [
|
|
23
|
+
"puppeteer"
|
|
24
|
+
],
|
|
21
25
|
"implements": [
|
|
22
26
|
"subscription"
|
|
23
27
|
]
|
|
24
28
|
}
|
|
25
29
|
},
|
|
26
30
|
"peerDependencies": {
|
|
27
|
-
"
|
|
31
|
+
"@satorijs/element": "^3.1.8",
|
|
32
|
+
"koishi": "^4.18.9"
|
|
28
33
|
}
|
|
29
34
|
}
|