Skip to content

Commit 288af1e

Browse files
author
Taois
committed
feat: 新增优雅改版的webdav
1 parent e7e4001 commit 288af1e

File tree

3 files changed

+283
-1
lines changed

3 files changed

+283
-1
lines changed

config/map.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
webdav[盘]@@?render=1&type=url&params=../json/webdav.json@@WebDav[盘]
2+
webdav影视[盘]@@?render=1&type=url&params=../json/webdav.json@@WebDav影视[盘]
23
ftp[盘]@@?render=1&type=url&params=../json/ftp.json@@FTP[盘]
34
哔哩收藏[官]@@?render=1&type=url&params=../json/哔哩收藏.json@@哔哩收藏[官]
45
我的哔哩[官]@@?render=1&type=url&params=../json/哔哩教育.json@@哔哩教育[官]

spider/js/webdav[盘].js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,14 @@ var rule = {
5858
url: webdavProxyUrl + input
5959
}
6060
},
61+
action: async function (action, value) {
62+
if (action === 'only_params') {
63+
return '这是个传参源哦'
64+
}
65+
return `未定义动作:${action}`
66+
},
6167
推荐: async function () {
62-
let {input, pdfa, pdfh, pd,publicUrl} = this;
68+
let {input, pdfa, pdfh, pd, publicUrl} = this;
6369
let vod_pic = urljoin(publicUrl, './images/icon_common/网盘.png');
6470
let d = [];
6571
if (!rule.pans || rule.pans.length < 1) {

spider/js/webdav影视[盘].js

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
/*
2+
@header({
3+
searchable: 0,
4+
filterable: 0,
5+
quickSearch: 0,
6+
title: 'webdav影视[盘]',
7+
'类型': '影视',
8+
lang: 'ds',
9+
style: {
10+
type: 'list',
11+
ratio: 1.433
12+
}
13+
})
14+
*/
15+
16+
var rule = {
17+
类型: '影视',
18+
title: 'webdav[盘]',
19+
host: '',
20+
url: '',
21+
searchUrl: '',
22+
headers: {'User-Agent': 'UC_UA'},
23+
searchable: 0,
24+
quickSearch: 0,
25+
filterable: 0,
26+
double: true,
27+
play_parse: true,
28+
limit: 6,
29+
class_name: '',
30+
class_url: '',
31+
pans: [],
32+
style: {"type": "list", "ratio": 1.433},
33+
// 推荐样式
34+
hikerListCol: 'icon_round_2',
35+
// 分类列表样式
36+
hikerClassListCol: 'avatar',
37+
hostJs: async function () {
38+
let {HOST} = this;
39+
return rule.params;
40+
},
41+
预处理: async function () {
42+
log('rule.host:', rule.host);
43+
let data = await request(rule.host);
44+
try {
45+
rule.pans = JSON.parse(data);
46+
} catch (e) {
47+
log('获取webdav配置错误:', e.message);
48+
}
49+
},
50+
class_parse: async function () {
51+
let {input, pdfa, pdfh, pd} = this;
52+
let classList = [];
53+
rule.pans.forEach(pan => {
54+
classList.push({
55+
type_name: pan.name,
56+
type_id: pan.id || pan.baseURL,
57+
})
58+
})
59+
60+
let filters = [{
61+
'key': 'order',
62+
'name': '排序',
63+
'value': [{'n': '名称⬆️', 'v': 'vod_name_asc'}, {'n': '名称⬇️', 'v': 'vod_name_desc'},
64+
{'n': '中英⬆️', 'v': 'vod_cn_asc'}, {'n': '中英⬇️', 'v': 'vod_cn_desc'},
65+
{'n': '时间⬆️', 'v': 'vod_time_asc'}, {'n': '时间⬇️', 'v': 'vod_time_desc'},
66+
{'n': '大小⬆️', 'v': 'vod_size_asc'}, {'n': '大小⬇️', 'v': 'vod_size_desc'}, {'n': '无', 'v': 'none'}]
67+
},
68+
{'key': 'show', 'name': '播放展示', 'value': [{'n': '单集', 'v': 'single'}, {'n': '全集', 'v': 'all'}]}
69+
];
70+
71+
let filter_dict = {};
72+
classList.forEach(it => {
73+
filter_dict[it.type_id] = filters;
74+
});
75+
76+
return {class: classList, filters: filter_dict}
77+
},
78+
lazy: async function () {
79+
let {input, webdavProxyUrl} = this;
80+
console.log(`✅webdavProxyUrl的结果:', ${webdavProxyUrl}`);
81+
return {
82+
parse: 0,
83+
url: webdavProxyUrl + input
84+
}
85+
},
86+
action: async function (action, value) {
87+
if (action === 'only_params') {
88+
return '这是个传参源哦'
89+
}
90+
return `未定义动作:${action}`
91+
},
92+
推荐: async function () {
93+
let {input, pdfa, pdfh, pd, publicUrl} = this;
94+
let vod_pic = urljoin(publicUrl, './images/icon_common/网盘.png');
95+
let d = [];
96+
if (!rule.pans || rule.pans.length < 1) {
97+
d.push({
98+
vod_id: 'only_params',
99+
vod_pic: vod_pic,
100+
vod_name: '这是个传参源哦',
101+
vod_tag: 'action',
102+
})
103+
}
104+
return d
105+
},
106+
107+
一级: async function (tid, pg, filter, extend) {
108+
let d = [];
109+
if (Number(pg) > 1) {
110+
return d
111+
}
112+
const _id = tid.split('$')[0];
113+
const _tid = tid.split('$')[1] || '/';
114+
let pan = rule.pans.find(it => it.id === _id || it.baseURL === _id);
115+
if (pan) {
116+
const webdav = createWebDAVClient(pan);
117+
const isConnected = await webdav.testConnection();
118+
if (isConnected) {
119+
const rootItems = await webdav.listDirectory(_tid);
120+
console.log('Root directory contents:');
121+
122+
// 排除的文件扩展名列表
123+
const excludeExts = [
124+
// 文档文件
125+
'nfo', 'txt', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
126+
// 图片文件
127+
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'ico', 'svg',
128+
// 压缩文件
129+
'zip', 'rar', '7z', 'tar', 'gz', 'bz2',
130+
// 程序文件
131+
'exe', 'msi', 'bat', 'cmd', 'sh', 'dmg', 'pkg',
132+
// 配置文件
133+
'ini', 'cfg', 'conf', 'config', 'xml', 'json', 'yml', 'yaml',
134+
// 其他文件
135+
'url', 'lnk', 'torrent', 'md', 'log', 'db', 'sqlite'
136+
];
137+
138+
const excludePattern = new RegExp(`\\.(${excludeExts.join('|')})$`, 'i');
139+
140+
// 音视频文件扩展名
141+
const mediaExts = [
142+
'mp4', 'mkv', 'avi', 'ts', 'mov', 'wmv', 'flv', 'webm', 'm4v', '3gp',
143+
'mp3', 'wav', 'flac', 'aac', 'wma', 'm4a', 'ogg', 'ape', 'dts'
144+
];
145+
const mediaPattern = new RegExp(`\\.(${mediaExts.join('|')})$`, 'i');
146+
147+
rootItems.forEach(item => {
148+
log(item);
149+
150+
// 当 showAll 为 false 时,排除不需要的文件类型
151+
if (pan.showAll === false && !item.isDirectory) {
152+
// 排除非音视频文件
153+
if (excludePattern.test(item.name)) {
154+
return; // 跳过这些文件
155+
}
156+
}
157+
158+
const type = item.isDirectory ? 'folder' : 'file';
159+
const size = item.isDirectory ? '' : `${(item.size / (1024 * 1024)).toFixed(2)} MB`;
160+
const content = item.isDirectory ? '' : `${item.contentType}`;
161+
162+
// 根据文件类型设置图标
163+
let vod_pic = 'https://mpimg.cn/view.php/9f684b4c4d80cb4b31d3dfade4b34612.png'; // 默认文件夹图标
164+
165+
if (!item.isDirectory) {
166+
if (mediaPattern.test(item.name)) {
167+
// 音视频和图片文件使用媒体图标
168+
vod_pic = 'https://mpimg.cn/view.php/41a0fdeb398939242397a3a467567337.png';
169+
} else {
170+
// 其他文件使用默认文件图标
171+
vod_pic = 'https://mpimg.cn/view.php/9f684b4c4d80cb4b31d3dfade4b34612.png';
172+
}
173+
}
174+
175+
d.push({
176+
vod_name: item.name,
177+
vod_remarks: size,
178+
vod_tag: type,
179+
vod_id: _id + '$' + item.path,
180+
vod_pic: vod_pic,
181+
vod_content: content,
182+
})
183+
});
184+
185+
let fl = filter ? extend : {};
186+
if (fl.order) {
187+
let key = fl.order.split('_').slice(0, -1).join('_');
188+
let order = fl.order.split('_').slice(-1)[0];
189+
console.log(`排序key:${key},排序order:${order}`);
190+
191+
if (key.includes('name')) {
192+
d = sortListByName(d, key, order);
193+
} else if (key.includes('time')) {
194+
d = sortListByTime(d, key, order);
195+
} else if (key.includes('size')) {
196+
d = sortListBySize(d, key, order);
197+
}
198+
}
199+
}
200+
}
201+
return d
202+
},
203+
204+
二级: async function (ids) {
205+
let VOD = {};
206+
let tid = ids[0];
207+
const _id = tid.split('$')[0];
208+
const _tid = tid.split('$')[1] || '/';
209+
let pan = rule.pans.find(it => it.id === _id || it.baseURL === _id);
210+
if (pan) {
211+
const webdav = createWebDAVClient(pan);
212+
const isConnected = await webdav.testConnection();
213+
if (isConnected) {
214+
const itemInfo = await webdav.getInfo(_tid);
215+
VOD.vod_name = itemInfo.name;
216+
VOD.vod_content = itemInfo.path + '\n' + '上次修改时间:' + itemInfo.lastModified;
217+
VOD.vod_remarks = itemInfo.size;
218+
VOD.vod_director = itemInfo.etag;
219+
VOD.vod_actor = itemInfo.contentType;
220+
VOD.vod_pic = '/default-poster.svg';
221+
VOD.vod_play_from = '在线观看';
222+
const proxy_params_url = `file?config=${encodeURIComponent(JSON.stringify(pan))}&path=${encodeURIComponent(_tid)}`;
223+
VOD.vod_play_url = itemInfo.name + '$' + proxy_params_url;
224+
}
225+
}
226+
return VOD
227+
},
228+
229+
搜索: async function () {
230+
let {input, pdfa, pdfh, pd} = this;
231+
let d = [];
232+
return setResult(d)
233+
}
234+
}
235+
236+
// 排序函数(移到 rule 对象外部)
237+
const sortListByName = (vodList, key, order) => {
238+
if (!key) return vodList;
239+
order = order || 'asc';
240+
return vodList.sort((a, b) => {
241+
const nameA = a[key].toLowerCase();
242+
const nameB = b[key].toLowerCase();
243+
if (order === 'asc') {
244+
return nameA.localeCompare(nameB);
245+
} else {
246+
return nameB.localeCompare(nameA);
247+
}
248+
});
249+
};
250+
251+
const sortListByTime = (vodList, key, order) => {
252+
if (!key) return vodList;
253+
let ASCarr = vodList.sort((a, b) => {
254+
const timeA = new Date(a.vod_content.split('上次修改时间:')[1] || 0);
255+
const timeB = new Date(b.vod_content.split('上次修改时间:')[1] || 0);
256+
return timeA - timeB;
257+
});
258+
if (order === 'desc') {
259+
ASCarr.reverse();
260+
}
261+
return ASCarr;
262+
};
263+
264+
const sortListBySize = (vodList, key, order) => {
265+
if (!key) return vodList;
266+
let ASCarr = vodList.sort((a, b) => {
267+
const sizeA = parseInt(a.vod_remarks) || 0;
268+
const sizeB = parseInt(b.vod_remarks) || 0;
269+
return sizeA - sizeB;
270+
});
271+
if (order === 'desc') {
272+
ASCarr.reverse();
273+
}
274+
return ASCarr;
275+
};

0 commit comments

Comments
 (0)