Skip to content

Commit c3f4854

Browse files
committed
update:增加本地代理功能
1 parent f34415c commit c3f4854

File tree

8 files changed

+216
-34
lines changed

8 files changed

+216
-34
lines changed

Diff for: README.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ nodejs作为服务端的drpy实现。全面升级异步写法
88

99
## 更新记录
1010

11-
### 20241204
11+
### 20241205
1212

13-
1. 引入crypto-js-wasm.js和使用文档
14-
2. 增加docs接口可以查看文档md文件的html页面
13+
1. 完善本地代理功能
1514

1615
[点此查看完整更新记录](docs/updateRecord.md)
1716

Diff for: controllers/api.js

+87-8
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,21 @@ export default (fastify, options, done) => {
1313
reply.status(404).send({error: `Module ${moduleName} not found`});
1414
return;
1515
}
16-
16+
const protocol = request.protocol;
17+
const hostname = request.hostname;
18+
const proxyUrl = `${protocol}://${hostname}${request.url}`.split('?')[0].replace('/api/', '/proxy/') + '/?do=js';
19+
// console.log(`proxyUrl:${proxyUrl}`);
20+
const env = {
21+
proxyUrl, getProxyUrl: function () {
22+
return proxyUrl
23+
}
24+
};
1725
const pg = Number(query.pg) || 1;
1826
try {
1927
// 根据 query 参数决定执行逻辑
2028
if ('play' in query) {
2129
// 处理播放逻辑
22-
const result = await drpy.play(modulePath, query.flag, query.play);
30+
const result = await drpy.play(modulePath, env, query.flag, query.play);
2331
return reply.send(result);
2432
}
2533

@@ -33,35 +41,35 @@ export default (fastify, options, done) => {
3341
}
3442
}
3543
// 分类逻辑
36-
const result = await drpy.cate(modulePath, query.t, pg, 1, extend);
44+
const result = await drpy.cate(modulePath, env, query.t, pg, 1, extend);
3745
return reply.send(result);
3846
}
3947

4048
if ('ac' in query && 'ids' in query) {
4149
// 详情逻辑
42-
const result = await drpy.detail(modulePath, query.ids.split(','));
50+
const result = await drpy.detail(modulePath, env, query.ids.split(','));
4351
return reply.send(result);
4452
}
4553

4654
if ('wd' in query) {
4755
// 搜索逻辑
4856
const quick = 'quick' in query ? query.quick : 0;
49-
const result = await drpy.search(modulePath, query.wd, quick, pg);
57+
const result = await drpy.search(modulePath, env, query.wd, quick, pg);
5058
return reply.send(result);
5159
}
5260

