Files
tvbox_collect/jaychouqq/yingshi/js2/rou.js
T
2026-06-29 03:41:14 +00:00

164 lines
4.5 KiB
JavaScript

import req from '../../util/req.js';
import { load } from 'cheerio';
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0';
const SITE = 'https://rou.video';
async function request(reqUrl) {
const resp = await req.get(reqUrl, {
headers: {
'User-Agent': UA,
},
});
return resp.data;
}
async function home(_inReq, _outResp) {
let classes = [
{ type_id: 'https://rou.video/v', type_name: '全部' },
{ type_id: 'https://rou.video/t/國產AV', type_name: '國產' },
{ type_id: 'https://rou.video/t/探花', type_name: '探花' },
{ type_id: 'https://rou.video/t/自拍流出', type_name: '自拍' },
{ type_id: 'https://rou.video/t/OnlyFans', type_name: 'OnlyFans' },
{ type_id: 'https://rou.video/t/日本', type_name: '日本' },
];
return {
class: classes,
};
}
async function category(inReq, _outResp) {
const tid = inReq.body.id;
const pg = inReq.body.page;
// const extend = inReq.body.filters;
let page = pg || 1;
if (page == 0) page = 1;
let reqUrl = tid;
if (page > 1) {
reqUrl += `?order=createdAt&page=${page}`;
}
const html = await request(reqUrl);
const $ = load(html);
let videos = [];
$('.grid.grid-cols-2.mb-6 > div').each((_, element) => {
if ($(element).find('.relative').length == 0) return;
const href = $(element).find('.relative a').attr('href');
const vodName = $(element).find('img:last').attr('alt');
const vodPic = $(element).find('img').attr('src');
const subTitle = $(element).find('.relative a > div:eq(1)').text();
const hdinfo = $(element).find('.relative a > div:first').text();
videos.push({
vod_id: SITE + href,
vod_name: vodName,
vod_pic: vodPic,
vod_remarks: subTitle || hdinfo,
});
});
return {
page: page,
pagecount: videos.length < 12 ? page : page + 1,
list: videos,
// filter logic placeholder
filter: [],
};
}
async function detail(inReq, _outResp) {
const id = inReq.body.id;
// 获取播放链接
const html = await request(id, {
headers: {
'User-Agent': UA,
},
});
let playUrl = null;
const evMatch = html.match(/"ev"\s*:\s*(\{[\s\S]*?"d"\s*:\s*"[^"]+"\s*,\s*"k"\s*:\s*\d+[\s\S]*?\})/);
if (evMatch) {
try {
const ev = JSON.parse(evMatch[1]);
const decoded = Buffer.from(ev.d, 'base64');
const bytes = decoded.map((b) => (b - ev.k + 256) % 256);
const evData = JSON.parse(Buffer.from(bytes).toString('utf8'));
playUrl = evData.videoUrl || null;
} catch (_) {
playUrl = null;
}
}
let vod = {
vod_id: id,
vod_name: '',
vod_pic: '',
vod_play_from: '肉视频',
vod_play_url: '播放$' + playUrl,
};
return {
list: [vod],
};
}
async function play(inReq, _outResp) {
const flag = inReq.body.flag;
const id = inReq.body.id;
// 将 .jpg 替换为 .m3u8
const playUrl = id.replace('.jpg', '.m3u8');
return {
parse: 0,
url: playUrl,
header: {
'User-Agent': UA,
},
};
}
async function search(inReq, _outResp) {
const pg = inReq.body.page;
const wd = inReq.body.wd;
let page = pg || 1;
if (page == 0) page = 1;
const text = encodeURIComponent(wd);
const html = await request(`${SITE}/search?q=${text}&t=&page=${page}`);
const $ = load(html);
let videos = [];
$('.grid.grid-cols-2.mb-6 > div').each((_, element) => {
if ($(element).find('.relative').length == 0) return;
const href = $(element).find('.relative a').attr('href');
const vodName = $(element).find('img:last').attr('alt');
const vodPic = $(element).find('img').attr('src');
const subTitle = $(element).find('.relative a > div:eq(1)').text();
const hdinfo = $(element).find('.relative a > div:first').text();
videos.push({
vod_id: SITE + href,
vod_name: vodName,
vod_pic: vodPic,
vod_remarks: subTitle || hdinfo,
});
});
return {
page: page,
pagecount: videos.length < 12 ? page : page + 1,
list: videos,
};
}
export default {
meta: {
key: 'rou',
name: '肉视频',
type: 3,
},
api: async (fastify) => {
fastify.post('/init', async () => ({}));
fastify.post('/home', home);
fastify.post('/category', category);
fastify.post('/detail', detail);
fastify.post('/play', play);
fastify.post('/search', search);
},
};