樱花动漫
https://www.yinhuadm.xyz
zpccool (13551) 2小时前 下载:72
视频
樱花动漫 - 日漫在线观看
// @name 樱花动漫
// @uuid yinhua-dm-xyz
// @version 1.1.0
// @author AI
// @url https://www.yinhuadm.xyz
// @type video
// @enabled true
// @description 樱花动漫 - 日漫在线观看
var BASE = "https://www.yinhuadm.xyz";
var B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function base64decode(str) {
var out = "";
var i = 0;
var len = str.length;
while (i < len) {
var c1 = B64.indexOf(str.charAt(i++));
var c2 = B64.indexOf(str.charAt(i++));
if (c1 === -1 || c2 === -1) break;
out += String.fromCharCode((c1 << 2) | (c2 >> 4));
var c3 = B64.indexOf(str.charAt(i++));
if (c3 === -1) break;
out += String.fromCharCode(((c2 & 15) << 4) | (c3 >> 2));
var c4 = B64.indexOf(str.charAt(i++));
if (c4 === -1) break;
out += String.fromCharCode(((c3 & 3) << 6) | c4);
}
return out;
}
var CATEGORIES = {
追番周表: "week",
今日更新: "new",
热榜: "hot",
新片上线: "newAnime"
};
var TITLE_FILTER = /^(更新至第?\d+集|已?完结|动漫|[Hh][Dd]中字|[Hh][Dd])$/;
function absUrl(href) {
if (!href) return "";
if (href.indexOf("http") === 0) return href;
if (href.charAt(0) === '/') return BASE + href;
return BASE + '/' + href;
}
async function search(keyword, page) {
legado.log("[search] keyword=" + keyword + " page=" + page);
var searchUrl = BASE + '/vch/' + encodeURIComponent(keyword) + '.html';
if (page > 1) searchUrl = BASE + '/vch/' + encodeURIComponent(keyword) + '/page/' + page + '.html';
var id = await legado.browser.create({ visible: false });
await legado.browser.navigate(id, searchUrl, { waitUntil: "networkidle", timeoutSecs: 30 });
var data = await legado.browser.eval(id, "return (function(){" +
"var r=[];" +
"var seen={};" +
"var items=document.querySelectorAll('a[href*=\"/v/\"]');" +
"for(var i=0;i<items.length;i++){" +
" var a=items[i];" +
" var href=a.href;" +
" if(href.indexOf('/v/')===-1)continue;" +
" var title=a.title||a.getAttribute('title')||a.innerText.trim()||'';" +
" if(!title||title.indexOf('http')===0||title.length>=100)continue;" +
" if(" + TITLE_FILTER.toString() + ".test(title))continue;" +
" if(seen[href])continue;" +
" seen[href]=true;" +
" var img=a.querySelector('img')||a.parentNode.querySelector('img');" +
" var cover=img?(img.src||img.getAttribute('data-src')||''):'';" +
" var nextA=items[i+1];" +
" var updateText=nextA?(nextA.innerText.trim()||''):'';" +
" r.push({url:href,title:title,cover:cover,update:updateText});" +
"}" +
"return JSON.stringify(r);" +
"})()");
await legado.browser.close(id);
var books = [];
if (data) {
try {
var items = JSON.parse(data);
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item.url && item.title) {
books.push({
name: item.title.trim(),
bookUrl: absUrl(item.url),
coverUrl: item.cover || "",
latestChapter: item.update || "",
kind: ""
});
}
}
} catch (e) {}
}
return books;
}
async function bookInfo(bookUrl) {
var id = await legado.browser.create({ visible: false });
await legado.browser.navigate(id, bookUrl, { waitUntil: "networkidle", timeoutSecs: 30 });
var name = await legado.browser.eval(id, "return (document.querySelector('h1')||{}).innerText||''");
var coverUrl = await legado.browser.eval(id,
"var img=document.querySelector('.module-item-pic img')||document.querySelector('.module-item-cover img');" +
"return img?(img.src||img.getAttribute('data-original')||img.getAttribute('data-src')||''):'';");
var intro = await legado.browser.eval(id, "return (document.querySelector('.vod_content')||{}).innerText||''");
var remark = await legado.browser.eval(id, "return (document.querySelector('.update')||{}).innerText||''");
await legado.browser.close(id);
return {
name: name.trim(),
author: "",
bookUrl: bookUrl,
coverUrl: coverUrl || "",
intro: intro || "",
latestChapter: remark || "",
tocUrl: bookUrl
};
}
async function chapterList(tocUrl) {
var vidMatch = String(tocUrl).match(/\/v\/(\d+)\.html/);
var vid = vidMatch ? vidMatch[1] : "";
var id = await legado.browser.create({ visible: false });
await legado.browser.navigate(id, tocUrl, { waitUntil: "networkidle", timeoutSecs: 30 });
var vidFilter = vid ? ("href.indexOf('/p/" + vid + "-')===-1") : "false";
var data = await legado.browser.eval(id, "return (function(){" +
"var r=[];" +
"var seen={};" +
"var links=document.querySelectorAll('a[href*=\"/p/\"]');" +
"for(var i=0;i<links.length;i++){" +
" var a=links[i];" +
" var href=a.href;" +
" if(!href||href.indexOf('/p/')===-1)continue;" +
" var match=href.match(/\\/p\\/\\d+-(\\d+)-(\\d+)\\.html/);" +
" if(!match)continue;" +
" if(" + vidFilter + ")continue;" +
" if(seen[href])continue;" +
" seen[href]=true;" +
" var epNum=parseInt(match[2],10);" +
" var lineNum=parseInt(match[1],10);" +
" var epStr=epNum<10?('0'+epNum):(''+epNum);" +
" var name='第'+epStr+'集';" +
" var group='线路'+lineNum;" +
" r.push({name:name,url:href,ep:epNum,line:lineNum,group:group});" +
"}" +
"return JSON.stringify(r);" +
"})()");
await legado.browser.close(id);
var chapters = [];
if (data) {
try {
var items = JSON.parse(data);
items.sort(function(a, b) {
if ((a.line || 0) !== (b.line || 0)) return (a.line || 0) - (b.line || 0);
return (a.ep || 0) - (b.ep || 0);
});
for (var i = 0; i < items.length; i++) {
chapters.push({
name: items[i].name || "第" + (i + 1) + "集",
url: absUrl(items[i].url),
group: items[i].group || ""
});
}
} catch (e) {}
}
return chapters;
}
// ── chapterContent ─────────────────────────────────────
// 流程:
// 1) 加载章节页 → 从 player_aaaa 提取 MCZY 链接
// 2) 导航到播放器页 (player.mcue.cc) → 播放器 JS 自动解密并请求 m3u8
// 3) onRequest + captureBody 拦截 m3u8 响应 → 检查 #EXTM3U → 返回真实地址
async function chapterContent(chapterUrl) {
legado.log("[chapterContent] url=" + chapterUrl);
function startsWithExtM3u(text) {
var value = String(text || "");
if (value.charCodeAt(0) === 0xfeff) value = value.substring(1);
value = value.replace(/^\s+/, "").toUpperCase();
return value.indexOf("#EXTM3U") === 0;
}
function shouldExclude(url, ct) {
var lurl = String(url || "").toLowerCase();
var lct = String(ct || "").toLowerCase();
if (lurl.indexOf("data:") === 0) return true;
if (lurl.indexOf("ipc.localhost") !== -1) return true;
if (lurl.indexOf(".js") !== -1 || lurl.indexOf(".css") !== -1) return true;
if (lurl.indexOf(".png") !== -1 || lurl.indexOf(".jpg") !== -1 ||
lurl.indexOf(".jpeg") !== -1 || lurl.indexOf(".gif") !== -1 ||
lurl.indexOf(".webp") !== -1 || lurl.indexOf(".ico") !== -1 ||
lurl.indexOf(".svg") !== -1 || lurl.indexOf(".woff") !== -1 ||
lurl.indexOf(".ttf") !== -1) return true;
if (lct.indexOf("javascript") !== -1 || lct.indexOf("text/css") !== -1) return true;
if (lct.indexOf("image/") === 0 || lct.indexOf("font/") === 0) return true;
return false;
}
var id = await legado.browser.create({ visible: false, muted: true });
var playUrl = "";
var evtTotal = 0;
legado.browser.onRequest(id, function(evt) {
evtTotal++;
if (playUrl) return;
if (!evt || evt.type !== "response") return;
var url = String(evt.url || "");
var lurl = url.toLowerCase();
var s = evt.status || 0;
if (shouldExclude(url, (evt.responseHeaders && evt.responseHeaders["content-type"]) || "")) return;
if (lurl.indexOf("m3u8") !== -1) {
var responseBody = evt.responseBody || "";
legado.log("[chapterContent] m3u8 resp status=" + s + " len=" + responseBody.length + " url=" + url);
if ((s === 200 || s === 206) && startsWithExtM3u(responseBody)) {
playUrl = url;
legado.log("[chapterContent] m3u8 found: " + url);
}
return;
}
if (s === 200) {
var body = evt.responseBody || "";
if (startsWithExtM3u(body)) {
playUrl = url;
legado.log("[chapterContent] m3u8 found(body): " + url);
}
}
}, { captureBody: true });
// 步骤1:加载章节页,提取 MCZY 链接
await legado.browser.navigate(id, chapterUrl, { waitUntil: "networkidle", timeoutSecs: 30 });
legado.log("[chapterContent] chapter loaded, events=" + evtTotal);
var mczyUrl = "";
// 先看 HTML 里有没有直接的 m3u8
if (!playUrl) {
var html = await legado.browser.html(id);
var htmlStr = String(html || "");
var m3u8Match = htmlStr.match(/https?:\/\/[^\s"'<>]+\.m3u8[^\s"'<>]*/i);
if (m3u8Match) { playUrl = m3u8Match[0]; legado.log("[chapterContent] m3u8 in chapter html"); }
}
// 没直接 m3u8 就提取 player_aaaa → MCZY
if (!playUrl && !mczyUrl) {
try {
var pRaw = await legado.browser.eval(id,
"try{var s=JSON.stringify(player_aaaa||{});return s;}catch(e){return'';}");
if (pRaw && pRaw.length > 5) {
var pd = JSON.parse(pRaw);
if (pd && pd.url) {
var vurl = String(pd.url);
var enc = String(pd.encrypt || "");
if (enc === "1") vurl = unescape(vurl);
else if (enc === "2") vurl = unescape(base64decode(vurl));
mczyUrl = vurl;
legado.log("[chapterContent] MCZY=" + mczyUrl);
}
}
} catch(e) {
legado.log("[chapterContent] player_aaaa parse err: " + e.message);
}
}
// 步骤2:导航到播放器页面,让播放器 JS 解密并请求真实 m3u8
if (!playUrl && mczyUrl) {
var playerPageUrl = "https://player.mcue.cc/yinhua/?url=" + encodeURIComponent(mczyUrl);
legado.log("[chapterContent] navigating to player: " + playerPageUrl);
await legado.browser.navigate(id, playerPageUrl, { waitUntil: "load", timeoutSecs: 30 });
legado.log("[chapterContent] player page loaded, events=" + evtTotal);
// 等待播放器 JS 执行并请求 m3u8(HLS 初始化需要时间)
await legado.sleep(6000);
legado.log("[chapterContent] after wait, events=" + evtTotal + " playUrl=" + (playUrl || "NONE"));
}
// 步骤3:如果还没抓到,用 eval 从 video 元素 / 全局变量获取
if (!playUrl) {
try {
var evalRes = await legado.browser.eval(id,
"(function(){" +
"var v=document.querySelector('video');" +
"if(v){var s=v.src||v.currentSrc||'';if(s.indexOf('http')===0)return s;}" +
"if(typeof config!=='undefined'&&config){return JSON.stringify(config.url||'');}" +
"return'';" +
"})()");
if (evalRes && evalRes.length > 10 && evalRes.indexOf("http") === 0) {
playUrl = evalRes;
legado.log("[chapterContent] eval video/config: " + playUrl);
} else if (evalRes) {
legado.log("[chapterContent] eval raw=" + evalRes);
}
} catch(e3) {
legado.log("[chapterContent] eval err: " + e3.message);
}
}
// 步骤4:如果还是没抓到,从播放器页 HTML 里找
if (!playUrl) {
try {
var pHtml = await legado.browser.html(id);
var m = pHtml.match(/https?:\/\/[^\s"'<>]+\.m3u8[^\s"'<>]*/i);
if (m) { playUrl = m[0]; legado.log("[chapterContent] m3u8 from player html"); }
} catch(e4) {}
}
// 清理
try {
await legado.browser.eval(id,
'try{document.querySelectorAll("video,audio").forEach(function(el){' +
'try{el.pause();el.removeAttribute("src");el.load();}catch(e2){}});}catch(e){}');
} catch(e) {}
await legado.browser.navigate(id, BASE, { waitUntil: "load", timeoutSecs: 10 });
legado.log("[chapterContent] events after backNav=" + evtTotal + " playUrl=" + (playUrl || "NONE"));
legado.browser.offRequest(id);
await legado.browser.close(id);
if (playUrl && playUrl.length > 10) {
legado.log("[chapterContent] result=" + playUrl);
return playUrl;
}
legado.log("[chapterContent] no m3u8 found");
return "";
}
// ── explore ─────────────────────────────────────────────
async function explore(page, category) {
if (category === "GETALL") {
return Object.keys(CATEGORIES);
}
var catKey = CATEGORIES[category] || "new";
var url;
if (catKey === "week") url = BASE + '/label/week.html';
else if (catKey === "new") url = BASE + '/label/new.html';
else if (catKey === "hot") url = BASE + '/label/hot.html';
else url = BASE + '/s/1.html';
if (page > 1) url = url.replace('.html', '/' + page + '.html');
var id = await legado.browser.create({ visible: false });
await legado.browser.navigate(id, url, { waitUntil: "networkidle", timeoutSecs: 30 });
var data = await legado.browser.eval(id, "return (function(){" +
"var r=[];" +
"var seen={};" +
"var items=document.querySelectorAll('a[href*=\"/v/\"]');" +
"for(var i=0;i<items.length;i++){" +
" var a=items[i];" +
" var href=a.href;" +
" if(href.indexOf('/v/')===-1)continue;" +
" var title=a.title||a.getAttribute('title')||a.innerText.trim()||'';" +
" if(!title||title.indexOf('http')===0||title.length>=100)continue;" +
" if(" + TITLE_FILTER.toString() + ".test(title))continue;" +
" if(seen[href])continue;" +
" seen[href]=true;" +
" var imgNode=a.querySelector('img')||a.parentNode.querySelector('img');" +
" var cover=imgNode?(imgNode.src||imgNode.getAttribute('data-src')||''):'';" +
" r.push({url:href,title:title,cover:cover});" +
"}" +
"return JSON.stringify(r);" +
"})()");
await legado.browser.close(id);
var books = [];
if (data) {
try {
var items = JSON.parse(data);
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item.url && item.title) {
books.push({
name: item.title.trim(),
bookUrl: absUrl(item.url),
coverUrl: item.cover || "",
latestChapter: "",
kind: category
});
}
}
} catch (e) {}
}
return books;
}