5361
if ('refresh' in query) {
5462
// 强制刷新初始化逻辑
55-
const refreshedObject = await drpy.init(modulePath, true);
63+
const refreshedObject = await drpy.init(modulePath, env, true);
5664
return reply.send(refreshedObject);
5765
}
5866
if (!('filter' in query)) {
5967
query.filter = 1
6068
}
6169
// 默认逻辑,返回 home + homeVod 接口
6270
const filter = 'filter' in query ? query.filter : 1;
63-
const resultHome = await drpy.home(modulePath, filter);
64-
const resultHomeVod = await drpy.homeVod(modulePath);
71+
const resultHome = await drpy.home(modulePath, env, filter);
72+
const resultHomeVod = await drpy.homeVod(modulePath, env);
6573
const result = {
6674
...resultHome,
6775
list: resultHomeVod,
@@ -77,5 +85,76 @@ export default (fastify, options, done) => {
7785
reply.status(500).send({error: `Failed to process module ${moduleName}: ${error.message}`});
7886
}
7987
});
88+
89+
fastify.get('/proxy/:module/*', async (request, reply) => {
90+
const moduleName = request.params.module;
91+
const query = request.query; // 获取 query 参数
92+
const modulePath = path.join(options.jsDir, `${moduleName}.js`);
93+
if (!existsSync(modulePath)) {
94+
reply.status(404).send({error: `Module ${moduleName} not found`});
95+
return;
96+
}
97+
const proxy_url = request.params['*']; // 捕获整个路径
98+
fastify.log.info(`try proxy for ${moduleName} -> ${proxy_url}:`);
99+
const protocol = request.protocol;
100+
const hostname = request.hostname;
101+
const proxyUrl = `${protocol}://${hostname}${request.url}`.split('?')[0].replace(proxy_url, '') + '?do=js';
102+
// console.log(`proxyUrl:${proxyUrl}`);
103+
const env = {
104+
proxyUrl, getProxyUrl: function () {
105+
return proxyUrl
106+
}
107+
};
108+
try {
109+
const backRespList = await drpy.proxy(modulePath, env, query);
110+
const statusCode = backRespList[0];
111+
const mediaType = backRespList[1];
112+
let content = backRespList[2];
113+
const headers = backRespList.length > 3 ? backRespList[3] : null;
114+
const toBytes = backRespList.length > 4 ? backRespList[4] : null;
115+
// 如果需要转换为字节内容
116+
if (toBytes) {
117+
try {
118+
if (content.includes('base64,')) {
119+
content = unescape(content.split("base64,")[1]);
120+
}
121+
content = Buffer.from(content, 'base64');
122+
} catch (e) {
123+
fastify.log.error(`Local Proxy toBytes error: ${e}`);
124+
}
125+
}
126+
127+
// 根据媒体类型来决定如何设置字符编码
128+
if (typeof content === 'string') {
129+
// 如果返回的是文本内容(例如 JSON 或字符串)
130+
if (mediaType.includes('text') || mediaType === 'application/json') {
131+
// 对于文本类型,设置 UTF-8 编码
132+
reply
133+
.code(statusCode)
134+
.type(`${mediaType}; charset=utf-8`) // 设置编码为 UTF-8
135+
.headers(headers || {}) // 如果有headers, 则加上
136+
.send(content);
137+
} else {
138+
// 对于其他类型的文本(例如 XML),直接返回,不指定 UTF-8 编码
139+
reply
140+
.code(statusCode)
141+
.type(mediaType)
142+
.headers(headers || {})
143+
.send(content);
144+
}
145+
} else {
146+
// 如果返回的是二进制内容(例如图片或其他文件)
147+
reply
148+
.code(statusCode)
149+
.type(mediaType) // 使用合适的媒体类型,如 image/png
150+
.headers(headers || {})
151+
.send(content);
152+
}
153+
154+
} catch (error) {
155+
fastify.log.error(`Error proxy module ${moduleName}:`, error);
156+
reply.status(500).send({error: `Failed to proxy module ${moduleName}: ${error.message}`});
157+
}
158+
});
80159
done();
81160
};

Diff for: controllers/root.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import path from 'path';
2-
import {readdirSync, readFileSync} from 'fs';
2+
import {readdirSync, readFileSync, existsSync} from 'fs';
33
import '../utils/marked.min.js';
44

