Skip to content

Commit

Permalink
Merge pull request #266 from hualiong/main
Browse files Browse the repository at this point in the history
Upgrade bilinovel.com.js and yymanhua.com.js
  • Loading branch information
OshekharO authored Sep 14, 2024
2 parents 3b7815f + 5af5061 commit 37a5c41
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 86 deletions.
51 changes: 30 additions & 21 deletions repo/bilinovel.com.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ==MiruExtension==
// @name 哔哩轻小说
// @version v0.0.4
// @version v0.0.5
// @author hualiong
// @lang zh
// @icon https://www.bilinovel.com/favicon.ico
Expand Down Expand Up @@ -28,7 +28,7 @@ export default class extends Extension {
return res === null ? null : res[0];
};
this.text = (element) => {
return [...element.content.matchAll(/>([^<\n]+?)</g)].map((m) => m[1].trim()).join("");
return [...element.content.matchAll(/>([^<]+?)</g)].map((m) => m[1]).join("").trim();
};
this.filter = (element) => { // 59392
if (element.content.startsWith("<img")) {
Expand Down Expand Up @@ -91,17 +91,18 @@ export default class extends Extension {
return await Promise.all(tasks);
}
// 此时已经在详情页
const desc = this.querySelector(res, "#bookSummary > content");
const head = await this.querySelector(res, "head");
const desc = await this.querySelector(res, "#bookSummary > content");
const title = await this.getAttributeText(head.content, "meta[property='og:title']", "content");
const cover = await this.getAttributeText(head.content, "meta[property='og:image']", "content");
const url = await this.getAttributeText(head.content, "meta[property='og:novel:read_url']", "content");
const url = this.getAttributeText(head.content, "meta[property='og:novel:read_url']", "content");
const remark = this.getAttributeText(head.content, "meta[property='og:novel:author']", "content");
return [
{
title,
cover,
url: `${url.substring(25)}|${title}|${cover}|${this.text(desc).replace("<br>", "")}`,
update: await this.getAttributeText(head.content, "meta[property='og:novel:author']", "content"),
url: `${(await url).substring(25)}|${title}|${cover}|${this.text(await desc)}`,
update: await remark,
},
];
}
Expand All @@ -113,7 +114,7 @@ export default class extends Extension {
promise = (async (data) => {
const res = await this.request(data[0]);
const desc = await this.querySelector(res, "#bookSummary > content");
data.push(this.text(desc).replace("<br>", ""));
data.push(this.text(desc));
}).call(this, data);
data[0] = `${data[0].slice(0, -5)}/catalog`;
}
Expand All @@ -122,31 +123,39 @@ export default class extends Extension {
const episodes = volumes.map(async (volume) => {
const title = this.text(await this.querySelector(volume.content, ".chapter-bar > h3"));
const urls = await this.querySelectorAll(volume.content, ".chapter-li-a");
const tasks = await Promise.all(
urls.map(async (url) => ({ name: this.text(url), url: await url.getAttributeText("href") }))
);
return { title, urls: tasks };
const tasks = urls.map((url, i) => {
const regex = /\/novel\/\d+\/([0-9_]+)/;
let match = regex.exec(url.content);
if (!match) {
const id = i ? parseInt(regex.exec(urls[i - 1].content)[1]) + 1 : parseInt(regex.exec(urls[i + 1].content)[1]) - 1;
match = [`${data[0].slice(0, -8)}/${id}`];
}
return { name: this.text(url), url: match[0] };
});
return { title, urls: await Promise.all(tasks) };
});
const newLocal = await Promise.all(episodes);
if (promise) await promise;
return { title: data[1], cover: data[2], desc: data[3], episodes: newLocal };
return { title: data[1], cover: data[2], desc: data[3], episodes: await Promise.all(episodes) };
}

async watch(url) {
url = url.slice(0, -5);
const res = await this.request(`${url}_2.html`, { headers: { "Accept-Language": "zh-cn", Accept: "*/*", Cookie: "night=0" } });
let tasks = [this.handle(`${url}.html`)];
const res = await this.request(`${url}_2.html`, {
headers: { "Accept-Language": "zh-cn", Accept: "*/*", Cookie: "night=0" },
});
const subtitle = this.text(await this.querySelector(res, "#apage h1"));
const total = parseInt(subtitle.split("/")[1].slice(0, -1)) || 1;
let tasks = [];
for (let i = 1; i <= total; i++) {
if (i != 2) {
tasks.push(this.handle(`${url}_${i}.html`));
}
for (let i = 3; i <= total; i++) {
tasks.push(this.handle(`${url}_${i}.html`));
}
tasks = await Promise.all(tasks);
if (total > 1) {
tasks.splice(1, 0, (await this.querySelectorAll(res, "#acontentz > p")).map(this.filter));
}
return { title: "Test", subtitle: subtitle.split("(")[0], content: tasks.flat() };
return {
title: "Why is this 'title' attribute not valid?",
subtitle: subtitle.split("(")[0],
content: tasks.flat(),
};
}
}
92 changes: 50 additions & 42 deletions repo/cycanime.com.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ==MiruExtension==
// @name 次元城动漫
// @version v0.0.6
// @version v0.0.7
// @author hualiong
// @lang zh
// @license MIT
Expand All @@ -12,29 +12,33 @@
// ==/MiruExtension==
export default class extends Extension {
async load() {
this.decrypt = {
player: (src, key1, key2) => {
let prefix = new Array(key2.length);
for (let i = 0; i < key2.length; i++) {
prefix[key1[i]] = key2[i];
}
let a = CryptoJS.MD5(prefix.join("") + "YLwJVbXw77pk2eOrAnFdBo2c3mWkLtodMni2wk81GCnP94ZltW").toString(),
key = CryptoJS.enc.Utf8.parse(a.substring(16)),
iv = CryptoJS.enc.Utf8.parse(a.substring(0, 16)),
dec = CryptoJS.AES.decrypt(src, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return dec.toString(CryptoJS.enc.Utf8);
},
timestamp: () => {
const time = Math.ceil(new Date().getTime() / 1000);
return { time, key: CryptoJS.MD5("DS" + time + "DCC147D11943AF75").toString() }; // EC.Pop.Uid: DCC147D11943AF75
},
// this.decrypt = {
// player: (src, key1, key2) => {
// let prefix = new Array(key2.length);
// for (let i = 0; i < key2.length; i++) {
// prefix[key1[i]] = key2[i];
// }
// let a = CryptoJS.MD5(prefix.join("") + "YLwJVbXw77pk2eOrAnFdBo2c3mWkLtodMni2wk81GCnP94ZltW").toString(),
// key = CryptoJS.enc.Utf8.parse(a.substring(16)),
// iv = CryptoJS.enc.Utf8.parse(a.substring(0, 16)),
// dec = CryptoJS.AES.decrypt(src, key, {
// iv: iv,
// mode: CryptoJS.mode.CBC,
// padding: CryptoJS.pad.Pkcs7,
// });
// return dec.toString(CryptoJS.enc.Utf8);
// },
// timestamp: () => {
// const time = Math.ceil(new Date().getTime() / 1000);
// return { time, key: CryptoJS.MD5("DS" + time + "DCC147D11943AF75").toString() }; // EC.Pop.Uid: DCC147D11943AF75
// },
// };
this.decrypt = () => {
const time = Math.ceil(new Date().getTime() / 1000);
return { time, key: CryptoJS.MD5("DS" + time + "DCC147D11943AF75").toString() }; // EC.Pop.Uid: DCC147D11943AF75
};
this.base64decode = (str) => {
var words = CryptoJS.enc.Base64.parse(str);
let words = CryptoJS.enc.Base64.parse(str);
return CryptoJS.enc.Utf8.stringify(words);
};
this.querySelector = async (content, selector) => {
Expand Down Expand Up @@ -122,7 +126,7 @@ export default class extends Extension {
return [];
}
const weekdays = ["日", "一", "二", "三", "四", "五", "六"];
const { time, key } = this.decrypt.timestamp();
const { time, key } = this.decrypt();
let res = await this.request("/index.php/api/weekday", {
method: "post",
data: { weekday: weekdays[new Date().getDay()], num: 20, time, key },
Expand Down Expand Up @@ -176,7 +180,7 @@ export default class extends Extension {
}

async select(page, filter) {
const { time, key } = this.decrypt.timestamp();
const { time, key } = this.decrypt();
const res = await this.request(`/index.php/api/vod`, {
method: "post",
data: { type: filter.channels[0], class: filter.genres[0], year: filter.years[0], page, time, key },
Expand All @@ -192,32 +196,36 @@ export default class extends Extension {
async detail(str) {
const data = str.split("|");
const res = await this.request(data[0]);
const descTask = this.querySelector(res, "#height_limit");
const desc = res.match(/\bid="height_limit".*?>([\s\S]*?)</)[1].replace("&nbsp;", " ");
const labelTask = this.querySelectorAll(res, ".anthology-tab a");
const sources = await this.querySelectorAll(res, ".anthology-list-play");
const labels = (await labelTask).map((e) => e.content.match(/i>(.*?)</)[1].replace("&nbsp;", ""));
const episodes = await Promise.all(
sources.map(async (source, i) => {
const urls = (await this.querySelectorAll(source.content, "a")).map(async (a) => {
const resp = await this.request(await a.getAttributeText("href"));
const json = JSON.parse(resp.match(/var player_aaaa=({.+?})</)[1]);
const url = json.encrypt ? decodeURIComponent(this.base64decode(json.url)) : decodeURIComponent(json.url);
return { name: this.text(a), url };
});
return { title: labels[i], urls: await Promise.all(urls) };
})
);
const desc = this.text(await descTask).replace("&nbsp;", "");
return { title: data[1], cover: data[2], desc, episodes };
let reg = /href="(.*?)">(.*?)</;
const episodes = sources.map(async (source, i) => {
const urls = (await this.querySelectorAll(source.content, "a")).map(async (a) => {
const match = reg.exec(a.content);
const resp = await this.request(match[1]);
const json = JSON.parse(resp.match(/var player_aaaa=({.+?})</)[1]);
const url = decodeURIComponent(json.encrypt ? this.base64decode(json.url) : json.url);
return { name: match[2], url };
});
return { title: labels[i], urls: await Promise.all(urls) };
});
return { title: data[1], cover: data[2], desc, episodes: await Promise.all(episodes) };
}

async watch(url) {
const resp = await this.request(`/?url=${url}`, { headers: { "Miru-Url": "https://player.cycanime.com" } });
const reg = /now_(\w+)/g;
const link = this.decrypt.player(resp.match(/"url": "([^:]+?)"/)[1], reg.exec(resp)[1], reg.exec(resp)[1]);
return { type: link.indexOf(".mp4") > 0 ? "mp4" : "hls", url: link };
console.log(url);
return { type: url.indexOf(".mp4") > 0 ? "mp4" : "hls", url };
}

// async watch(url) {
// const resp = await this.request(`/?url=${url}`, { headers: { "Miru-Url": "https://player.cycanime.com" } });
// const reg = /now_(\w+)/g;
// const link = this.decrypt.player(resp.match(/"url": "([^:]+?)"/)[1], reg.exec(resp)[1], reg.exec(resp)[1]);
// return { type: link.indexOf(".mp4") > 0 ? "mp4" : "hls", url: link };
// }

async checkUpdate(str) {
const url = str.split("|")[0];
const res = await this.request(url);
Expand Down
28 changes: 12 additions & 16 deletions repo/xfani.com.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ==MiruExtension==
// @name 稀饭动漫
// @version v0.0.6
// @version v0.0.7
// @author hualiong
// @lang zh
// @license MIT
Expand Down Expand Up @@ -136,29 +136,25 @@ export default class extends Extension {
if (res.length < 25000) {
throw Error("您没有权限访问此数据,请升级会员 -【稀饭动漫】");
}
const descTask = this.querySelector(res, "#height_limit");
const desc = res.match(/\bid="height_limit".*?>([\s\S]*?)</)[1].replace("&nbsp;", " ");
const labelTask = this.querySelectorAll(res, ".anthology-tab a");
const sources = await this.querySelectorAll(res, ".anthology-list-play");
const labels = (await labelTask).map((e) => e.content.match(/i>(.*?)</)[1].replace("&nbsp;", ""));
const episodes = await Promise.all(
sources.map(async (source, i) => {
const urls = await this.querySelectorAll(source.content, "a");
for (let j = 0; j < urls.length; j++) {
urls[j] = { name: this.text(urls[j]), url: await urls[j].getAttributeText("href") };
}
return { title: labels[i], urls };
let reg = /href="(.*?)">(.*?)</;
const episodes = sources.map(async (source, i) => {
const urls = (await this.querySelectorAll(source.content, "a")).map((a) => {
const match = reg.exec(a.content);
return { name: match[2], url: match[1] };
})
);
const desc = this.text(await descTask).replace("&nbsp;", "");
return { title: data[1], cover: data[2], desc, episodes };
return { title: labels[i], urls };
});
return { title: data[1], cover: data[2], desc, episodes: await Promise.all(episodes) };
}

async watch(url) {
const res = await this.request(url);
const json = JSON.parse(
this.text(await this.querySelector(res, ".player-left > script:nth-child(7)")).substring(16)
);
const link = json.encrypt ? decodeURIComponent(this.base64decode(json.url)) : decodeURIComponent(json.url);
const json = JSON.parse(res.match(/var player_aaaa=({.+?})</)[1]);
const link = decodeURIComponent(json.encrypt ? this.base64decode(json.url) : json.url);
console.log(link);
return { type: link.indexOf(".mp4") > 0 ? "mp4" : "hls", url: link };
}
Expand Down
33 changes: 26 additions & 7 deletions repo/yymanhua.com.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ==MiruExtension==
// @name YY漫画
// @version v0.0.1
// @version v0.0.3
// @author hualiong
// @lang zh-cn
// @license MIT
Expand Down Expand Up @@ -45,10 +45,29 @@ export default class extends Extension {
const match = element.content.match(/<[^>]+>([^<]+)<\/[^>]+>/);
return !match ? "" : match[1].trim();
};
this.$get = async (url) => {
return await this.request(url, {
headers: { cookie: "yymanhua_lang=2;image_time_cookie=;mangabzimgpage=", referer: "https://www.yymanhua.com/" },
});
this.$get = async (url, count = 3, timeout = 5000) => {
try {
return await Promise.race([
this.request(url, {
headers: {
cookie: "yymanhua_lang=2;image_time_cookie=;mangabzimgpage=",
referer: "https://www.yymanhua.com/",
},
}),
new Promise((_, reject) => {
setTimeout(() => {
reject(new Error("Request timed out!"));
}, timeout);
}),
]);
} catch (error) {
if (count > 1) {
console.log(`[Retry]: ${url}`);
return this.$get(url, count - 1);
} else {
throw error;
}
}
};
}

Expand Down Expand Up @@ -108,11 +127,11 @@ export default class extends Extension {
const data = str.split("|");
const cid = data[0].match(/\d+/)[0];
const seq = Array.from({ length: parseInt(data[1]) }, (_, i) => i);
const urls = await this.asyncPool(50, seq, async (i) => {
const urls = await this.asyncPool(40, seq, async (i) => {
const resp = await this.$get(`${data[0]}chapterimage.ashx?cid=${cid}&page=${i + 1}`);
const match = this.deobfuscator(resp).match(/var pix="(.*?)".*var pvalue=\["(.*?)"/);
return match[1] + match[2];
});
return { urls };
}
}
}

0 comments on commit 37a5c41

Please sign in to comment.