Skip to content

Commit c34271d

Browse files
author
Taois
committed
feat: 发布新版本
1 parent 927c9cd commit c34271d

File tree

9 files changed

+952
-1
lines changed

9 files changed

+952
-1
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ nodejs作为服务端的drpy实现。全面升级异步写法
3838

3939
## 更新记录
4040

41+
### 20250907
42+
43+
更新至V1.2.26
44+
4145
### 20250906
4246

4347
更新至V1.2.25

docs/updateRecord.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# drpyS更新记录
22

3+
### 20250907
4+
5+
更新至V1.2.26
6+
7+
1. 从源动力进货,顺带改个版本号,源动力域名已更换,点此访问[源动力](https://tvshare.cn/)
8+
2. 优化通用网页脚本(油猴插件)
9+
10+
已知Bug: 没重启的情况下直接丢js文件进去,可能会产生文件头处理bug,被清空文件只剩下头
11+
本次更新没提升进度
12+
313
### 20250905
414

515
更新至V1.2.25

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "drpy-node",
3-
"version": "1.2.25",
3+
"version": "1.2.26",
44
"main": "index.js",
55
"type": "module",
66
"scripts": {

public/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ <h3 id="插件应用列表">插件应用列表</h3>
4040
<li><a href="/cat/index.html">在线猫ds源主页</a></li>
4141
</ul>
4242
<h2 id="更新记录">更新记录</h2>
43+
<h3 id="20250907">20250907</h3>
44+
<p>更新至V1.2.26</p>
4345
<h3 id="20250906">20250906</h3>
4446
<p>更新至V1.2.25</p>
4547
<h3 id="20250903">20250903</h3>

spider/js/七猫短剧.js

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
@header({
3+
searchable: 1,
4+
filterable: 1,
5+
quickSearch: 0,
6+
title: '七猫短剧',
7+
'类型': '影视',
8+
lang: 'ds'
9+
})
10+
*/
11+
12+
const h_ost = 'https://api-store.qmplaylet.com';
13+
const h_ost1 = 'https://api-read.qmplaylet.com';
14+
const keys = 'd3dGiJc651gSQ8w1';
15+
const char_map = {
16+
'+': 'P', '/': 'X', '0': 'M', '1': 'U', '2': 'l', '3': 'E', '4': 'r', '5': 'Y', '6': 'W', '7': 'b', '8': 'd', '9': 'J',
17+
'A': '9', 'B': 's', 'C': 'a', 'D': 'I', 'E': '0', 'F': 'o', 'G': 'y', 'H': '_', 'I': 'H', 'J': 'G', 'K': 'i', 'L': 't',
18+
'M': 'g', 'N': 'N', 'O': 'A', 'P': '8', 'Q': 'F', 'R': 'k', 'S': '3', 'T': 'h', 'U': 'f', 'V': 'R', 'W': 'q', 'X': 'C',
19+
'Y': '4', 'Z': 'p', 'a': 'm', 'b': 'B', 'c': 'O', 'd': 'u', 'e': 'c', 'f': '6', 'g': 'K', 'h': 'x', 'i': '5', 'j': 'T',
20+
'k': '-', 'l': '2', 'm': 'z', 'n': 'S', 'o': 'Z', 'p': '1', 'q': 'V', 'r': 'v', 's': 'j', 't': 'Q', 'u': '7', 'v': 'D',
21+
'w': 'w', 'x': 'n', 'y': 'L', 'z': 'e'
22+
};
23+
24+
// 公共函数:获取请求头配置(减少重复代码)
25+
async function getCommonRequestOptions(ruleHeaders) {
26+
let formDatas = await getHeaderX();
27+
// 合并公共请求头与规则中的请求头
28+
let headers = { ...formDatas, ...ruleHeaders };
29+
return { method: 'GET', headers };
30+
}
31+
32+
async function getQmParamsAndSign() {
33+
try {
34+
let sessionId = Math.floor(Date.now()).toString(); // 确保无小数点,纯整数字符串
35+
let data = {
36+
"static_score": "0.8", "uuid": "00000000-7fc7-08dc-0000-000000000000",
37+
"device-id": "20250220125449b9b8cac84c2dd3d035c9052a2572f7dd0122edde3cc42a70",
38+
"mac": "", "sourceuid": "aa7de295aad621a6", "refresh-type": "0", "model": "22021211RC",
39+
"wlb-imei": "", "client-id": "aa7de295aad621a6", "brand": "Redmi", "oaid": "",
40+
"oaid-no-cache": "", "sys-ver": "12", "trusted-id": "", "phone-level": "H",
41+
"imei": "", "wlb-uid": "aa7de295aad621a6", "session-id": sessionId // 动态参数对齐
42+
};
43+
let jsonStr = JSON.stringify(data, null, 0); // 禁用缩进,确保无空格
44+
console.log('[调试] JSON序列化结果:', jsonStr);
45+
// 2.3 Base64编码:对齐Python base64.b64encode(处理UTF-8字符)
46+
let utf8Encoded = encodeURIComponent(jsonStr); // 转UTF-8编码
47+
let base64Str = btoa(unescape(utf8Encoded)); // 对齐Python b64encode
48+
console.log('[调试] Base64编码结果:', base64Str); // 调试:对比Python的encoded
49+
// 2.4 字符映射:逐字符替换,确保无遗漏
50+
let qmParams = '';
51+
for (let c of base64Str) {
52+
qmParams += char_map[c] || c;
53+
}
54+
console.log('[调试] qm-params结果:', qmParams);
55+
// 2.5 签名参数拼接:
56+
let paramsStr = `AUTHORIZATION=app-version=10001application-id=com.duoduo.readchannel=unknownis-white=net-env=5platform=androidqm-params=${qmParams}reg=${keys}`;
57+
console.log('[调试] 签名原始字符串:', paramsStr);
58+
// 2.6 计算MD5签名
59+
let sign = await md5(paramsStr);
60+
console.log('[调试] 生成的sign:', sign);
61+
return { qmParams, sign };
62+
} catch (e) {
63+
console.error('[错误] qm-params/sign生成失败:', e);
64+
throw e; // 抛出错误,避免传递无效参数
65+
}
66+
}
67+
68+
async function getHeaderX() {
69+
let { qmParams, sign } = await getQmParamsAndSign();
70+
return {
71+
'net-env': '5', 'reg': '', 'channel': 'unknown', 'is-white': '', 'platform': 'android',
72+
'application-id': 'com.duoduo.read', 'authorization': '', 'app-version': '10001',
73+
'user-agent': 'webviewversion/0', 'qm-params': qmParams, // 确保键名正确
74+
'sign': sign // 确保键名正确
75+
};
76+
}
77+
78+
var rule = {
79+
title: '七猫短剧',
80+
host: h_ost,
81+
homeUrl: '/api/v1/playlet/index?tag_id=0&playlet_privacy=1&operation=1',
82+
searchUrl: '/api/v1/playlet/search?keyword=fykey&page=fypage',
83+
url: '/api/v1/playlet/index?tag_id=fyclass&page=fypage',
84+
headers: {
85+
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
86+
},
87+
timeout: 5000,
88+
filterable: 1,
89+
limit: 90,
90+
multi: 1,
91+
searchable: 1,
92+
play_parse: true,
93+
search_match: true,
94+
95+
class_parse: async function() {
96+
let signString = `operation=1playlet_privacy=1tag_id=0${keys}`;
97+
let apiSign = md5(signString);
98+
let url = `${h_ost}/api/v1/playlet/index?tag_id=0&playlet_privacy=1&operation=1&sign=${apiSign}`;
99+
100+
// 调用公共函数获取请求配置
101+
let options = await getCommonRequestOptions(rule.headers);
102+
let html = await request(url, options);
103+
let data = JSON.parse(html);
104+
105+
let classList = [];
106+
let duoxuan = ['0', '1', '2', '3', '4']; // 分类筛选维度
107+
for (let duo of duoxuan) {
108+
let tags = data?.data?.tag_categories?.[Number(duo)]?.tags || [];
109+
for (let vod of tags) {
110+
classList.push({
111+
type_id: String(vod.tag_id),
112+
type_name: vod.tag_name || ''
113+
});
114+
}
115+
}
116+
return { class: classList, filters: {} };
117+
},
118+
119+
一级: async function() {
120+
let { MY_CATE, MY_PAGE } = this;
121+
let cid = MY_CATE || 0;
122+
let page = MY_PAGE || 1;
123+
let signString;
124+
125+
if (page === 1) {
126+
signString = `operation=1playlet_privacy=1tag_id=${cid}${keys}`;
127+
} else {
128+
signString = `next_id=${page}operation=1playlet_privacy=1tag_id=${cid}${keys}`;
129+
}
130+
let sign = md5(signString);
131+
console.log('[调试] 一级列表sign:', sign);
132+
133+
// 构造分页URL
134+
let url = page === 1 ?
135+
`${h_ost}/api/v1/playlet/index?tag_id=${cid}&playlet_privacy=1&operation=1&sign=${sign}` :
136+
`${h_ost}/api/v1/playlet/index?tag_id=${cid}&next_id=${page}&playlet_privacy=1&operation=1&sign=${sign}`;
137+
138+
// 调用公共函数获取请求配置
139+
let options = await getCommonRequestOptions(rule.headers);
140+
let html = await request(url, options);
141+
let data = JSON.parse(html);
142+
let videoList = data?.data?.list || [];
143+
144+
let videos = videoList.map(vod => ({
145+
title: vod.title || '未知标题',
146+
img: vod.image_link || '',
147+
desc: `${vod.tags} ${vod.total_episode_num}${vod.hot_value}`,
148+
url: encodeURIComponent(vod.playlet_id)
149+
}));
150+
return setResult(videos);
151+
},
152+
153+
二级: async function() {
154+
let { orId } = this;
155+
let did = decodeURIComponent(orId);
156+
let signString = `playlet_id=${did}${keys}`;
157+
let sign = md5(signString);
158+
console.log('[调试] 详情接口sign:', sign);
159+
160+
let detailUrl = `${h_ost1}/player/api/v1/playlet/info?playlet_id=${did}&sign=${sign}`;
161+
// 调用公共函数获取请求配置
162+
let options = await getCommonRequestOptions(rule.headers);
163+
let html = await request(detailUrl, options);
164+
165+
let data = JSON.parse(html).data;
166+
// 构造播放地址列表:排序$地址拼接
167+
let play_url = data.play_list.map(it => `${it.sort}$${it.video_url}`).join('#');
168+
return {
169+
vod_name: data.title || "未知标题",
170+
vod_pic: data.image_link || "未知图片",
171+
vod_actor: "",
172+
vod_remarks: `${data.tags} ${data.total_episode_num}集`,
173+
vod_content: `${data.intro}` || "未知剧情",
174+
vod_play_from: '七猫短剧',
175+
vod_play_url: play_url
176+
};
177+
},
178+
179+
搜索: async function() {
180+
let { KEY, MY_PAGE } = this;
181+
let page = MY_PAGE || 1;
182+
let d = [];
183+
let trackId = 'ec1280db127955061754851657967';
184+
185+
let signString = `extend=page=${page}read_preference=0track_id=${trackId}wd=${KEY}${keys}`;
186+
let sign = md5(signString);
187+
console.log('[调试] 搜索接口sign:', sign);
188+
let encodedKey = encodeURIComponent(KEY);
189+
let url = `${h_ost}/api/v1/playlet/search?extend=&page=${page}&wd=${encodedKey}&read_preference=0&track_id=${trackId}&sign=${sign}`;
190+
191+
// 调用公共函数获取请求配置
192+
let options = await getCommonRequestOptions(rule.headers);
193+
let html = await request(url, options);
194+
195+
let data = JSON.parse(html);
196+
let videoList = data?.data?.list || [];
197+
videoList.forEach((vod) => {
198+
let cleanTitle = (vod.title || '').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();
199+
200+
if (rule.search_match && !new RegExp(KEY, "i").test(cleanTitle)) {
201+
console.log(`[调试] 排除不符合搜索关键词的名称: ${cleanTitle}`);
202+
return;
203+
}
204+
205+
d.push({
206+
title: cleanTitle,
207+
img: vod.image_link || '',
208+
desc: `${vod.total_num}`,
209+
url: encodeURIComponent(vod.id)
210+
});
211+
});
212+
213+
return setResult(d);
214+
},
215+
216+
lazy: async function() {
217+
let { input } = this;
218+
console.log('[调试] 播放地址:', input);
219+
return { parse: 0, url: input };
220+
}
221+
};

0 commit comments

Comments
 (0)