55
export default (fastify, options, done) => {
@@ -41,5 +41,22 @@ export default (fastify, options, done) => {
4141
</html>
4242
`);
4343
});
44+
45+
// 新增 /favicon.ico 路由
46+
fastify.get('/favicon.ico', async (request, reply) => {
47+
try {
48+
// 设置文件路径
49+
const faviconPath = path.join(options.rootDir, 'public', 'favicon.ico');
50+
51+
// 如果文件存在,返回图片
52+
if (existsSync(faviconPath)) {
53+
return reply.sendFile('favicon.ico', path.join(options.rootDir, 'public')); // 直接返回图片
54+
} else {
55+
reply.status(404).send({error: 'Favicon not found'}); // 如果文件不存在,返回 404 错误
56+
}
57+
} catch (error) {
58+
reply.status(500).send({error: 'Failed to fetch favicon', details: error.message});
59+
}
60+
});
4461
done();
4562
};

Diff for: docs/updateRecord.md

+30
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,42 @@
11
# drpyS更新记录
22

3+
### 20241205
4+
5+
更新至V1.0.2
6+
7+
1. 增加本地代理功能,示例参考_qq.js 用法:在源的各个js函数里(http://192.168.31.49:5757/api/_qq)
8+
9+
```javascript
10+
let {getProxyUrl} = this;
11+
let vod_url = getProxyUrl() + '&url=' + 'https://hls09.cntv.myhwcdn.cn/asp/hls/2000/0303000a/3/default/d9b0eaa065934f25abd193d391f731b6/2000.m3u8';
12+
```
13+
314
### 20241204
15+
416
更新至V1.0.1
17+
518
1. 引入crypto-js-wasm.js和使用文档
619
2. 增加docs接口可以查看文档md文件的html页面
720
3. 完成index.js接口剥离,保持主文件的干净。同时导出start和stop方法
821
4. 改进本地配置接口,增加外网可用配置。
922
5. 支持puppeteer,仅pc可用。如需使用请手动安装puppeteer库,然后drpyS的源里支持使用puppeteerHelper对象。
23+
6. 添加favicon.ico
24+
7. 引入全局CryptoJSW对象(海阔暂时会报错无法使用)
25+
8. 增加本地代理功能,示例(跳转百度):
26+
27+
```javascript
28+
{
29+
proxy_rule: async function (params) {
30+
// log(this);
31+
let {input, MY_URL} = this;
32+
log(`params:`, params);
33+
log(`input:${input}`);
34+
log(`MY_URL::${MY_URL}`);
35+
// return [404, 'text/plain', 'Not Found']
36+
return [302, 'text/html', '', {location: 'http://www.baidu.com'}]
37+
}
38+
}
39+
```
1040

1141
### 20241203
1242

Diff for: js/_qq.js

+22-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var rule = {
55
class_parse: async () => {
66
// await CryptoJSW.MD5.loadWasm();
77
const rstMD5 = CryptoJSW.MD5('message').toString();
8-
console.log('rstMD5:',rstMD5);
8+
console.log('rstMD5:', rstMD5);
99
console.log('执行了分类获取')
1010
return [
1111
{type_id: '1', type_name: '电影'},
@@ -20,8 +20,12 @@ var rule = {
2020
await local.set(rule.title, 'cookie', 'qwer1234')
2121

2222
},
23-
推荐: async () => {
24-
console.log('执行了推荐函数')
23+
推荐: async function (...args) {
24+
console.log('执行了推荐函数');
25+
// log(typeof (getProxyUrl));
26+
// log(getProxyUrl());
27+
let {getProxyUrl} = this;
28+
log(getProxyUrl());
2529
console.log(typeof (jsp))
2630
console.log(typeof (pdfh))
2731
console.log('pako:', typeof (pako))
@@ -35,7 +39,12 @@ var rule = {
3539
// console.log(template.getMubans())
3640
console.log(typeof template.getMubans)
3741
return [
38-
{vod_name: '测试电影1', vod_pic: '1.png', vod_remarks: '测试描述1', vod_id: 'http://www.1.com'},
42+
{
43+
vod_name: '测试电影1',
44+
vod_pic: '1.png',
45+
vod_remarks: '测试描述1',
46+
vod_id: getProxyUrl() + '&url=' + 'https://hls09.cntv.myhwcdn.cn/asp/hls/2000/0303000a/3/default/d9b0eaa065934f25abd193d391f731b6/2000.m3u8'
47+
},
3948
{vod_name: '测试电影2', vod_pic: '2.png', vod_remarks: '测试描述2', vod_id: 'http://www.2.com'},
4049
]
4150
},
@@ -61,4 +70,13 @@ var rule = {
6170
lazy: async () => {
6271
return template.getMubans()
6372
},
73+
proxy_rule: async function (params) {
74+
// log(this);
75+
let {input, MY_URL} = this;
76+
log(`params:`, params);
77+
log(`input:${input}`);
78+
log(`MY_URL:${MY_URL}`);
79+
// return [404, 'text/plain', 'Not Found']
80+
return [302, 'text/html', '', {location: input || 'http://www.baidu.com'}]
81+
}
6482
};

0 commit comments

Comments
 (0)