karin-plugin-kkk 1.1.4 → 1.1.7-pr51.16aebd4
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/CHANGELOG.md +16 -0
- package/README.md +16 -13
- package/lib/apps/push.js +2 -2
- package/lib/module/db/bilibili.d.ts +121 -0
- package/lib/module/db/bilibili.js +353 -0
- package/lib/module/db/douyin.d.ts +125 -0
- package/lib/module/db/douyin.js +396 -0
- package/lib/module/db/index.d.ts +12 -49
- package/lib/module/db/index.js +186 -123
- package/lib/module/utils/Config.d.ts +115 -115
- package/lib/platform/bilibili/push.d.ts +12 -12
- package/lib/platform/bilibili/push.js +136 -167
- package/lib/platform/douyin/comments.js +1 -1
- package/lib/platform/douyin/push.d.ts +38 -27
- package/lib/platform/douyin/push.js +314 -417
- package/lib/web.config.d.ts +1 -1
- package/lib/web.config.js +33 -51
- package/package.json +2 -3
- package/config/PluginConfigView.yaml +0 -271
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.1.6](https://github.com/ikenxuan/karin-plugin-kkk/compare/v1.1.5...v1.1.6) (2025-03-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* ci ([149f99c](https://github.com/ikenxuan/karin-plugin-kkk/commit/149f99cb89af18da99b18fc13793fcbb5ebc75f3))
|
|
9
|
+
|
|
10
|
+
## [1.1.5](https://github.com/ikenxuan/karin-plugin-kkk/compare/v1.1.4...v1.1.5) (2025-03-24)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* 优化前端配置显示 ([b64efa6](https://github.com/ikenxuan/karin-plugin-kkk/commit/b64efa65a82b191bd59dc8b82871eb5250a0f54a))
|
|
16
|
+
* 移除一些过时内容 ([65d2a0a](https://github.com/ikenxuan/karin-plugin-kkk/commit/65d2a0a0d55ffaf3ecd87acbdfcd4c89ba0a5e1b))
|
|
17
|
+
* 评论解析错误 ([d08c76e](https://github.com/ikenxuan/karin-plugin-kkk/commit/d08c76e363f7701df60c9e12d26fbbe0518a365d))
|
|
18
|
+
|
|
3
19
|
## [1.1.4](https://github.com/ikenxuan/karin-plugin-kkk/compare/v1.1.3...v1.1.4) (2025-03-01)
|
|
4
20
|
|
|
5
21
|
|
package/README.md
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-

|
|
2
|
-
|
|
3
1
|
# karin-plugin-kkk
|
|
4
|
-
|
|
5
2
|
🦄 **_Karin 的「抖音」「B站」「快手」视频解析/动态推送插件_**
|
|
6
3
|
|
|
4
|
+
PS: 快手暂不支持推送
|
|
5
|
+
|
|
7
6
|
## ⬇️ 安装
|
|
8
7
|
|
|
9
|
-
*
|
|
8
|
+
* 使用 **`包管理器`** 安装(非常推荐)
|
|
9
|
+
<details>
|
|
10
|
+
<summary>点击展开</summary>
|
|
11
|
+
|
|
12
|
+
在 **Karin 根目录** 下运行
|
|
13
|
+
```sh
|
|
14
|
+
pnpm add karin-plugin-kkk@latest -w
|
|
15
|
+
```
|
|
16
|
+
</details>
|
|
17
|
+
|
|
18
|
+
<br />
|
|
19
|
+
|
|
20
|
+
* 克隆编译产物 **`build 分支`**(比较推荐)
|
|
10
21
|
<details>
|
|
11
22
|
<summary>点击展开</summary>
|
|
12
23
|
|
|
@@ -34,15 +45,7 @@
|
|
|
34
45
|
|
|
35
46
|
</details>
|
|
36
47
|
|
|
37
|
-
|
|
38
|
-
<details>
|
|
39
|
-
<summary>点击展开</summary>
|
|
40
|
-
|
|
41
|
-
在 **Karin 根目录** 下运行
|
|
42
|
-
```sh
|
|
43
|
-
pnpm add karin-plugin-kkk@latest -w
|
|
44
|
-
```
|
|
45
|
-
</details>
|
|
48
|
+
<br />
|
|
46
49
|
|
|
47
50
|
* 使用 Release **`发行版`**(不推荐)
|
|
48
51
|
<details>
|
package/lib/apps/push.js
CHANGED
|
@@ -36,10 +36,10 @@ export const setbiliPush = karin.command(/^#设置[bB]站推送(?:[Uu][Ii][Dd]:)
|
|
|
36
36
|
return true;
|
|
37
37
|
}, { name: 'kkk-推送功能-设置', event: 'message.group', perm: Config.bilibili.push.permission, dsbAdapter: ['qqbot'] });
|
|
38
38
|
export const bilibiliPushList = karin.command(/^#?[bB]站推送列表$/, async (e) => {
|
|
39
|
-
await new Bilibilipush(e).renderPushList(
|
|
39
|
+
await new Bilibilipush(e).renderPushList();
|
|
40
40
|
}, { name: 'kkk-推送功能-列表', event: 'message.group' });
|
|
41
41
|
export const douyinPushList = karin.command(/^#?抖音推送列表$/, async (e) => {
|
|
42
|
-
await new DouYinpush(e).renderPushList(
|
|
42
|
+
await new DouYinpush(e).renderPushList();
|
|
43
43
|
}, { name: 'kkk-推送功能-列表', event: 'message.group' });
|
|
44
44
|
export const changeBotID = karin.command(/^#kkk设置推送机器人/, async (e) => {
|
|
45
45
|
const newDouyinlist = Config.pushlist.douyin.map(item => {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Model } from 'sequelize';
|
|
2
|
+
import { bilibiliPushItem } from '../../types/config/pushlist.js';
|
|
3
|
+
type GroupUserSubscriptionAttributes = {
|
|
4
|
+
id?: number;
|
|
5
|
+
/** 群号 */
|
|
6
|
+
groupId: string;
|
|
7
|
+
/** UP主UID */
|
|
8
|
+
host_mid: number;
|
|
9
|
+
};
|
|
10
|
+
/** Bots表 - 存储机器人信息 */
|
|
11
|
+
declare const Bot: import("sequelize").ModelCtor<Model<any, any>>;
|
|
12
|
+
/** Groups表 - 存储群组信息 */
|
|
13
|
+
declare const Group: import("sequelize").ModelCtor<Model<any, any>>;
|
|
14
|
+
/** BilibiliUsers表 - 存储B站用户信息 */
|
|
15
|
+
declare const BilibiliUser: import("sequelize").ModelCtor<Model<any, any>>;
|
|
16
|
+
/** GroupUserSubscriptions表 - 存储群组订阅的B站用户关系 */
|
|
17
|
+
declare const GroupUserSubscription: import("sequelize").ModelCtor<Model<GroupUserSubscriptionAttributes, GroupUserSubscriptionAttributes>>;
|
|
18
|
+
/** DynamicCache表 - 存储已推送的动态ID */
|
|
19
|
+
declare const DynamicCache: import("sequelize").ModelCtor<Model<any, any>>;
|
|
20
|
+
/** 数据库操作类 */
|
|
21
|
+
export declare class BilibiliDBBase {
|
|
22
|
+
/**
|
|
23
|
+
* 获取或创建机器人记录
|
|
24
|
+
* @param botId 机器人ID
|
|
25
|
+
*/
|
|
26
|
+
getOrCreateBot(botId: string): Promise<Model<any, any>>;
|
|
27
|
+
/**
|
|
28
|
+
* 获取或创建群组记录
|
|
29
|
+
* @param groupId 群组ID
|
|
30
|
+
* @param botId 机器人ID
|
|
31
|
+
*/
|
|
32
|
+
getOrCreateGroup(groupId: string, botId: string): Promise<Model<any, any>>;
|
|
33
|
+
/**
|
|
34
|
+
* 获取或创建B站用户记录
|
|
35
|
+
* @param host_mid B站用户UID
|
|
36
|
+
* @param remark UP主昵称
|
|
37
|
+
* @param avatar_img 头像URL
|
|
38
|
+
*/
|
|
39
|
+
getOrCreateBilibiliUser(host_mid: number, remark?: string): Promise<Model<any, any>>;
|
|
40
|
+
/**
|
|
41
|
+
* 订阅B站用户
|
|
42
|
+
* @param groupId 群组ID
|
|
43
|
+
* @param botId 机器人ID
|
|
44
|
+
* @param host_mid B站用户UID
|
|
45
|
+
* @param remark UP主昵称
|
|
46
|
+
*/
|
|
47
|
+
subscribeBilibiliUser(groupId: string, botId: string, host_mid: number, remark?: string): Promise<Model<GroupUserSubscriptionAttributes, GroupUserSubscriptionAttributes>>;
|
|
48
|
+
/**
|
|
49
|
+
* 取消订阅B站用户
|
|
50
|
+
* @param groupId 群组ID
|
|
51
|
+
* @param host_mid B站用户UID
|
|
52
|
+
*/
|
|
53
|
+
unsubscribeBilibiliUser(groupId: string, host_mid: number): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* 添加动态缓存
|
|
56
|
+
* @param dynamic_id 动态ID
|
|
57
|
+
* @param host_mid B站用户UID
|
|
58
|
+
* @param groupId 群组ID
|
|
59
|
+
* @param dynamic_type 动态类型
|
|
60
|
+
*/
|
|
61
|
+
addDynamicCache(dynamic_id: string, host_mid: number, groupId: string, dynamic_type: string): Promise<Model<any, any>>;
|
|
62
|
+
/**
|
|
63
|
+
* 检查动态是否已推送
|
|
64
|
+
* @param dynamic_id 动态ID
|
|
65
|
+
* @param host_mid B站用户UID
|
|
66
|
+
* @param groupId 群组ID
|
|
67
|
+
*/
|
|
68
|
+
isDynamicPushed(dynamic_id: string, host_mid: number, groupId: string): Promise<boolean>;
|
|
69
|
+
/**
|
|
70
|
+
* 获取机器人管理的所有群组
|
|
71
|
+
* @param botId 机器人ID
|
|
72
|
+
*/
|
|
73
|
+
getBotGroups(botId: string): Promise<Model<any, any>[]>;
|
|
74
|
+
/**
|
|
75
|
+
* 获取群组订阅的所有B站用户
|
|
76
|
+
* @param groupId 群组ID
|
|
77
|
+
*/
|
|
78
|
+
getGroupSubscriptions(groupId: string): Promise<Model<GroupUserSubscriptionAttributes>[]>;
|
|
79
|
+
/**
|
|
80
|
+
* 获取B站用户的所有订阅群组
|
|
81
|
+
* @param host_mid B站用户UID
|
|
82
|
+
*/
|
|
83
|
+
getUserSubscribedGroups(host_mid: number): Promise<Model<GroupUserSubscriptionAttributes, GroupUserSubscriptionAttributes>[]>;
|
|
84
|
+
/**
|
|
85
|
+
* 获取群组的动态缓存
|
|
86
|
+
* @param groupId 群组ID
|
|
87
|
+
* @param host_mid 可选的B站用户UID过滤
|
|
88
|
+
*/
|
|
89
|
+
getGroupDynamicCache(groupId: string, host_mid?: number): Promise<Model<any, any>[]>;
|
|
90
|
+
/**
|
|
91
|
+
* 检查群组是否已订阅B站用户
|
|
92
|
+
* @param host_mid B站用户UID
|
|
93
|
+
* @param groupId 群组ID
|
|
94
|
+
*/
|
|
95
|
+
isSubscribed(host_mid: number, groupId: string): Promise<boolean>;
|
|
96
|
+
/**
|
|
97
|
+
* 迁移旧数据到新数据库结构
|
|
98
|
+
* @param oldData 旧的数据结构
|
|
99
|
+
*/
|
|
100
|
+
migrateOldData(oldData: any): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* 批量同步配置文件中的订阅到数据库
|
|
103
|
+
* @param configItems 配置文件中的订阅项
|
|
104
|
+
*/
|
|
105
|
+
syncConfigSubscriptions(configItems: bilibiliPushItem[]): Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
export declare const bilibiliDB: BilibiliDBBase;
|
|
108
|
+
export { BilibiliUser, Bot, DynamicCache, Group, GroupUserSubscription };
|
|
109
|
+
/** B站数据库模型集合 */
|
|
110
|
+
export declare const bilibiliModels: {
|
|
111
|
+
/** BilibiliUsers表 - 存储B站用户信息 */
|
|
112
|
+
BilibiliUser: import("sequelize").ModelCtor<Model<any, any>>;
|
|
113
|
+
/** Bots表 - 存储机器人信息 */
|
|
114
|
+
Bot: import("sequelize").ModelCtor<Model<any, any>>;
|
|
115
|
+
/** DynamicCache表 - 存储已推送的动态ID */
|
|
116
|
+
DynamicCache: import("sequelize").ModelCtor<Model<any, any>>;
|
|
117
|
+
/** Groups表 - 存储群组信息 */
|
|
118
|
+
Group: import("sequelize").ModelCtor<Model<any, any>>;
|
|
119
|
+
/** GroupUserSubscriptions表 - 存储群组订阅的B站用户关系 */
|
|
120
|
+
GroupUserSubscription: import("sequelize").ModelCtor<Model<GroupUserSubscriptionAttributes, GroupUserSubscriptionAttributes>>;
|
|
121
|
+
};
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { basePath } from 'node-karin';
|
|
3
|
+
import { DataTypes, Sequelize } from 'sequelize';
|
|
4
|
+
import { Version } from '../utils/index.js';
|
|
5
|
+
/** 创建 Sequelize 实例,需要传入配置对象。 */
|
|
6
|
+
const sequelize = new Sequelize({
|
|
7
|
+
dialect: 'sqlite',
|
|
8
|
+
storage: join(`${basePath}/${Version.pluginName}/data`, 'bilibili.db'),
|
|
9
|
+
logging: false
|
|
10
|
+
});
|
|
11
|
+
/** 测试数据库连接是否成功 */
|
|
12
|
+
await sequelize.authenticate();
|
|
13
|
+
// 定义模型
|
|
14
|
+
/** Bots表 - 存储机器人信息 */
|
|
15
|
+
const Bot = sequelize.define('Bot', {
|
|
16
|
+
id: {
|
|
17
|
+
type: DataTypes.STRING,
|
|
18
|
+
primaryKey: true,
|
|
19
|
+
comment: '机器人ID'
|
|
20
|
+
}
|
|
21
|
+
}, {
|
|
22
|
+
timestamps: true
|
|
23
|
+
});
|
|
24
|
+
/** Groups表 - 存储群组信息 */
|
|
25
|
+
const Group = sequelize.define('Group', {
|
|
26
|
+
id: {
|
|
27
|
+
type: DataTypes.STRING,
|
|
28
|
+
primaryKey: true,
|
|
29
|
+
comment: '群组ID'
|
|
30
|
+
},
|
|
31
|
+
botId: {
|
|
32
|
+
type: DataTypes.STRING,
|
|
33
|
+
allowNull: false,
|
|
34
|
+
comment: '所属机器人ID',
|
|
35
|
+
references: {
|
|
36
|
+
model: 'Bots',
|
|
37
|
+
key: 'id'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}, {
|
|
41
|
+
timestamps: true
|
|
42
|
+
});
|
|
43
|
+
/** BilibiliUsers表 - 存储B站用户信息 */
|
|
44
|
+
const BilibiliUser = sequelize.define('BilibiliUser', {
|
|
45
|
+
host_mid: {
|
|
46
|
+
type: DataTypes.INTEGER,
|
|
47
|
+
primaryKey: true,
|
|
48
|
+
comment: 'B站用户UID'
|
|
49
|
+
},
|
|
50
|
+
remark: {
|
|
51
|
+
type: DataTypes.STRING,
|
|
52
|
+
comment: 'B站用户昵称'
|
|
53
|
+
},
|
|
54
|
+
avatar_img: {
|
|
55
|
+
type: DataTypes.STRING,
|
|
56
|
+
comment: '头像URL'
|
|
57
|
+
}
|
|
58
|
+
}, {
|
|
59
|
+
timestamps: true
|
|
60
|
+
});
|
|
61
|
+
/** GroupUserSubscriptions表 - 存储群组订阅的B站用户关系 */
|
|
62
|
+
const GroupUserSubscription = sequelize.define('GroupUserSubscription', {
|
|
63
|
+
id: {
|
|
64
|
+
type: DataTypes.INTEGER,
|
|
65
|
+
primaryKey: true,
|
|
66
|
+
autoIncrement: true,
|
|
67
|
+
comment: '订阅ID'
|
|
68
|
+
},
|
|
69
|
+
groupId: {
|
|
70
|
+
type: DataTypes.STRING,
|
|
71
|
+
allowNull: false,
|
|
72
|
+
comment: '群组ID',
|
|
73
|
+
references: {
|
|
74
|
+
model: 'Groups',
|
|
75
|
+
key: 'id'
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
host_mid: {
|
|
79
|
+
type: DataTypes.INTEGER,
|
|
80
|
+
allowNull: false,
|
|
81
|
+
comment: 'B站用户UID',
|
|
82
|
+
references: {
|
|
83
|
+
model: 'BilibiliUsers',
|
|
84
|
+
key: 'host_mid'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}, {
|
|
88
|
+
timestamps: true
|
|
89
|
+
});
|
|
90
|
+
/** DynamicCache表 - 存储已推送的动态ID */
|
|
91
|
+
const DynamicCache = sequelize.define('DynamicCache', {
|
|
92
|
+
id: {
|
|
93
|
+
type: DataTypes.INTEGER,
|
|
94
|
+
primaryKey: true,
|
|
95
|
+
autoIncrement: true,
|
|
96
|
+
comment: '缓存ID'
|
|
97
|
+
},
|
|
98
|
+
dynamic_id: {
|
|
99
|
+
type: DataTypes.STRING,
|
|
100
|
+
allowNull: false,
|
|
101
|
+
comment: '动态ID'
|
|
102
|
+
},
|
|
103
|
+
host_mid: {
|
|
104
|
+
type: DataTypes.INTEGER,
|
|
105
|
+
allowNull: false,
|
|
106
|
+
comment: 'B站用户UID',
|
|
107
|
+
references: {
|
|
108
|
+
model: 'BilibiliUsers',
|
|
109
|
+
key: 'host_mid'
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
groupId: {
|
|
113
|
+
type: DataTypes.STRING,
|
|
114
|
+
allowNull: false,
|
|
115
|
+
comment: '群组ID',
|
|
116
|
+
references: {
|
|
117
|
+
model: 'Groups',
|
|
118
|
+
key: 'id'
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
dynamic_type: {
|
|
122
|
+
type: DataTypes.STRING,
|
|
123
|
+
comment: '动态类型'
|
|
124
|
+
}
|
|
125
|
+
}, {
|
|
126
|
+
timestamps: true
|
|
127
|
+
});
|
|
128
|
+
// 建立关联关系
|
|
129
|
+
Bot.hasMany(Group, { foreignKey: 'botId' });
|
|
130
|
+
Group.belongsTo(Bot, { foreignKey: 'botId' });
|
|
131
|
+
Group.belongsToMany(BilibiliUser, { through: GroupUserSubscription, foreignKey: 'groupId' });
|
|
132
|
+
BilibiliUser.belongsToMany(Group, { through: GroupUserSubscription, foreignKey: 'host_mid' });
|
|
133
|
+
BilibiliUser.hasMany(DynamicCache, { foreignKey: 'host_mid' });
|
|
134
|
+
DynamicCache.belongsTo(BilibiliUser, { foreignKey: 'host_mid' });
|
|
135
|
+
Group.hasMany(DynamicCache, { foreignKey: 'groupId' });
|
|
136
|
+
DynamicCache.belongsTo(Group, { foreignKey: 'groupId' });
|
|
137
|
+
/** 数据库操作类 */
|
|
138
|
+
export class BilibiliDBBase {
|
|
139
|
+
/**
|
|
140
|
+
* 获取或创建机器人记录
|
|
141
|
+
* @param botId 机器人ID
|
|
142
|
+
*/
|
|
143
|
+
async getOrCreateBot(botId) {
|
|
144
|
+
const [bot] = await Bot.findOrCreate({
|
|
145
|
+
where: { id: botId }
|
|
146
|
+
});
|
|
147
|
+
return bot;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* 获取或创建群组记录
|
|
151
|
+
* @param groupId 群组ID
|
|
152
|
+
* @param botId 机器人ID
|
|
153
|
+
*/
|
|
154
|
+
async getOrCreateGroup(groupId, botId) {
|
|
155
|
+
await this.getOrCreateBot(botId);
|
|
156
|
+
const [group] = await Group.findOrCreate({
|
|
157
|
+
where: { id: groupId, botId }
|
|
158
|
+
});
|
|
159
|
+
return group;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 获取或创建B站用户记录
|
|
163
|
+
* @param host_mid B站用户UID
|
|
164
|
+
* @param remark UP主昵称
|
|
165
|
+
* @param avatar_img 头像URL
|
|
166
|
+
*/
|
|
167
|
+
async getOrCreateBilibiliUser(host_mid, remark = '') {
|
|
168
|
+
const [user] = await BilibiliUser.findOrCreate({
|
|
169
|
+
where: { host_mid },
|
|
170
|
+
defaults: { remark }
|
|
171
|
+
});
|
|
172
|
+
return user;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 订阅B站用户
|
|
176
|
+
* @param groupId 群组ID
|
|
177
|
+
* @param botId 机器人ID
|
|
178
|
+
* @param host_mid B站用户UID
|
|
179
|
+
* @param remark UP主昵称
|
|
180
|
+
*/
|
|
181
|
+
async subscribeBilibiliUser(groupId, botId, host_mid, remark = '') {
|
|
182
|
+
await this.getOrCreateGroup(groupId, botId);
|
|
183
|
+
await this.getOrCreateBilibiliUser(host_mid, remark);
|
|
184
|
+
const [subscription] = await GroupUserSubscription.findOrCreate({
|
|
185
|
+
where: { groupId, host_mid }
|
|
186
|
+
});
|
|
187
|
+
return subscription;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* 取消订阅B站用户
|
|
191
|
+
* @param groupId 群组ID
|
|
192
|
+
* @param host_mid B站用户UID
|
|
193
|
+
*/
|
|
194
|
+
async unsubscribeBilibiliUser(groupId, host_mid) {
|
|
195
|
+
const result = await GroupUserSubscription.destroy({
|
|
196
|
+
where: { groupId, host_mid }
|
|
197
|
+
});
|
|
198
|
+
// 清除相关的动态缓存
|
|
199
|
+
await DynamicCache.destroy({
|
|
200
|
+
where: { groupId, host_mid }
|
|
201
|
+
});
|
|
202
|
+
return result > 0;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 添加动态缓存
|
|
206
|
+
* @param dynamic_id 动态ID
|
|
207
|
+
* @param host_mid B站用户UID
|
|
208
|
+
* @param groupId 群组ID
|
|
209
|
+
* @param dynamic_type 动态类型
|
|
210
|
+
*/
|
|
211
|
+
async addDynamicCache(dynamic_id, host_mid, groupId, dynamic_type) {
|
|
212
|
+
const [cache] = await DynamicCache.findOrCreate({
|
|
213
|
+
where: { dynamic_id, host_mid, groupId },
|
|
214
|
+
defaults: { dynamic_type }
|
|
215
|
+
});
|
|
216
|
+
return cache;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 检查动态是否已推送
|
|
220
|
+
* @param dynamic_id 动态ID
|
|
221
|
+
* @param host_mid B站用户UID
|
|
222
|
+
* @param groupId 群组ID
|
|
223
|
+
*/
|
|
224
|
+
async isDynamicPushed(dynamic_id, host_mid, groupId) {
|
|
225
|
+
const count = await DynamicCache.count({
|
|
226
|
+
where: { dynamic_id, host_mid, groupId }
|
|
227
|
+
});
|
|
228
|
+
return count > 0;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* 获取机器人管理的所有群组
|
|
232
|
+
* @param botId 机器人ID
|
|
233
|
+
*/
|
|
234
|
+
async getBotGroups(botId) {
|
|
235
|
+
return await Group.findAll({
|
|
236
|
+
where: { botId }
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* 获取群组订阅的所有B站用户
|
|
241
|
+
* @param groupId 群组ID
|
|
242
|
+
*/
|
|
243
|
+
async getGroupSubscriptions(groupId) {
|
|
244
|
+
return await GroupUserSubscription.findAll({
|
|
245
|
+
where: { groupId }
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 获取B站用户的所有订阅群组
|
|
250
|
+
* @param host_mid B站用户UID
|
|
251
|
+
*/
|
|
252
|
+
async getUserSubscribedGroups(host_mid) {
|
|
253
|
+
return await GroupUserSubscription.findAll({
|
|
254
|
+
where: { host_mid },
|
|
255
|
+
include: [Group]
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* 获取群组的动态缓存
|
|
260
|
+
* @param groupId 群组ID
|
|
261
|
+
* @param host_mid 可选的B站用户UID过滤
|
|
262
|
+
*/
|
|
263
|
+
async getGroupDynamicCache(groupId, host_mid) {
|
|
264
|
+
const where = { groupId };
|
|
265
|
+
if (host_mid)
|
|
266
|
+
where.host_mid = host_mid;
|
|
267
|
+
return await DynamicCache.findAll({
|
|
268
|
+
where,
|
|
269
|
+
order: [['createdAt', 'DESC']]
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* 检查群组是否已订阅B站用户
|
|
274
|
+
* @param host_mid B站用户UID
|
|
275
|
+
* @param groupId 群组ID
|
|
276
|
+
*/
|
|
277
|
+
async isSubscribed(host_mid, groupId) {
|
|
278
|
+
const count = await GroupUserSubscription.count({
|
|
279
|
+
where: { host_mid, groupId }
|
|
280
|
+
});
|
|
281
|
+
return count > 0;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* 迁移旧数据到新数据库结构
|
|
285
|
+
* @param oldData 旧的数据结构
|
|
286
|
+
*/
|
|
287
|
+
async migrateOldData(oldData) {
|
|
288
|
+
if (!oldData || !oldData.bilibili)
|
|
289
|
+
return;
|
|
290
|
+
for (const groupIdWithBotId in oldData.bilibili) {
|
|
291
|
+
const [groupId, botId] = groupIdWithBotId.split(':');
|
|
292
|
+
if (!groupId || !botId)
|
|
293
|
+
continue;
|
|
294
|
+
const groupData = oldData.bilibili[groupIdWithBotId];
|
|
295
|
+
for (const hostMidKey in groupData) {
|
|
296
|
+
const userData = groupData[hostMidKey];
|
|
297
|
+
const host_mid = userData.host_mid;
|
|
298
|
+
const remark = userData.remark;
|
|
299
|
+
const dynamic_idlist = userData.dynamic_idlist || [];
|
|
300
|
+
const dynamic_type = userData.dynamic_type;
|
|
301
|
+
// 创建订阅关系
|
|
302
|
+
await this.subscribeBilibiliUser(groupId, botId, host_mid, remark);
|
|
303
|
+
// 添加动态缓存
|
|
304
|
+
for (const dynamic_id of dynamic_idlist) {
|
|
305
|
+
await this.addDynamicCache(dynamic_id, host_mid, groupId, dynamic_type);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* 批量同步配置文件中的订阅到数据库
|
|
312
|
+
* @param configItems 配置文件中的订阅项
|
|
313
|
+
*/
|
|
314
|
+
async syncConfigSubscriptions(configItems) {
|
|
315
|
+
if (!configItems || configItems.length === 0)
|
|
316
|
+
return;
|
|
317
|
+
for (const item of configItems) {
|
|
318
|
+
const host_mid = item.host_mid;
|
|
319
|
+
const remark = item.remark || '';
|
|
320
|
+
// 创建或更新B站用户记录
|
|
321
|
+
await this.getOrCreateBilibiliUser(host_mid, remark);
|
|
322
|
+
// 处理该UP主的所有群组订阅
|
|
323
|
+
for (const groupWithBot of item.group_id) {
|
|
324
|
+
const [groupId, botId] = groupWithBot.split(':');
|
|
325
|
+
if (!groupId || !botId)
|
|
326
|
+
continue;
|
|
327
|
+
// 检查是否已订阅
|
|
328
|
+
const isSubscribed = await this.isSubscribed(host_mid, groupId);
|
|
329
|
+
// 如果未订阅,创建订阅关系
|
|
330
|
+
if (!isSubscribed) {
|
|
331
|
+
await this.subscribeBilibiliUser(groupId, botId, host_mid, remark);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
export const bilibiliDB = new BilibiliDBBase();
|
|
338
|
+
// 同步数据库结构
|
|
339
|
+
await sequelize.sync({ alter: true, force: false });
|
|
340
|
+
export { BilibiliUser, Bot, DynamicCache, Group, GroupUserSubscription };
|
|
341
|
+
/** B站数据库模型集合 */
|
|
342
|
+
export const bilibiliModels = {
|
|
343
|
+
/** BilibiliUsers表 - 存储B站用户信息 */
|
|
344
|
+
BilibiliUser,
|
|
345
|
+
/** Bots表 - 存储机器人信息 */
|
|
346
|
+
Bot,
|
|
347
|
+
/** DynamicCache表 - 存储已推送的动态ID */
|
|
348
|
+
DynamicCache,
|
|
349
|
+
/** Groups表 - 存储群组信息 */
|
|
350
|
+
Group,
|
|
351
|
+
/** GroupUserSubscriptions表 - 存储群组订阅的B站用户关系 */
|
|
352
|
+
GroupUserSubscription
|
|
353
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Model } from 'sequelize';
|
|
2
|
+
import { douyinPushItem } from '../../types/config/pushlist.js';
|
|
3
|
+
type GroupUserSubscriptionAttributes = {
|
|
4
|
+
id?: number;
|
|
5
|
+
/** 群号 */
|
|
6
|
+
groupId: string;
|
|
7
|
+
/** 抖音用户sec_uid */
|
|
8
|
+
sec_uid: string;
|
|
9
|
+
};
|
|
10
|
+
/** 数据库操作类 */
|
|
11
|
+
export declare class DouyinDBBase {
|
|
12
|
+
/**
|
|
13
|
+
* 获取或创建机器人记录
|
|
14
|
+
* @param botId 机器人ID
|
|
15
|
+
*/
|
|
16
|
+
getOrCreateBot(botId: string): Promise<Model<any, any>>;
|
|
17
|
+
/**
|
|
18
|
+
* 获取或创建群组记录
|
|
19
|
+
* @param groupId 群组ID
|
|
20
|
+
* @param botId 机器人ID
|
|
21
|
+
*/
|
|
22
|
+
getOrCreateGroup(groupId: string, botId: string): Promise<Model<any, any>>;
|
|
23
|
+
/**
|
|
24
|
+
* 获取或创建抖音用户记录
|
|
25
|
+
* @param sec_uid 抖音用户sec_uid
|
|
26
|
+
* @param short_id 抖音号
|
|
27
|
+
* @param remark 用户昵称
|
|
28
|
+
*/
|
|
29
|
+
getOrCreateDouyinUser(sec_uid: string, short_id?: string, remark?: string): Promise<Model<any, any>>;
|
|
30
|
+
/**
|
|
31
|
+
* 订阅抖音用户
|
|
32
|
+
* @param groupId 群组ID
|
|
33
|
+
* @param botId 机器人ID
|
|
34
|
+
* @param sec_uid 抖音用户sec_uid
|
|
35
|
+
* @param short_id 抖音号
|
|
36
|
+
* @param remark 用户昵称
|
|
37
|
+
*/
|
|
38
|
+
subscribeDouyinUser(groupId: string, botId: string, sec_uid: string, short_id?: string, remark?: string): Promise<Model<GroupUserSubscriptionAttributes, GroupUserSubscriptionAttributes>>;
|
|
39
|
+
/**
|
|
40
|
+
* 取消订阅抖音用户
|
|
41
|
+
* @param groupId 群组ID
|
|
42
|
+
* @param sec_uid 抖音用户sec_uid
|
|
43
|
+
*/
|
|
44
|
+
unsubscribeDouyinUser(groupId: string, sec_uid: string): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* 添加作品缓存
|
|
47
|
+
* @param aweme_id 作品ID
|
|
48
|
+
* @param sec_uid 抖音用户sec_uid
|
|
49
|
+
* @param groupId 群组ID
|
|
50
|
+
*/
|
|
51
|
+
addAwemeCache(aweme_id: string, sec_uid: string, groupId: string): Promise<Model<any, any>>;
|
|
52
|
+
/**
|
|
53
|
+
* 检查作品是否已推送
|
|
54
|
+
* @param aweme_id 作品ID
|
|
55
|
+
* @param sec_uid 抖音用户sec_uid
|
|
56
|
+
* @param groupId 群组ID
|
|
57
|
+
*/
|
|
58
|
+
isAwemePushed(aweme_id: string, sec_uid: string, groupId: string): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* 获取机器人管理的所有群组
|
|
61
|
+
* @param botId 机器人ID
|
|
62
|
+
*/
|
|
63
|
+
getBotGroups(botId: string): Promise<Model<any, any>[]>;
|
|
64
|
+
/**
|
|
65
|
+
* 获取群组订阅的所有抖音用户
|
|
66
|
+
* @param groupId 群组ID
|
|
67
|
+
*/
|
|
68
|
+
getGroupSubscriptions(groupId: string): Promise<Model<GroupUserSubscriptionAttributes, GroupUserSubscriptionAttributes>[]>;
|
|
69
|
+
/**
|
|
70
|
+
* 获取抖音用户的所有订阅群组
|
|
71
|
+
* @param sec_uid 抖音用户sec_uid
|
|
72
|
+
*/
|
|
73
|
+
getUserSubscribedGroups(sec_uid: string): Promise<Model<GroupUserSubscriptionAttributes, GroupUserSubscriptionAttributes>[]>;
|
|
74
|
+
/**
|
|
75
|
+
* 检查群组是否已订阅抖音用户
|
|
76
|
+
* @param sec_uid 抖音用户sec_uid
|
|
77
|
+
* @param groupId 群组ID
|
|
78
|
+
*/
|
|
79
|
+
isSubscribed(sec_uid: string, groupId: string): Promise<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* 更新用户直播状态
|
|
82
|
+
* @param sec_uid 抖音用户sec_uid
|
|
83
|
+
* @param living 是否正在直播
|
|
84
|
+
*/
|
|
85
|
+
updateLiveStatus(sec_uid: string, living: boolean): Promise<boolean>;
|
|
86
|
+
/**
|
|
87
|
+
* 获取用户直播状态
|
|
88
|
+
* @param sec_uid 抖音用户sec_uid
|
|
89
|
+
*/
|
|
90
|
+
getLiveStatus(sec_uid: string): Promise<{
|
|
91
|
+
living: boolean;
|
|
92
|
+
live_msg_id: string;
|
|
93
|
+
live_start_time: number;
|
|
94
|
+
}>;
|
|
95
|
+
/**
|
|
96
|
+
* 批量同步配置文件中的订阅到数据库
|
|
97
|
+
* @param configItems 配置文件中的订阅项
|
|
98
|
+
*/
|
|
99
|
+
syncConfigSubscriptions(configItems: douyinPushItem[]): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* 迁移旧数据到新数据库结构
|
|
102
|
+
* @param oldData 旧的数据结构
|
|
103
|
+
*/
|
|
104
|
+
migrateOldData(oldData: any): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* 通过ID获取群组信息
|
|
107
|
+
* @param groupId 群组ID
|
|
108
|
+
*/
|
|
109
|
+
getGroupById(groupId: string): Promise<Model<any, any> | null>;
|
|
110
|
+
}
|
|
111
|
+
export declare const douyinDB: DouyinDBBase;
|
|
112
|
+
/** 抖音数据库模型集合 */
|
|
113
|
+
export declare const DouyinModels: {
|
|
114
|
+
/** AwemeCache表 - 存储已推送的作品ID */
|
|
115
|
+
AwemeCache: import("sequelize").ModelCtor<Model<any, any>>;
|
|
116
|
+
/** Bots表 - 存储机器人信息 */
|
|
117
|
+
Bot: import("sequelize").ModelCtor<Model<any, any>>;
|
|
118
|
+
/** DouyinUsers表 - 存储抖音用户信息 */
|
|
119
|
+
DouyinUser: import("sequelize").ModelCtor<Model<any, any>>;
|
|
120
|
+
/** Groups表 - 存储群组信息 */
|
|
121
|
+
Group: import("sequelize").ModelCtor<Model<any, any>>;
|
|
122
|
+
/** GroupUserSubscriptions表 - 存储群组订阅的抖音用户关系 */
|
|
123
|
+
GroupUserSubscription: import("sequelize").ModelCtor<Model<GroupUserSubscriptionAttributes, GroupUserSubscriptionAttributes>>;
|
|
124
|
+
};
|
|
125
|
+
export {};
|