koishi-plugin-bilitester 1.0.0 → 1.1.0
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.js +61 -2
- package/lib/services/auth.service.d.ts +43 -0
- package/lib/services/auth.service.js +101 -0
- package/lib/services/bilibili.service.d.ts +98 -0
- package/lib/services/bilibili.service.js +99 -0
- package/lib/services/database.service.d.ts +27 -0
- package/lib/services/database.service.js +67 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -353,7 +353,7 @@ function apply(ctx, config) {
|
|
|
353
353
|
return '获取动态失败,请稍后重试';
|
|
354
354
|
}
|
|
355
355
|
});
|
|
356
|
-
cmd.subcommand('live <roomId>', '
|
|
356
|
+
cmd.subcommand('live <roomId>', '获取B站直播间信息')
|
|
357
357
|
.action(async ({ session }, roomId) => {
|
|
358
358
|
if (!session) {
|
|
359
359
|
return '无法获取会话信息';
|
|
@@ -362,7 +362,7 @@ function apply(ctx, config) {
|
|
|
362
362
|
try {
|
|
363
363
|
const accounts = await ctx.database.get('bilibili', { userId });
|
|
364
364
|
if (!accounts || accounts.length === 0) {
|
|
365
|
-
return '
|
|
365
|
+
return '您还未登录B站账号,请使用 "bilitester login" 进行登录';
|
|
366
366
|
}
|
|
367
367
|
const acc = accounts[0];
|
|
368
368
|
const cookie = getCookieString(acc.sessdata, acc.biliJct, acc.dedeUserId, acc.dedeUserIdCkMd5);
|
|
@@ -391,6 +391,65 @@ function apply(ctx, config) {
|
|
|
391
391
|
return '获取直播间信息失败,请稍后重试';
|
|
392
392
|
}
|
|
393
393
|
});
|
|
394
|
+
cmd.subcommand('search <keyword>', '搜索B站视频')
|
|
395
|
+
.action(async ({ session }, keyword) => {
|
|
396
|
+
if (!session) {
|
|
397
|
+
return '无法获取会话信息';
|
|
398
|
+
}
|
|
399
|
+
const userId = session.userId || session.guildId || 'unknown';
|
|
400
|
+
try {
|
|
401
|
+
const accounts = await ctx.database.get('bilibili', { userId });
|
|
402
|
+
if (!accounts || accounts.length === 0) {
|
|
403
|
+
return '您还未登录B站账号,请使用 "bilitester login" 进行登录';
|
|
404
|
+
}
|
|
405
|
+
const acc = accounts[0];
|
|
406
|
+
const cookie = getCookieString(acc.sessdata, acc.biliJct, acc.dedeUserId, acc.dedeUserIdCkMd5);
|
|
407
|
+
const axiosInstance = createAxiosInstance(cookie);
|
|
408
|
+
const response = await axiosInstance.get('https://api.bilibili.com/x/web-interface/search/type', {
|
|
409
|
+
params: {
|
|
410
|
+
search_type: 'video',
|
|
411
|
+
keyword: keyword,
|
|
412
|
+
page: 1,
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
if (response.data.code === 0) {
|
|
416
|
+
const { data } = response.data;
|
|
417
|
+
const videos = data.result[0]?.data || [];
|
|
418
|
+
if (videos.length === 0) {
|
|
419
|
+
return `未找到与"${keyword}"相关的视频`;
|
|
420
|
+
}
|
|
421
|
+
let result = `搜索结果:${keyword}\n`;
|
|
422
|
+
result += `共找到 ${data.numResults} 个视频,第 ${data.page}/${data.numPages} 页\n`;
|
|
423
|
+
result += '─'.repeat(40) + '\n';
|
|
424
|
+
for (let i = 0; i < Math.min(videos.length, 5); i++) {
|
|
425
|
+
const video = videos[i];
|
|
426
|
+
const duration = video.duration ? video.duration : '未知';
|
|
427
|
+
const pubdate = new Date(video.pubdate * 1000).toLocaleString('zh-CN');
|
|
428
|
+
result += `${i + 1}. ${video.title}\n`;
|
|
429
|
+
result += ` UP主: ${video.author}\n`;
|
|
430
|
+
result += ` BV号: ${video.bvid}\n`;
|
|
431
|
+
result += ` 时长: ${duration}\n`;
|
|
432
|
+
result += ` 播放: ${video.play} | 弹幕: ${video.video_review} | 收藏: ${video.favorites}\n`;
|
|
433
|
+
result += ` 发布: ${pubdate}\n`;
|
|
434
|
+
result += '─'.repeat(40) + '\n';
|
|
435
|
+
}
|
|
436
|
+
if (videos.length > 5) {
|
|
437
|
+
result += `还有 ${videos.length - 5} 个结果未显示...\n`;
|
|
438
|
+
}
|
|
439
|
+
return result;
|
|
440
|
+
}
|
|
441
|
+
else if (response.data.code === -412) {
|
|
442
|
+
return '搜索被拦截,请稍后重试';
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
return '搜索失败,请稍后重试';
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
console.error('搜索视频失败:', error);
|
|
450
|
+
return '搜索视频失败,请稍后重试';
|
|
451
|
+
}
|
|
452
|
+
});
|
|
394
453
|
ctx.on('dispose', () => {
|
|
395
454
|
for (const session of loginSessions.values()) {
|
|
396
455
|
if (session.timer) {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface QRCodeResponse {
|
|
2
|
+
code: number;
|
|
3
|
+
message: string;
|
|
4
|
+
ttl: number;
|
|
5
|
+
data: {
|
|
6
|
+
url: string;
|
|
7
|
+
qrcode_key: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface PollResponse {
|
|
11
|
+
code: number;
|
|
12
|
+
message: string;
|
|
13
|
+
ttl: number;
|
|
14
|
+
data: {
|
|
15
|
+
url: string;
|
|
16
|
+
refresh_token: string;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
code: number;
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface LoginResult {
|
|
23
|
+
success: boolean;
|
|
24
|
+
sessdata?: string;
|
|
25
|
+
biliJct?: string;
|
|
26
|
+
dedeUserId?: string;
|
|
27
|
+
dedeUserIdCkMd5?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface LoginSession {
|
|
30
|
+
qrcodeKey: string;
|
|
31
|
+
userId: string;
|
|
32
|
+
startTime: number;
|
|
33
|
+
}
|
|
34
|
+
export declare class AuthService {
|
|
35
|
+
private static readonly POLL_INTERVAL;
|
|
36
|
+
private static readonly QR_CODE_TIMEOUT;
|
|
37
|
+
static generateQRCode(): Promise<{
|
|
38
|
+
url: string;
|
|
39
|
+
qrcodeKey: string;
|
|
40
|
+
} | null>;
|
|
41
|
+
static pollLoginStatus(qrcodeKey: string, onLogin: (result: LoginResult) => void, onTimeout: () => void, onError: (error: string) => void): Promise<NodeJS.Timeout>;
|
|
42
|
+
static getCookieString(sessdata: string, biliJct: string, dedeUserId: string, dedeUserIdCkMd5: string): string;
|
|
43
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AuthService = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
class AuthService {
|
|
9
|
+
static async generateQRCode() {
|
|
10
|
+
try {
|
|
11
|
+
const response = await axios_1.default.get('https://passport.bilibili.com/x/passport-login/web/qrcode/generate', {
|
|
12
|
+
headers: {
|
|
13
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const { code, data } = response.data;
|
|
17
|
+
if (code === 0 && data) {
|
|
18
|
+
return {
|
|
19
|
+
url: data.url,
|
|
20
|
+
qrcodeKey: data.qrcode_key,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.error('生成二维码失败:', error);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
static async pollLoginStatus(qrcodeKey, onLogin, onTimeout, onError) {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
const timer = setInterval(async () => {
|
|
33
|
+
try {
|
|
34
|
+
const response = await axios_1.default.get('https://passport.bilibili.com/x/passport-login/web/qrcode/poll', {
|
|
35
|
+
params: { qrcode_key: qrcodeKey },
|
|
36
|
+
headers: {
|
|
37
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const { code, data } = response.data;
|
|
41
|
+
if (code === 0) {
|
|
42
|
+
if (data.code === 0) {
|
|
43
|
+
const cookies = response.headers['set-cookie'] || [];
|
|
44
|
+
let sessdata = '';
|
|
45
|
+
let biliJct = '';
|
|
46
|
+
let dedeUserId = '';
|
|
47
|
+
let dedeUserIdCkMd5 = '';
|
|
48
|
+
for (const cookie of cookies) {
|
|
49
|
+
if (cookie.includes('SESSDATA=')) {
|
|
50
|
+
sessdata = cookie.match(/SESSDATA=([^;]+)/)?.[1] || '';
|
|
51
|
+
}
|
|
52
|
+
if (cookie.includes('bili_jct=')) {
|
|
53
|
+
biliJct = cookie.match(/bili_jct=([^;]+)/)?.[1] || '';
|
|
54
|
+
}
|
|
55
|
+
if (cookie.includes('DedeUserID=')) {
|
|
56
|
+
dedeUserId = cookie.match(/DedeUserID=([^;]+)/)?.[1] || '';
|
|
57
|
+
}
|
|
58
|
+
if (cookie.includes('DedeUserID__ckMd5=')) {
|
|
59
|
+
dedeUserIdCkMd5 = cookie.match(/DedeUserID__ckMd5=([^;]+)/)?.[1] || '';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (sessdata && biliJct && dedeUserId) {
|
|
63
|
+
onLogin({
|
|
64
|
+
success: true,
|
|
65
|
+
sessdata,
|
|
66
|
+
biliJct,
|
|
67
|
+
dedeUserId,
|
|
68
|
+
dedeUserIdCkMd5,
|
|
69
|
+
});
|
|
70
|
+
clearInterval(timer);
|
|
71
|
+
resolve(timer);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else if (data.code === 86038) {
|
|
75
|
+
onError('二维码已失效');
|
|
76
|
+
clearInterval(timer);
|
|
77
|
+
resolve(timer);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error('轮询登录状态失败:', error);
|
|
83
|
+
onError('网络错误,请稍后重试');
|
|
84
|
+
clearInterval(timer);
|
|
85
|
+
resolve(timer);
|
|
86
|
+
}
|
|
87
|
+
}, this.POLL_INTERVAL);
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
clearInterval(timer);
|
|
90
|
+
onTimeout();
|
|
91
|
+
resolve(timer);
|
|
92
|
+
}, this.QR_CODE_TIMEOUT * 1000);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
static getCookieString(sessdata, biliJct, dedeUserId, dedeUserIdCkMd5) {
|
|
96
|
+
return `SESSDATA=${sessdata}; bili_jct=${biliJct}; DedeUserID=${dedeUserId}; DedeUserID__ckMd5=${dedeUserIdCkMd5}`;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.AuthService = AuthService;
|
|
100
|
+
AuthService.POLL_INTERVAL = 2000;
|
|
101
|
+
AuthService.QR_CODE_TIMEOUT = 180;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export interface VideoInfo {
|
|
2
|
+
bvid: string;
|
|
3
|
+
aid: number;
|
|
4
|
+
title: string;
|
|
5
|
+
desc: string;
|
|
6
|
+
pic: string;
|
|
7
|
+
owner: {
|
|
8
|
+
mid: string;
|
|
9
|
+
name: string;
|
|
10
|
+
face: string;
|
|
11
|
+
};
|
|
12
|
+
stat: {
|
|
13
|
+
view: number;
|
|
14
|
+
danmaku: number;
|
|
15
|
+
reply: number;
|
|
16
|
+
favorite: number;
|
|
17
|
+
coin: number;
|
|
18
|
+
share: number;
|
|
19
|
+
like: number;
|
|
20
|
+
};
|
|
21
|
+
duration: number;
|
|
22
|
+
pubdate: number;
|
|
23
|
+
}
|
|
24
|
+
export interface VideoSearchResult {
|
|
25
|
+
bvid: string;
|
|
26
|
+
aid: number;
|
|
27
|
+
title: string;
|
|
28
|
+
pic: string;
|
|
29
|
+
description: string;
|
|
30
|
+
owner: {
|
|
31
|
+
mid: string;
|
|
32
|
+
name: string;
|
|
33
|
+
face: string;
|
|
34
|
+
};
|
|
35
|
+
stat: {
|
|
36
|
+
view: number;
|
|
37
|
+
danmaku: number;
|
|
38
|
+
reply: number;
|
|
39
|
+
favorite: number;
|
|
40
|
+
coin: number;
|
|
41
|
+
share: number;
|
|
42
|
+
like: number;
|
|
43
|
+
};
|
|
44
|
+
duration: number;
|
|
45
|
+
pubdate: number;
|
|
46
|
+
}
|
|
47
|
+
export interface UserInfo {
|
|
48
|
+
isLogin: boolean;
|
|
49
|
+
mid: string;
|
|
50
|
+
uname: string;
|
|
51
|
+
face: string;
|
|
52
|
+
vipStatus: number;
|
|
53
|
+
vipType: number;
|
|
54
|
+
vipDueDate: number;
|
|
55
|
+
level_info: {
|
|
56
|
+
current_level: number;
|
|
57
|
+
current_exp: number;
|
|
58
|
+
next_exp: string | number;
|
|
59
|
+
};
|
|
60
|
+
money: number;
|
|
61
|
+
}
|
|
62
|
+
export interface DynamicResponse {
|
|
63
|
+
cards: Array<{
|
|
64
|
+
card: string;
|
|
65
|
+
desc: {
|
|
66
|
+
type: number;
|
|
67
|
+
dynamic_id: number;
|
|
68
|
+
timestamp: number;
|
|
69
|
+
};
|
|
70
|
+
}>;
|
|
71
|
+
}
|
|
72
|
+
export interface LiveRoomInfo {
|
|
73
|
+
roomid: number;
|
|
74
|
+
uid: number;
|
|
75
|
+
title: string;
|
|
76
|
+
live_status: number;
|
|
77
|
+
keyframe: string;
|
|
78
|
+
cover: string;
|
|
79
|
+
online: number;
|
|
80
|
+
area_name: string;
|
|
81
|
+
parent_area_name: string;
|
|
82
|
+
}
|
|
83
|
+
export interface SearchResponse {
|
|
84
|
+
code: number;
|
|
85
|
+
message: string;
|
|
86
|
+
data: {
|
|
87
|
+
result: VideoSearchResult[];
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export declare class BilibiliService {
|
|
91
|
+
private axiosInstance;
|
|
92
|
+
constructor(cookie: string);
|
|
93
|
+
getUserInfo(): Promise<UserInfo | null>;
|
|
94
|
+
getVideoInfo(bvid: string): Promise<VideoInfo | null>;
|
|
95
|
+
searchVideos(keyword: string, page?: number): Promise<VideoSearchResult[] | null>;
|
|
96
|
+
getDynamics(uid: string): Promise<DynamicResponse | null>;
|
|
97
|
+
getLiveRoomInfo(roomId: number): Promise<LiveRoomInfo | null>;
|
|
98
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BilibiliService = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
class BilibiliService {
|
|
9
|
+
constructor(cookie) {
|
|
10
|
+
this.axiosInstance = axios_1.default.create({
|
|
11
|
+
headers: {
|
|
12
|
+
'Cookie': cookie,
|
|
13
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
14
|
+
'Referer': 'https://www.bilibili.com',
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async getUserInfo() {
|
|
19
|
+
try {
|
|
20
|
+
const response = await this.axiosInstance.get('https://api.bilibili.com/x/web-interface/nav');
|
|
21
|
+
if (response.data.code === 0 && response.data.data.isLogin) {
|
|
22
|
+
return response.data.data;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error('获取用户信息失败:', error);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async getVideoInfo(bvid) {
|
|
32
|
+
try {
|
|
33
|
+
const response = await this.axiosInstance.get('https://api.bilibili.com/x/web-interface/view', {
|
|
34
|
+
params: { bvid }
|
|
35
|
+
});
|
|
36
|
+
if (response.data.code === 0) {
|
|
37
|
+
return response.data.data;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error('获取视频信息失败:', error);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async searchVideos(keyword, page = 1) {
|
|
47
|
+
try {
|
|
48
|
+
const response = await this.axiosInstance.get('https://api.bilibili.com/x/web-interface/search/all', {
|
|
49
|
+
params: {
|
|
50
|
+
keyword,
|
|
51
|
+
page,
|
|
52
|
+
search_type: 'video',
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
if (response.data.code === 0) {
|
|
56
|
+
return response.data.data.result;
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error('搜索视频失败:', error);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async getDynamics(uid) {
|
|
66
|
+
try {
|
|
67
|
+
const response = await this.axiosInstance.get('https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new', {
|
|
68
|
+
params: {
|
|
69
|
+
uid,
|
|
70
|
+
type_list: '8',
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
if (response.data.code === 0) {
|
|
74
|
+
return response.data.data;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error('获取动态失败:', error);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async getLiveRoomInfo(roomId) {
|
|
84
|
+
try {
|
|
85
|
+
const response = await this.axiosInstance.get('https://api.live.bilibili.com/room/v1/Room/get_info', {
|
|
86
|
+
params: { room_id: roomId }
|
|
87
|
+
});
|
|
88
|
+
if (response.data.code === 0) {
|
|
89
|
+
return response.data.data;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error('获取直播间信息失败:', error);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.BilibiliService = BilibiliService;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Context } from 'koishi';
|
|
2
|
+
export interface BilibiliAccount {
|
|
3
|
+
id: number;
|
|
4
|
+
userId: string;
|
|
5
|
+
sessdata: string;
|
|
6
|
+
biliJct: string;
|
|
7
|
+
dedeUserId: string;
|
|
8
|
+
dedeUserIdCkMd5: string;
|
|
9
|
+
mid: string;
|
|
10
|
+
name: string;
|
|
11
|
+
face: string;
|
|
12
|
+
vipStatus: number;
|
|
13
|
+
vipType: number;
|
|
14
|
+
vipDueDate: number;
|
|
15
|
+
level: number;
|
|
16
|
+
coins: number;
|
|
17
|
+
createdAt: Date;
|
|
18
|
+
updatedAt: Date;
|
|
19
|
+
}
|
|
20
|
+
export declare class DatabaseService {
|
|
21
|
+
private ctx;
|
|
22
|
+
constructor(ctx: Context);
|
|
23
|
+
createAccount(account: Omit<BilibiliAccount, 'id'>): Promise<BilibiliAccount>;
|
|
24
|
+
getAccountByUserId(userId: string): Promise<BilibiliAccount | null>;
|
|
25
|
+
updateAccount(id: number, data: Partial<Omit<BilibiliAccount, 'id' | 'userId' | 'createdAt'>>): Promise<boolean>;
|
|
26
|
+
deleteAccountByUserId(userId: string): Promise<boolean>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DatabaseService = void 0;
|
|
4
|
+
class DatabaseService {
|
|
5
|
+
constructor(ctx) {
|
|
6
|
+
this.ctx = ctx;
|
|
7
|
+
this.ctx.model.extend('bilibili', {
|
|
8
|
+
id: 'unsigned',
|
|
9
|
+
userId: 'text',
|
|
10
|
+
sessdata: 'text',
|
|
11
|
+
biliJct: 'text',
|
|
12
|
+
dedeUserId: 'text',
|
|
13
|
+
dedeUserIdCkMd5: 'text',
|
|
14
|
+
mid: 'text',
|
|
15
|
+
name: 'text',
|
|
16
|
+
face: 'text',
|
|
17
|
+
vipStatus: 'integer',
|
|
18
|
+
vipType: 'integer',
|
|
19
|
+
vipDueDate: 'integer',
|
|
20
|
+
level: 'integer',
|
|
21
|
+
coins: 'float',
|
|
22
|
+
createdAt: 'timestamp',
|
|
23
|
+
updatedAt: 'timestamp',
|
|
24
|
+
}, {
|
|
25
|
+
autoInc: false,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async createAccount(account) {
|
|
29
|
+
const newAccount = {
|
|
30
|
+
...account,
|
|
31
|
+
id: Date.now(),
|
|
32
|
+
};
|
|
33
|
+
await this.ctx.database.create('bilibili', newAccount);
|
|
34
|
+
return newAccount;
|
|
35
|
+
}
|
|
36
|
+
async getAccountByUserId(userId) {
|
|
37
|
+
const accounts = await this.ctx.database.get('bilibili', { userId });
|
|
38
|
+
if (!accounts || accounts.length === 0) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return accounts[0];
|
|
42
|
+
}
|
|
43
|
+
async updateAccount(id, data) {
|
|
44
|
+
try {
|
|
45
|
+
await this.ctx.database.set('bilibili', { id }, {
|
|
46
|
+
...data,
|
|
47
|
+
updatedAt: new Date(),
|
|
48
|
+
});
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.error('更新账号信息失败:', error);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async deleteAccountByUserId(userId) {
|
|
57
|
+
try {
|
|
58
|
+
await this.ctx.database.remove('bilibili', { userId });
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.error('删除账号信息失败:', error);
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.DatabaseService = DatabaseService;
|