@ikenxuan/amagi 1.4.3

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.
Files changed (58) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +82 -0
  3. package/config/config.yaml +5 -0
  4. package/config/default_config.yaml +5 -0
  5. package/lib/app.d.ts +1 -0
  6. package/lib/app.js +2 -0
  7. package/lib/business/bilibili/API.d.ts +39 -0
  8. package/lib/business/bilibili/API.js +37 -0
  9. package/lib/business/bilibili/getdata.d.ts +9 -0
  10. package/lib/business/bilibili/getdata.js +169 -0
  11. package/lib/business/bilibili/getid.d.ts +26 -0
  12. package/lib/business/bilibili/getid.js +41 -0
  13. package/lib/business/bilibili/index.d.ts +7 -0
  14. package/lib/business/bilibili/index.js +7 -0
  15. package/lib/business/bilibili/qtparam.d.ts +13 -0
  16. package/lib/business/bilibili/qtparam.js +16 -0
  17. package/lib/business/bilibili/result.d.ts +6 -0
  18. package/lib/business/bilibili/result.js +36 -0
  19. package/lib/business/bilibili/sign/CorrespondPath.d.ts +1 -0
  20. package/lib/business/bilibili/sign/CorrespondPath.js +11 -0
  21. package/lib/business/bilibili/sign/wbi.d.ts +1 -0
  22. package/lib/business/bilibili/sign/wbi.js +56 -0
  23. package/lib/business/douyin/API.d.ts +37 -0
  24. package/lib/business/douyin/API.js +42 -0
  25. package/lib/business/douyin/getdata.d.ts +9 -0
  26. package/lib/business/douyin/getdata.js +119 -0
  27. package/lib/business/douyin/getid.d.ts +13 -0
  28. package/lib/business/douyin/getid.js +36 -0
  29. package/lib/business/douyin/index.d.ts +6 -0
  30. package/lib/business/douyin/index.js +6 -0
  31. package/lib/business/douyin/result.d.ts +6 -0
  32. package/lib/business/douyin/result.js +39 -0
  33. package/lib/business/douyin/sign/a_bougs.js +487 -0
  34. package/lib/business/douyin/sign/index.d.ts +8 -0
  35. package/lib/business/douyin/sign/index.js +29 -0
  36. package/lib/index.d.ts +30 -0
  37. package/lib/index.js +113 -0
  38. package/lib/model/config.d.ts +70 -0
  39. package/lib/model/config.js +173 -0
  40. package/lib/model/index.d.ts +4 -0
  41. package/lib/model/index.js +4 -0
  42. package/lib/model/logger.d.ts +3 -0
  43. package/lib/model/logger.js +28 -0
  44. package/lib/model/networks.d.ts +38 -0
  45. package/lib/model/networks.js +224 -0
  46. package/lib/types/ConfigType.d.ts +10 -0
  47. package/lib/types/ConfigType.js +1 -0
  48. package/lib/types/DataType.d.ts +32 -0
  49. package/lib/types/DataType.js +1 -0
  50. package/lib/types/GetDataResponseType.d.ts +17 -0
  51. package/lib/types/GetDataResponseType.js +1 -0
  52. package/lib/types/NetworksConfigType.d.ts +30 -0
  53. package/lib/types/NetworksConfigType.js +1 -0
  54. package/lib/types/OptionsType.d.ts +66 -0
  55. package/lib/types/OptionsType.js +1 -0
  56. package/lib/types/index.d.ts +6 -0
  57. package/lib/types/index.js +1 -0
  58. package/package.json +49 -0
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # amagi
2
+ * 热门平台视频解析 API 基于 Node.js 的实现,支持最低node版本为 v16
3
+ * ~~抖音(坏掉了)~~、B站
4
+
5
+ ## 环境
6
+ > [Node.js](https://nodejs.org) **必要**
7
+
8
+ > [git](https://git-scm.com) _可选_
9
+
10
+ > [pnpm](https://pnpm.io) _可选_
11
+
12
+ ## 使用
13
+ > Node.js版本约定:
14
+ > Node.js => v16.20.2
15
+
16
+ ### 直接使用
17
+ 前往 [releases 页面](https://github.com/ikenxuan/amagi/releases) 找到最新版本的压缩文件(zip格式)下载
18
+
19
+ 解压后打开 `config/config.yaml` 根据提示填写cookies
20
+
21
+ **根目录打开终端运行**
22
+
23
+ * 安装pnpm,已安装可跳过
24
+ ```
25
+ npm install -g pnpm
26
+ ```
27
+ * 安装依赖
28
+ ```
29
+ pnpm install
30
+ ```
31
+ * 启动
32
+ ```
33
+ pnpm app
34
+ ```
35
+
36
+ ### 外部调用
37
+ **快速上手:**
38
+ ```js
39
+ import { StartClient, CreateNewClient, AddRoute } from '@ikenxuan/amagi';
40
+
41
+ const main = async () => {
42
+ let client = CreateNewClient({ log: true });
43
+ const handler = (request, reply) => {
44
+ // http://ip:port/your-route?url=http://www.baidu.com
45
+ const url = request.query.url;
46
+ reply.type('application/json').send({ hello: 'hello, world!', url });
47
+ };
48
+ const routeArray = [
49
+ // http://ip:port/1
50
+ { method: 'GET', url: '/1', handler, },
51
+ { method: 'GET', url: '/2', handler, },
52
+ { method: 'GET', url: '/3', handler, },
53
+ { method: 'GET', url: '/4', handler }
54
+ ];
55
+ // 继承 amagi 路由规则
56
+ client = AddRoute(client, routeArray, true);
57
+ // 监听4567端口
58
+ return await StartClient(client, { port: 4567 });
59
+ };
60
+
61
+ await main().catch((error) => console.log(error));
62
+ ```
63
+ ## 开发构建
64
+ > Node.js版本约定:
65
+ > v18.20.4 <= Node.js <= v22.x.x
66
+ * 克隆仓库
67
+ ```
68
+ git clone git@github.com:ikenxuan/amagi.git
69
+ ```
70
+ * 安装依赖
71
+ ```
72
+ pnpm install
73
+ ```
74
+ * 运行
75
+ ```
76
+ pnpm dev
77
+ ```
78
+
79
+ ## 其他
80
+ 该项目代码从 [kkkkkk-10086](https://github.com/ikenxuan/kkkkkk-10086) 提取修改并发布
81
+
82
+ <h2>未经同意,禁止将本项目的开源代码用于任何商业目的。因使用本项目产生的一切问题与后果由使用者自行承担,项目开发者不承担任何责任</h2>
@@ -0,0 +1,5 @@
1
+ # 抖音ck
2
+ douyin:
3
+
4
+ # B站ck
5
+ bilibili:
@@ -0,0 +1,5 @@
1
+ # 抖音ck
2
+ douyin:
3
+
4
+ # B站ck
5
+ bilibili:
package/lib/app.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/lib/app.js ADDED
@@ -0,0 +1,2 @@
1
+ import { StartClient, CreateNewClient } from './index.js';
2
+ (() => { return StartClient(CreateNewClient({ log: true }), { port: 4567 }); })();
@@ -0,0 +1,39 @@
1
+ declare class BiLiBiLiAPI {
2
+ LOGIN_INFO(): string;
3
+ INFO(data: {
4
+ id_type: string;
5
+ id: string;
6
+ }): string;
7
+ VIDEO(data: {
8
+ avid: string;
9
+ cid: string;
10
+ }): string;
11
+ /** type参数详见https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/readme.md#评论区类型代码 */
12
+ COMMENTS(data: {
13
+ type: number;
14
+ oid: number;
15
+ }): string;
16
+ EMOJI(): string;
17
+ bangumivideo(data: {
18
+ id: string;
19
+ isep: boolean | undefined;
20
+ }): string;
21
+ bangumidata(data: {
22
+ cid: string;
23
+ ep_id: string;
24
+ }): string;
25
+ 获取用户空间动态(data: {
26
+ host_mid: string;
27
+ }): string;
28
+ 动态详情(data: {
29
+ dynamic_id: string;
30
+ }): string;
31
+ 动态卡片信息(data: {
32
+ dynamic_id: string;
33
+ }): string;
34
+ 用户名片信息(data: {
35
+ host_mid: string;
36
+ }): string;
37
+ }
38
+ declare const _default: BiLiBiLiAPI;
39
+ export default _default;
@@ -0,0 +1,37 @@
1
+ class BiLiBiLiAPI {
2
+ LOGIN_INFO() {
3
+ return 'https://api.bilibili.com/x/web-interface/nav';
4
+ }
5
+ INFO(data) {
6
+ return `https://api.bilibili.com/x/web-interface/view?${data.id_type === 'bvid' ? 'bvid=' + data.id : 'aid=' + data.id}`;
7
+ }
8
+ VIDEO(data) {
9
+ return `https://api.bilibili.com/x/player/playurl?avid=${data.avid}&cid=${data.cid}`;
10
+ }
11
+ /** type参数详见https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/readme.md#评论区类型代码 */
12
+ COMMENTS(data) {
13
+ return `https://api.bilibili.com/x/v2/reply?sort=1&ps=20&type=${data.type}&oid=${data.oid}`;
14
+ }
15
+ EMOJI() {
16
+ return 'https://api.bilibili.com/x/emote/user/panel/web?business=reply&web_location=0.0';
17
+ }
18
+ bangumivideo(data) {
19
+ return `https://api.bilibili.com/pgc/view/web/season?${data.isep ? 'ep_id' : 'season_id'}=${data.id}`;
20
+ }
21
+ bangumidata(data) {
22
+ return `https://api.bilibili.com/pgc/player/web/playurl?cid=${data.cid}&ep_id=${data.ep_id}`;
23
+ }
24
+ 获取用户空间动态(data) {
25
+ return `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?host_mid=${data.host_mid}`;
26
+ }
27
+ 动态详情(data) {
28
+ return `https://api.bilibili.com/x/polymer/web-dynamic/v1/detail?id=${data.dynamic_id}`;
29
+ }
30
+ 动态卡片信息(data) {
31
+ return `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=${data.dynamic_id}`;
32
+ }
33
+ 用户名片信息(data) {
34
+ return `https://api.bilibili.com/x/web-interface/card?mid=${data.host_mid}&photo=true`;
35
+ }
36
+ }
37
+ export default new BiLiBiLiAPI();
@@ -0,0 +1,9 @@
1
+ import { BilibiliDataType, BilibiliOptionsType, NetworksConfigType } from '../../types/index.js';
2
+ export default class BilibiliData {
3
+ type: BilibiliDataType;
4
+ headers: any;
5
+ URL: string | undefined;
6
+ constructor(type: BilibiliDataType);
7
+ GetData(data?: BilibiliOptionsType): Promise<any>;
8
+ GlobalGetData(options: NetworksConfigType): Promise<any>;
9
+ }
@@ -0,0 +1,169 @@
1
+ import { BiLiBiLiAPI, qtparam, wbi_sign } from '../../business/bilibili/index.js';
2
+ import { Networks, Config, logger } from '../../model/index.js';
3
+ export default class BilibiliData {
4
+ type;
5
+ headers;
6
+ URL;
7
+ constructor(type) {
8
+ this.type = type;
9
+ this.headers = {};
10
+ this.headers.Referer = 'https://api.bilibili.com/';
11
+ this.headers.Cookie = Config.bilibili;
12
+ }
13
+ async GetData(data = {}) {
14
+ let result;
15
+ switch (this.type) {
16
+ case 'VideoData': {
17
+ const INFODATA = await this.GlobalGetData({ url: BiLiBiLiAPI.INFO({ id_type: 'bvid', id: data.id }) });
18
+ const BASEURL = BiLiBiLiAPI.VIDEO({ avid: INFODATA.data.aid, cid: INFODATA.data.cid });
19
+ const SIGN = await qtparam(BASEURL);
20
+ const DATA = await this.GlobalGetData({
21
+ url: BiLiBiLiAPI.VIDEO({ avid: INFODATA.data.aid, cid: INFODATA.data.cid }) + SIGN.QUERY,
22
+ headers: this.headers
23
+ });
24
+ return { INFODATA, DATA, };
25
+ }
26
+ case 'CommentData': {
27
+ const INFODATA = await this.GlobalGetData({ url: BiLiBiLiAPI.INFO({ id_type: 'bvid', id: data.bvid }) });
28
+ const PARAM = await wbi_sign(BiLiBiLiAPI.COMMENTS({ type: 1, oid: INFODATA.data.aid }));
29
+ const COMMENTSDATA = await this.GlobalGetData({ url: BiLiBiLiAPI.COMMENTS({ type: 1, oid: INFODATA.data.aid }) + PARAM, headers: this.headers });
30
+ return COMMENTSDATA;
31
+ }
32
+ case 'EmojiData':
33
+ return await this.GlobalGetData({ url: BiLiBiLiAPI.EMOJI() });
34
+ case 'BangumiVideoData': {
35
+ let isep;
36
+ if (data?.id?.startsWith('ss')) {
37
+ data.id = data.id.replace('ss', '');
38
+ isep = false;
39
+ }
40
+ else if (data?.id?.startsWith('ep')) {
41
+ data.id = data?.id?.replace('ep', '');
42
+ isep = true;
43
+ }
44
+ const INFO = await this.GlobalGetData({
45
+ url: BiLiBiLiAPI.bangumivideo({ id: data.id, isep }),
46
+ headers: this.headers
47
+ });
48
+ return INFO;
49
+ }
50
+ case 'BangumiVideoDownloadLinkData':
51
+ return await this.GlobalGetData({ url: BiLiBiLiAPI.bangumidata({ cid: data.cid, ep_id: data.ep_id }) });
52
+ case 'UserDynamicListData':
53
+ delete this.headers.Referer;
54
+ result = await this.GlobalGetData({
55
+ url: BiLiBiLiAPI.获取用户空间动态({ host_mid: data.host_mid }),
56
+ headers: this.headers
57
+ });
58
+ return result;
59
+ case 'DynamicInfoData': {
60
+ delete this.headers.Referer;
61
+ const dynamicINFO = await this.GlobalGetData({
62
+ url: BiLiBiLiAPI.动态详情({ dynamic_id: data.dynamic_id }),
63
+ headers: this.headers
64
+ });
65
+ return dynamicINFO;
66
+ }
67
+ case 'DynamicCardData': {
68
+ delete this.headers.Referer;
69
+ const dynamicINFO_CARD = await this.GlobalGetData({
70
+ url: BiLiBiLiAPI.动态卡片信息({ dynamic_id: data.dynamic_id }),
71
+ headers: this.headers
72
+ });
73
+ return dynamicINFO_CARD;
74
+ }
75
+ case 'UserInfoData':
76
+ result = await this.GlobalGetData({
77
+ url: BiLiBiLiAPI.用户名片信息({ host_mid: data.host_mid }),
78
+ headers: this.headers
79
+ });
80
+ return result;
81
+ }
82
+ }
83
+ async GlobalGetData(options) {
84
+ const result = await new Networks(options).getData();
85
+ if (result && result.code !== 0) {
86
+ const errorMessage = errorMap[result.code] || '未知错误';
87
+ logger.error(`获取响应数据失败!\n请求接口类型:${this.type}\n请求URL:${options.url}\n错误代码:${result.code},\n含义:${errorMessage}`);
88
+ return null;
89
+ }
90
+ else {
91
+ return result;
92
+ }
93
+ }
94
+ }
95
+ function mapping_table(type) {
96
+ // 使用类型断言来告诉 TypeScript 编译器 Array 对象实际上是一个可以接受字符串索引的对象
97
+ const Array = {
98
+ 1: ['DYNAMIC_TYPE_AV', 'DYNAMIC_TYPE_PGC', 'DYNAMIC_TYPE_UGC_SEASON'],
99
+ 11: ['DYNAMIC_TYPE_DRAW'],
100
+ 12: ['DYNAMIC_TYPE_ARTICLE'],
101
+ 17: ['DYNAMIC_TYPE_LIVE_RCMD', 'DYNAMIC_TYPE_FORWARD', 'DYNAMIC_TYPE_WORD', 'DYNAMIC_TYPE_COMMON_SQUARE'],
102
+ 19: ['DYNAMIC_TYPE_MEDIALIST']
103
+ };
104
+ for (const key in Array) {
105
+ if (Array[key].includes(type)) {
106
+ return parseInt(key);
107
+ }
108
+ }
109
+ return 1;
110
+ }
111
+ function oid(dynamicINFO, dynamicINFO_CARD) {
112
+ if (dynamicINFO.data.item.type == 'DYNAMIC_TYPE_WORD') {
113
+ return dynamicINFO.data.item.id_str;
114
+ }
115
+ else
116
+ return dynamicINFO_CARD.data.card.desc.rid;
117
+ }
118
+ // 同上
119
+ const errorMap = {
120
+ '-1': '应用程序不存在或已被封禁',
121
+ '-2': 'Access Key 错误',
122
+ '-3': 'API 校验密匙错误',
123
+ '-4': '调用方对该 Method 没有权限',
124
+ '-101': '账号未登录',
125
+ '-102': '账号被封停',
126
+ '-103': '积分不足',
127
+ '-104': '硬币不足',
128
+ '-105': '验证码错误',
129
+ '-106': '账号非正式会员或在适应期',
130
+ '-107': '应用不存在或者被封禁',
131
+ '-108': '未绑定手机',
132
+ '-110': '未绑定手机',
133
+ '-111': 'csrf 校验失败',
134
+ '-112': '系统升级中',
135
+ '-113': '账号尚未实名认证',
136
+ '-114': '请先绑定手机',
137
+ '-115': '请先完成实名认证',
138
+ '-304': '木有改动',
139
+ '-307': '撞车跳转',
140
+ '-352': '风控校验失败 (UA 或 wbi 参数不合法)',
141
+ '-400': '请求错误',
142
+ '-401': '未认证 (或非法请求)',
143
+ '-403': '访问权限不足',
144
+ '-404': '啥都木有',
145
+ '-405': '不支持该方法',
146
+ '-409': '冲突',
147
+ '-412': '请求被拦截 (客户端 ip 被服务端风控)',
148
+ '-500': '服务器错误',
149
+ '-503': '过载保护,服务暂不可用',
150
+ '-504': '服务调用超时',
151
+ '-509': '超出限制',
152
+ '-616': '上传文件不存在',
153
+ '-617': '上传文件太大',
154
+ '-625': '登录失败次数太多',
155
+ '-626': '用户不存在',
156
+ '-628': '密码太弱',
157
+ '-629': '用户名或密码错误',
158
+ '-632': '操作对象数量限制',
159
+ '-643': '被锁定',
160
+ '-650': '用户等级太低',
161
+ '-652': '重复的用户',
162
+ '-658': 'Token 过期',
163
+ '-662': '密码时间戳过期',
164
+ '-688': '地理区域限制',
165
+ '-689': '版权限制',
166
+ '-701': '扣节操失败',
167
+ '-799': '请求过于频繁,请稍后再试',
168
+ '-8888': '对不起,服务器开小差了~ (ಥ﹏ಥ)'
169
+ };
@@ -0,0 +1,26 @@
1
+ import { BilibiliDataType } from '../../types/index.js';
2
+ interface IDDataTypes {
3
+ /**
4
+ * 类型
5
+ */
6
+ type: BilibiliDataType;
7
+ /**
8
+ * 作品ID、BV号、AV号
9
+ */
10
+ id?: string;
11
+ /**
12
+ * 动态ID、
13
+ */
14
+ dynamic_id?: string;
15
+ /**
16
+ * 用户UID
17
+ */
18
+ host_mid?: string;
19
+ }
20
+ /**
21
+ * return aweme_id
22
+ * @param {string} url 分享连接
23
+ * @returns
24
+ */
25
+ export default function GetBilibiliID(url: string): Promise<IDDataTypes>;
26
+ export {};
@@ -0,0 +1,41 @@
1
+ import { Networks } from '../../model/index.js';
2
+ /**
3
+ * return aweme_id
4
+ * @param {string} url 分享连接
5
+ * @returns
6
+ */
7
+ export default async function GetBilibiliID(url) {
8
+ const longLink = await new Networks({ url }).getLongLink();
9
+ let result = {};
10
+ switch (true) {
11
+ case /video\/([A-Za-z0-9]+)/.test(longLink): {
12
+ const bvideoMatch = longLink.match(/video\/([A-Za-z0-9]+)/);
13
+ result = {
14
+ type: "VideoData" /* BilibiliDataType['单个视频作品数据'] */,
15
+ id: bvideoMatch ? bvideoMatch[1] : '',
16
+ };
17
+ break;
18
+ }
19
+ case /play\/(\S+?)\??/.test(longLink): {
20
+ const playMatch = longLink.match(/play\/(\w+)/);
21
+ result = {
22
+ type: "BangumiVideoData" /* BilibiliDataType['番剧基本信息数据'] */,
23
+ id: playMatch ? playMatch[1] : '',
24
+ };
25
+ break;
26
+ }
27
+ case /^https:\/\/t\.bilibili\.com\/(\d+)/.test(longLink) || /^https:\/\/www\.bilibili\.com\/opus\/(\d+)/.test(longLink): {
28
+ const tMatch = longLink.match(/^https:\/\/t\.bilibili\.com\/(\d+)/);
29
+ const opusMatch = longLink.match(/^https:\/\/www\.bilibili\.com\/opus\/(\d+)/);
30
+ const dynamic_id = tMatch || opusMatch;
31
+ result = {
32
+ type: "DynamicInfoData" /* BilibiliDataType['动态详情数据'] */,
33
+ dynamic_id: dynamic_id ? dynamic_id[1] : '',
34
+ };
35
+ break;
36
+ }
37
+ default:
38
+ break;
39
+ }
40
+ return result;
41
+ }
@@ -0,0 +1,7 @@
1
+ import BiLiBiLiAPI from './API.js';
2
+ import BilibiliData from './getdata.js';
3
+ import GetBilibiliID from './getid.js';
4
+ import wbi_sign from './sign/wbi.js';
5
+ import qtparam from './qtparam.js';
6
+ import BilibiliResult from './result.js';
7
+ export { BiLiBiLiAPI, BilibiliData, GetBilibiliID, wbi_sign, qtparam, BilibiliResult };
@@ -0,0 +1,7 @@
1
+ import BiLiBiLiAPI from './API.js';
2
+ import BilibiliData from './getdata.js';
3
+ import GetBilibiliID from './getid.js';
4
+ import wbi_sign from './sign/wbi.js';
5
+ import qtparam from './qtparam.js';
6
+ import BilibiliResult from './result.js';
7
+ export { BiLiBiLiAPI, BilibiliData, GetBilibiliID, wbi_sign, qtparam, BilibiliResult };
@@ -0,0 +1,13 @@
1
+ export default function qtparam(BASEURL: string): Promise<{
2
+ QUERY: string;
3
+ STATUS: string;
4
+ isvip?: undefined;
5
+ } | {
6
+ QUERY: string;
7
+ STATUS: string;
8
+ isvip: true;
9
+ } | {
10
+ QUERY: string;
11
+ STATUS: string;
12
+ isvip: false;
13
+ }>;
@@ -0,0 +1,16 @@
1
+ import { Config, Networks } from '../../model/index.js';
2
+ import { BiLiBiLiAPI, wbi_sign } from '../../business/bilibili/index.js';
3
+ export default async function qtparam(BASEURL) {
4
+ if (Config.bilibili == '')
5
+ return { QUERY: '&platform=html5', STATUS: '!isLogin' };
6
+ const logininfo = await new Networks({ url: BiLiBiLiAPI.LOGIN_INFO(), headers: { Cookie: Config.bilibili } }).getData();
7
+ const sign = await wbi_sign(BASEURL);
8
+ const qn = [6, 16, 32, 64, 74, 80, 112, 116, 120, 125, 126, 127];
9
+ let isvip;
10
+ logininfo.data.vipStatus === 1 ? (isvip = true) : (isvip = false);
11
+ if (isvip) {
12
+ return { QUERY: `&fnval=16&fourk=1&${sign}`, STATUS: 'isLogin', isvip };
13
+ }
14
+ else
15
+ return { QUERY: `&qn=${qn[3]}&fnval=16`, STATUS: 'isLogin', isvip };
16
+ }
@@ -0,0 +1,6 @@
1
+ import { BilibiliDataType, GetDataResponseType, BilibiliOptionsType } from '../../types/index.js';
2
+ export default class BilibiliResult {
3
+ type: BilibiliDataType;
4
+ constructor(type: BilibiliDataType);
5
+ result(options?: BilibiliOptionsType): Promise<GetDataResponseType>;
6
+ }
@@ -0,0 +1,36 @@
1
+ import { BilibiliData, GetBilibiliID } from '../../business/bilibili/index.js';
2
+ export default class BilibiliResult {
3
+ type;
4
+ constructor(type) {
5
+ this.type = type;
6
+ }
7
+ async result(options = {}) {
8
+ let result;
9
+ switch (this.type) {
10
+ case 'UserInfoData':
11
+ case 'SearchData':
12
+ case 'EmojiData':
13
+ case 'CommentData':
14
+ case 'BangumiVideoDownloadLinkData':
15
+ case 'UserDynamicListData':
16
+ case 'DynamicInfoData':
17
+ case 'DynamicCardData':
18
+ result = await new BilibiliData(this.type).GetData(options);
19
+ break;
20
+ case 'VideoData':
21
+ case 'BangumiVideoData': {
22
+ const iddata = await GetBilibiliID(options.url);
23
+ result = await new BilibiliData(this.type).GetData(iddata);
24
+ break;
25
+ }
26
+ default:
27
+ result = '';
28
+ break;
29
+ }
30
+ return {
31
+ code: result !== false && result !== '' ? 200 : 503,
32
+ message: result !== !false && result !== '' ? 'success' : 'error',
33
+ data: result !== !false && result !== '' ? result : null,
34
+ };
35
+ }
36
+ }
@@ -0,0 +1 @@
1
+ export default function getCorrespondPath(timestamp: number): Promise<string>;
@@ -0,0 +1,11 @@
1
+ import crypto from 'crypto';
2
+ const publicKey = await crypto.subtle.importKey('jwk', {
3
+ kty: 'RSA',
4
+ n: 'y4HdjgJHBlbaBN04VERG4qNBIFHP6a3GozCl75AihQloSWCXC5HDNgyinEnhaQ_4-gaMud_GF50elYXLlCToR9se9Z8z433U3KjM-3Yx7ptKkmQNAMggQwAVKgq3zYAoidNEWuxpkY_mAitTSRLnsJW-NCTa0bqBFF6Wm1MxgfE',
5
+ e: 'AQAB'
6
+ }, { name: 'RSA-OAEP', hash: 'SHA-256' }, true, ['encrypt']);
7
+ export default async function getCorrespondPath(timestamp) {
8
+ const data = new TextEncoder().encode(`refresh_${timestamp}`);
9
+ const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: 'RSA-OAEP' }, publicKey, data));
10
+ return encrypted.reduce((str, c) => str + c.toString(16).padStart(2, '0'), '');
11
+ }
@@ -0,0 +1 @@
1
+ export default function wbi_sign(BASEURL: string | URL): Promise<string>;
@@ -0,0 +1,56 @@
1
+ import { Config } from '../../../model/index.js';
2
+ import md5 from 'md5';
3
+ import fetch from 'node-fetch';
4
+ const mixinKeyEncTab = [
5
+ 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26,
6
+ 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52,
7
+ ];
8
+ // 对 imgKey 和 subKey 进行字符顺序打乱编码
9
+ const getMixinKey = (orig) => mixinKeyEncTab
10
+ .map((n) => orig[n])
11
+ .join('')
12
+ .slice(0, 32);
13
+ // 为请求参数进行 wbi 签名
14
+ function encWbi(params, img_key, sub_key) {
15
+ const mixin_key = getMixinKey(img_key + sub_key);
16
+ const curr_time = Math.round(Date.now() / 1000);
17
+ const chr_filter = /[!'()*]/g;
18
+ Object.assign(params, { wts: curr_time }); // 添加 wts 字段
19
+ // 按照 key 重排参数
20
+ const query = Object.keys(params)
21
+ .sort()
22
+ .map((key) => {
23
+ // 过滤 value 中的 "!'()*" 字符
24
+ const value = params[key].toString().replace(chr_filter, '');
25
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
26
+ })
27
+ .join('&');
28
+ const wbi_sign = md5(query + mixin_key); // 计算 w_rid
29
+ return `&wts=${curr_time}` + `&w_rid=${wbi_sign}`;
30
+ }
31
+ // 获取最新的 img_key 和 sub_key
32
+ async function getWbiKeys() {
33
+ const res = await fetch('https://api.bilibili.com/x/web-interface/nav', {
34
+ headers: {
35
+ Cookie: Config.bilibili,
36
+ },
37
+ });
38
+ const responseJson = await res.json();
39
+ const response = responseJson; // 类型断言
40
+ // 确保response是ResponseData类型后再解构
41
+ const { data: { wbi_img: { img_url, sub_url }, }, } = response;
42
+ return {
43
+ img_key: img_url.slice(img_url.lastIndexOf('/') + 1, img_url.lastIndexOf('.')),
44
+ sub_key: sub_url.slice(sub_url.lastIndexOf('/') + 1, sub_url.lastIndexOf('.')),
45
+ };
46
+ }
47
+ export default async function wbi_sign(BASEURL) {
48
+ const web_keys = await getWbiKeys();
49
+ const url = new URL(BASEURL);
50
+ const params = {};
51
+ for (const [key, value] of url.searchParams.entries()) {
52
+ params[key] = value;
53
+ }
54
+ const query = encWbi(params, web_keys.img_key, web_keys.sub_key);
55
+ return query;
56
+ }
@@ -0,0 +1,37 @@
1
+ declare class DouyinAPI {
2
+ 视频或图集(data: {
3
+ aweme_id: string;
4
+ }): string;
5
+ 评论(data: {
6
+ aweme_id: string;
7
+ }): string;
8
+ 二级评论(data: {
9
+ aweme_id: string;
10
+ comment_id: string;
11
+ }): string;
12
+ 动图(data: {
13
+ aweme_id: string;
14
+ }): string;
15
+ 表情(): string;
16
+ 用户主页视频(data: {
17
+ sec_uid: string;
18
+ }): string;
19
+ 用户主页信息(data: {
20
+ sec_uid: string;
21
+ }): string;
22
+ 热点词(data: {
23
+ query: string;
24
+ }): string;
25
+ 搜索(data: {
26
+ query: string;
27
+ }): string;
28
+ 互动表情(): string;
29
+ 背景音乐(data: {
30
+ music_id: string;
31
+ }): string;
32
+ 直播间信息(data: {
33
+ room_id: string;
34
+ }): string;
35
+ }
36
+ declare const _default: DouyinAPI;
37
+ export default _default;