"番茄短剧"
"https://www.shanhuzs.com/"
zpccool (13551) 16小时前 下载:306
视频
"感谢作者大大"
// @name "番茄短剧"
// @uuid "fanqieduanju"
// @version 1.0.0
// @updateUrl http://aliyun.18638642193.cn/api/sources/user:a65fc492-08a0-44f7-a052-b9836fe7318d/download
// @author AI
// @url "https://www.shanhuzs.com/"
// @enabled true
// @description "感谢作者大大"
// @group "影视 书源"
// @type video
var BASE_URL = "https://www.shanhuzs.com/";
function absoluteUrl(u) {
if (!u) return "";
if (/^https?:\/\//i.test(u)) return u;
if (u[0] === '/') u = u.substring(1);
return BASE_URL.replace(/\/$/, '') + '/' + u;
}
// ==================== 原书源规则(供手动适配) ====================
// searchUrl : "/fqsansc/{{key}}----------{{page}}---.html"
// search.bookList : "class.col8"
// search.name : "h4@a@text"
// search.author : ""
// search.coverUrl : "img@data-original"
// search.bookUrl : "h4@a@href"
// info.* : "{\"kind\": \".tag@a@text\"}"
// toc.* : "{\"chapterList\": \"a[href^=\\\"/fqsanpy/\\\"]\", \"chapterName\": \"text\", \"chapterUrl\": \"href\"}"
// content.* : "{\"content\": \"##\\\"url\\\":\\\"(.*)\\\",\\\"url_next\\\"##$1###@js:\\nif(book.durChapterIndex==chapter.index){\\n\\t\\tjava.startBrowser(result.replace(/\\\\\\\\/g,''),title)\\n\\t\\tjava.toast('正在加载视频\\\\n视频加载较慢,请耐心等待')\\n\\t}\\n'【刷新正文】播放\\\\n✅直链:\\\\n'+result\", \"replaceRegex\": \"##\\\\\"}"
// explore.* : "{}"
// ================================================================
async function search(keyword, page) {
const url = BASE_URL + '/fqsansc/' + encodeURIComponent(keyword) + '----------' + page + '---.html';
const resp = await legado.http.get(url);
const doc = legado.dom.parse(resp);
const items = [];
const listItems = legado.dom.selectAll(doc, '.shoutu-vodlist li.col8');
for (var i = 0; i < listItems.length; i++) {
var item = listItems[i];
var titleEl = legado.dom.select(item, 'h4.title a');
var name = titleEl ? legado.dom.text(titleEl) : '';
var bookUrl = '';
if (titleEl) {
var href = legado.dom.attr(titleEl, 'href');
bookUrl = absoluteUrl(href);
}
var coverUrl = '';
var imgEl = legado.dom.select(item, 'img');
if (imgEl) {
var dataOriginal = legado.dom.attr(imgEl, 'data-original');
coverUrl = absoluteUrl(dataOriginal);
}
if (name && bookUrl) {
items.push({
name: name,
bookUrl: bookUrl,
coverUrl: coverUrl,
author: '',
kind: ''
});
}
}
legado.dom.free(doc);
return items;
}
async function bookInfo(bookUrl) {
const resp = await legado.http.get(bookUrl);
const doc = legado.dom.parse(resp);
var name = '';
var h1El = legado.dom.select(doc, '.shoutu-content h1');
if (h1El) name = legado.dom.text(h1El);
var coverUrl = '';
// 方案1: 尝试从 .cover-img img 获取
var imgEl = legado.dom.select(doc, '.cover-img img');
if (imgEl) {
var dataOriginal = legado.dom.attr(imgEl, 'data-original');
if (!dataOriginal) dataOriginal = legado.dom.attr(imgEl, 'src');
if (dataOriginal) {
coverUrl = absoluteUrl(dataOriginal);
legado.log('方案1获取封面: ' + coverUrl);
}
}
// 方案2: 尝试从 img[data-original*="/upload/vod/"] 获取
if (!coverUrl) {
var vodPicEl = legado.dom.select(doc, 'img[data-original*="/upload/vod/"]');
if (vodPicEl) {
var dataOriginal = legado.dom.attr(vodPicEl, 'data-original');
if (dataOriginal) {
coverUrl = absoluteUrl(dataOriginal);
legado.log('方案2获取封面: ' + coverUrl);
}
}
}
// 方案3: 尝试从所有带有 data-original 属性的 img 获取
if (!coverUrl) {
var allImgEl = legado.dom.select(doc, 'img[data-original]');
if (allImgEl) {
var dataOriginal = legado.dom.attr(allImgEl, 'data-original');
if (dataOriginal) {
coverUrl = absoluteUrl(dataOriginal);
legado.log('方案3获取封面: ' + coverUrl);
}
}
}
// 方案4: 尝试从 mac_history_set 标签中获取
if (!coverUrl) {
var historyEl = legado.dom.select(doc, '.mac_history_set');
if (historyEl) {
var dataPic = legado.dom.attr(historyEl, 'data-pic');
if (dataPic) {
coverUrl = absoluteUrl(dataPic);
legado.log('方案4获取封面: ' + coverUrl);
}
}
}
var kind = '';
var tagEl = legado.dom.select(doc, '.tag a');
if (tagEl) kind = legado.dom.text(tagEl);
var intro = '';
var descEl = legado.dom.select(doc, '.desc');
if (descEl) {
intro = legado.dom.text(descEl).replace('简介:', '').trim();
}
var latestChapter = '';
var textEl = legado.dom.select(doc, '.text');
if (textEl) latestChapter = legado.dom.text(textEl);
legado.dom.free(doc);
legado.log('最终封面URL: ' + coverUrl);
return {
name: name,
author: '',
bookUrl: bookUrl,
tocUrl: bookUrl,
coverUrl: coverUrl,
intro: intro,
latestChapter: latestChapter,
kind: kind
};
}
async function chapterList(tocUrl) {
const resp = await legado.http.get(tocUrl);
const doc = legado.dom.parse(resp);
const chapters = [];
const links = legado.dom.selectAll(doc, '.shoutu-playlist a');
for (var i = 0; i < links.length; i++) {
var link = links[i];
var href = legado.dom.attr(link, 'href');
if (href && href.startsWith('/fqsanpy/')) {
var name = legado.dom.text(link);
var url = absoluteUrl(href);
chapters.push({
name: name,
url: url
});
}
}
legado.dom.free(doc);
return chapters;
}
async function chapterContent(chapterUrl) {
const resp = await legado.http.get(chapterUrl);
// 尝试匹配 player_aaaa 对象中的 url 字段
const match = resp.match(/var player_aaaa=\{[^}]*"url":"([^"]+)"/);
if (match && match[1]) {
let videoUrl = match[1];
// 解码转义的斜杠
videoUrl = videoUrl.replace(/\\\//g, '/');
legado.log('提取到视频地址: ' + videoUrl);
return videoUrl;
}
// 尝试匹配 player_aaaa 对象中的 url 字段(包含换行)
const match2 = resp.match(/var player_aaaa=\{[\s\S]*?"url":"([^"]+)"/);
if (match2 && match2[1]) {
let videoUrl = match2[1];
// 解码转义的斜杠
videoUrl = videoUrl.replace(/\\\//g, '/');
legado.log('提取到视频地址 (多行): ' + videoUrl);
return videoUrl;
}
// 尝试直接匹配 m3u8 地址
const match3 = resp.match(/https:\/\/[^"'\s]+\.m3u8/g);
if (match3 && match3.length > 0) {
let videoUrl = match3[0];
// 解码转义的斜杠
videoUrl = videoUrl.replace(/\\\//g, '/');
legado.log('提取到视频地址 (直接): ' + videoUrl);
return videoUrl;
}
legado.log('未找到视频地址');
return '';
}
async function explore(page, category) {
if (!category || category === "GETALL") {
// 返回分类列表
return ["短剧"];
}
const url = BASE_URL + '/fqsantp/5.html';
const resp = await legado.http.get(url);
const doc = legado.dom.parse(resp);
const items = [];
const listItems = legado.dom.selectAll(doc, '.shoutu-vodlist li.col8');
for (var i = 0; i < listItems.length; i++) {
var item = listItems[i];
var titleEl = legado.dom.select(item, 'h4.title a');
var name = titleEl ? legado.dom.text(titleEl) : '';
var bookUrl = '';
if (titleEl) {
var href = legado.dom.attr(titleEl, 'href');
bookUrl = absoluteUrl(href);
}
var coverUrl = '';
var imgEl = legado.dom.select(item, 'img');
if (imgEl) {
var dataOriginal = legado.dom.attr(imgEl, 'data-original');
coverUrl = absoluteUrl(dataOriginal);
}
if (name && bookUrl) {
items.push({
name: name,
bookUrl: bookUrl,
coverUrl: coverUrl,
author: '',
kind: ''
});
}
}
legado.dom.free(doc);
return items;
}
function categories() {
return [
{ name: '短剧', url: '/fqsantp/5.html' }
];
}
async function TEST(type) {
if (type === '__list__') return ['explore', 'bookInfo', 'chapterList', 'chapterContent', 'search'];
if (type === 'explore') {
var cats = await explore(1, '__invalid__');
if (!cats || cats.length < 1) return { passed: false, message: '分类列表异常' };
var books = await explore(1, cats[0]);
if (!books || books.length < 1) return { passed: false, message: '发现页 [' + cats[0] + '] 返回为空' };
return { passed: true, message: '发现页 [' + cats[0] + ']: ' + books.length + ' 条结果 ✓' };
}
if (type === 'bookInfo') {
var info = await bookInfo('https://www.shanhuzs.com/fqsandt/73059.html');
if (!info || !info.name) return { passed: false, message: 'bookInfo 返回为空' };
return { passed: true, message: 'name=' + info.name + ' ✓' };
}
if (type === 'chapterList') {
var chs = await chapterList('https://www.shanhuzs.com/fqsandt/73059.html');
if (!chs || chs.length < 1) return { passed: false, message: '章节列表为空' };
return { passed: true, message: '共 ' + chs.length + ' 集 ✓' };
}
if (type === 'chapterContent') {
var url = await chapterContent('https://www.shanhuzs.com/fqsanpy/73059-1-1.html');
if (!url) return { passed: false, message: '播放地址为空' };
return { passed: true, message: '播放地址获取成功 ✓' };
}
if (type === 'search') {
var results = await search('系统', 1);
if (!results || results.length < 1) return { passed: false, message: '搜索结果为空' };
return { passed: true, message: '搜索返回 ' + results.length + ' 条结果 ✓' };
}
return { passed: false, message: '未知测试类型: ' + type };
}