Files
tvbox_collect/dr/vod/supjav.js
T
2026-06-29 03:41:14 +00:00

222 lines
7.2 KiB
JavaScript

/**
* SupJav 爬虫
* 作者:deepseek
* 版本:1.0
* 最后更新:2025-12-17
* 发布页 https://supjav.com/zh
*/
const baseUrl = 'https://supjav.com/zh';
/**
* 初始化配置
*/
async function init(cfg) {
return {
webview: {
debug: true, // 是否开启调试模式
showWebView: false, // 默认不显示
widthPercent: 80, // 窗口宽度百分比
heightPercent: 40, // 窗口高度百分比
keyword: '', // 页面不存在该关键字时显示webview
returnType: 'dom', // 返回DOM对象
timeout: 30, // 超时时间(秒)
blockImages: false, // 是否禁止加载图片
enableJavaScript: true, // 是否启用JS
header: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
'Referer': baseUrl + '/',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
}
}
};
}
/**
* 首页分类
*/
async function homeContent(filter) {
return {
class: [
{ type_id: "popular", type_name: "热门" },
{ type_id: "category/censored-jav", type_name: "有码" },
{ type_id: "category/uncensored-jav", type_name: "无码" },
{ type_id: "category/amateur", type_name: "素人" },
{ type_id: "category/chinese-subtitles", type_name: "中文字幕" },
{ type_id: "category/english-subtitles", type_name: "英文字幕" },
{ type_id: "category/reducing-mosaic", type_name: "无码破解" }
]
};
}
/**
* 首页推荐视频
*/
async function homeVideoContent() {
const document = await Java.wvOpen(baseUrl + '/');
const videos = parseVideoList(document);
return { list: videos };
}
/**
* 分类内容
*/
async function categoryContent(tid, pg, filter, extend) {
const pgSuffix = (pg === 1 ? '' : `/page/${pg}`);
const document = await Java.wvOpen(`${baseUrl}/${tid}${pgSuffix}`);
const videos = parseVideoList(document);
return { code: 1, msg: "数据列表", list: videos, page: pg, pagecount: 10000, limit: 24, total: 240000 };
}
/**
* 详情页
*/
async function detailContent(ids) {
const document = await Java.wvOpen(ids[0]);
const list = parseDetailPage(document, ids[0]);
return list;
}
/**
* 搜索
*/
async function searchContent(key, quick, pg) {
// 暂未实现搜索逻辑
return { list: [] };
}
/**
* 播放器
*/
async function playerContent(flag, id, vipFlags) {
const ids = id.split('---');
Java.showWebView();
return {
type: 'sniff', // 必填,标识嗅探模式
url: ids[1], // 必填,要加载的播放页面 URL
keyword: '.m3u8|.mp4', // 可选,嗅探关键字,多个用 | 分隔
script: `
(function(){
setTimeout(() => {
document.querySelectorAll('.btn-server').forEach(btn => {
if(btn.textContent.trim() === '${ids[0]}') {
btn.click();
console.log('已点击服务器: ${ids[0]}');
}
});
setTimeout(() => {
document.querySelector("#a > div.spin").click();
console.log('已点击播放按钮');
}, 3000);
}, 500);
})();
`,
timeout: 15 // 可选,嗅探超时时间(秒),默认 15
};
}
/**
* action
*/
async function action(actionStr) {
try {
const params = JSON.parse(actionStr);
console.log("action params:", params);
} catch (e) {
console.log("action is not JSON, treat as string");
}
return { list: [] };
}
/* ---------------- 工具函数 ---------------- */
/**
* 提取视频列表
*/
function parseVideoList(document) {
const posts = document.querySelectorAll('.post');
return Array.from(posts).map(post => {
const titleLink = post.querySelector('h3 a');
const vod_name = titleLink?.getAttribute('title') || titleLink?.textContent || '';
const vod_id = titleLink?.getAttribute('href') || '';
const img = post.querySelector('img');
const vod_pic = img?.getAttribute('data-original') || img?.getAttribute('src') || '';
const meta = post.querySelector('.meta');
let vod_remarks = '';
if (meta) {
const metaText = meta.textContent || '';
const viewsMatch = metaText.match(/(\d+)\s*Views/);
if (viewsMatch) {
vod_remarks = `${viewsMatch[1]}次浏览`;
} else {
const chineseMatch = metaText.match(/(\d+)\s*次浏览/);
vod_remarks = chineseMatch ? `${chineseMatch[1]}次浏览` : '';
}
}
return { vod_id, vod_name, vod_pic, vod_remarks };
});
}
/**
* 解析详情页
*/
function parseDetailPage(doc, id) {
const title = doc.querySelector('.archive-title h1')?.textContent?.trim() || '';
const vod_pic = doc.querySelector('.post-meta .img')?.src || '';
const viewsText = doc.querySelector('.dz_view .views')?.textContent || '';
const vod_remarks = viewsText.replace(/[^0-9]/g, '') || '0';
const tagElements = doc.querySelectorAll('.tags a');
const vod_actor = Array.from(tagElements).map(tag => tag.textContent.trim()).join(',');
let vod_director = '';
const catElements = doc.querySelectorAll('.cats p, .cats span, .cats a');
for (let el of catElements) {
if (el.textContent.includes('Maker')) {
if (el.nextElementSibling?.tagName === 'A') {
vod_director = el.nextElementSibling.textContent.trim();
break;
}
const linkInParent = el.querySelector('a');
if (linkInParent) {
vod_director = linkInParent.textContent.trim();
break;
}
}
}
const vod_content = doc.querySelector('.post-content')?.textContent?.trim() || '';
const serverButtons = doc.querySelectorAll('.btnst .btn-server');
const playItems = Array.from(serverButtons).map(btn => {
const serverName = btn.textContent.trim();
const dataLink = btn.getAttribute('data-link');
return serverName && dataLink ? `${serverName}$${serverName}---${id}` : '';
}).filter(Boolean);
const vod_play_url = playItems.join('#') || '';
const vod = {
code: 1,
msg: "数据列表",
page: 1,
pagecount: 1,
limit: 1,
total: 1,
list: [{
vod_id: id || 'unknown_id',
vod_name: title,
vod_pic: vod_pic,
vod_remarks: vod_remarks,
vod_director: vod_director,
vod_actor: vod_actor,
vod_content: vod_content,
vod_play_from: 'SERVER',
vod_play_url: vod_play_url
}]
};
// console.log(vod);
return vod;
}
/* ---------------- 导出对象 ---------------- */
const spider = { init, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent, action };
spider;