mirror of
https://github.com/kodjodevf/mangayomi-extensions.git
synced 2026-02-14 02:41:39 +00:00
feat:JS new sourcces AniWorld(DE) & AllAnime(EN)
This commit is contained in:
252
javascript/anime/src/de/aniworld.js
Normal file
252
javascript/anime/src/de/aniworld.js
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
const mangayomiSources = [{
|
||||||
|
"name": "AniWorld",
|
||||||
|
"lang": "de",
|
||||||
|
"baseUrl": "https://aniworld.to",
|
||||||
|
"apiUrl": "",
|
||||||
|
"iconUrl": "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/de.aniworld.png",
|
||||||
|
"typeSource": "single",
|
||||||
|
"isManga": false,
|
||||||
|
"isNsfw": false,
|
||||||
|
"version": "0.0.1",
|
||||||
|
"dateFormat": "",
|
||||||
|
"dateFormatLocale": "",
|
||||||
|
"pkgPath": "anime/src/de/aniworld.js"
|
||||||
|
}];
|
||||||
|
|
||||||
|
class DefaultExtension extends MProvider {
|
||||||
|
async getPopular(page) {
|
||||||
|
const baseUrl = this.source.baseUrl;
|
||||||
|
const res = await new Client().get(`${baseUrl}/beliebte-animes`);
|
||||||
|
const elements = new Document(res.body).select("div.seriesListContainer div");
|
||||||
|
const list = [];
|
||||||
|
for (const element of elements) {
|
||||||
|
const linkElement = element.selectFirst("a");
|
||||||
|
const name = element.selectFirst("h3").text;
|
||||||
|
const imageUrl = baseUrl + linkElement.selectFirst("img").attr("data-src");
|
||||||
|
const link = linkElement.attr("href");
|
||||||
|
list.push({ name, imageUrl, link });
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
list: list,
|
||||||
|
hasNextPage: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async getLatestUpdates(page) {
|
||||||
|
const baseUrl = this.source.baseUrl;
|
||||||
|
const res = await new Client().get(`${baseUrl}/neu`);
|
||||||
|
const elements = new Document(res.body).select("div.seriesListContainer div");
|
||||||
|
const list = [];
|
||||||
|
for (const element of elements) {
|
||||||
|
const linkElement = element.selectFirst("a");
|
||||||
|
const name = element.selectFirst("h3").text;
|
||||||
|
const imageUrl = baseUrl + linkElement.selectFirst("img").attr("data-src");
|
||||||
|
const link = linkElement.attr("href");
|
||||||
|
list.push({ name, imageUrl, link });
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
list: list,
|
||||||
|
hasNextPage: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async search(query, page, filters) {
|
||||||
|
const baseUrl = this.source.baseUrl;
|
||||||
|
const res = await new Client().get(`${baseUrl}/animes`);
|
||||||
|
const elements = new Document(res.body).select("#seriesContainer > div > ul > li > a").filter(e => e.attr("title").toLowerCase().includes(query.toLowerCase()));
|
||||||
|
const list = [];
|
||||||
|
for (const element of elements) {
|
||||||
|
const name = element.text;
|
||||||
|
const link = element.attr("href");
|
||||||
|
const img = new Document((await new Client().get(baseUrl + link)).body).selectFirst("div.seriesCoverBox img").attr("data-src");
|
||||||
|
const imageUrl = baseUrl + img;
|
||||||
|
list.push({ name, imageUrl, link });
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
list: list,
|
||||||
|
hasNextPage: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async getDetail(url) {
|
||||||
|
const baseUrl = this.source.baseUrl;
|
||||||
|
const res = await new Client().get(baseUrl + url);
|
||||||
|
const document = new Document(res.body);
|
||||||
|
const imageUrl = baseUrl +
|
||||||
|
document.selectFirst("div.seriesCoverBox img").attr("data-src");
|
||||||
|
const name = document.selectFirst("div.series-title h1 span").text;
|
||||||
|
const genre = document.select("div.genres ul li").map(e => e.text);
|
||||||
|
const description = document.selectFirst("p.seri_des").attr("data-full-description");
|
||||||
|
const produzent = document.select("div.cast li")
|
||||||
|
.filter(e => e.outerHtml.includes("Produzent:"));
|
||||||
|
let author = "";
|
||||||
|
if (produzent.length > 0) {
|
||||||
|
author = produzent[0].select("li").map(e => e.text).join(", ");
|
||||||
|
}
|
||||||
|
const seasonsElements = document.select("#stream > ul:nth-child(1) > li > a");
|
||||||
|
let episodes = [];
|
||||||
|
for (const element of seasonsElements) {
|
||||||
|
const eps = await this.parseEpisodesFromSeries(element);
|
||||||
|
for (const ep of eps) {
|
||||||
|
episodes.push(ep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
episodes.reverse();
|
||||||
|
|
||||||
|
return {
|
||||||
|
name, imageUrl, description, author, status: 5, genre, episodes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async parseEpisodesFromSeries(element) {
|
||||||
|
const seasonId = element.getHref;
|
||||||
|
const res = await new Client().get(this.source.baseUrl + seasonId);
|
||||||
|
const episodeElements = new Document(res.body).select("table.seasonEpisodesList tbody tr");
|
||||||
|
const list = [];
|
||||||
|
for (const episodeElement of episodeElements) {
|
||||||
|
list.push(this.episodeFromElement(episodeElement));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
episodeFromElement(element) {
|
||||||
|
let name = "";
|
||||||
|
let url = "";
|
||||||
|
if (element.selectFirst("td.seasonEpisodeTitle a").attr("href").includes("/film")) {
|
||||||
|
const num = element.attr("data-episode-season-id");
|
||||||
|
name = `Film ${num}` + " : " + element.selectFirst("td.seasonEpisodeTitle a span").text;
|
||||||
|
url = element.selectFirst("td.seasonEpisodeTitle a").attr("href");
|
||||||
|
} else {
|
||||||
|
const season =
|
||||||
|
element.selectFirst("td.seasonEpisodeTitle a").attr("href").substringAfter("staffel-").substringBefore("/episode");;
|
||||||
|
const num = element.attr("data-episode-season-id");
|
||||||
|
name = `Staffel ${season} Folge ${num}` + " : " + element.selectFirst("td.seasonEpisodeTitle a span").text;
|
||||||
|
url = element.selectFirst("td.seasonEpisodeTitle a").attr("href");
|
||||||
|
}
|
||||||
|
if (name.length > 0 && url.length > 0) {
|
||||||
|
return { name, url }
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
async getVideoList(url) {
|
||||||
|
const baseUrl = this.source.baseUrl;
|
||||||
|
const res = await new Client().get(baseUrl + url);
|
||||||
|
const document = new Document(res.body);
|
||||||
|
const redirectlink = document.select("ul.row li");
|
||||||
|
const preference = new SharedPreferences();
|
||||||
|
const hosterSelection = preference.get("hoster_selection");
|
||||||
|
const videos = [];
|
||||||
|
for (const element of redirectlink) {
|
||||||
|
const langkey = element.attr("data-lang-key");
|
||||||
|
let language = "";
|
||||||
|
if (langkey.includes("3")) {
|
||||||
|
language = "Deutscher Sub";
|
||||||
|
} else if (langkey.includes("1")) {
|
||||||
|
language = "Deutscher Dub";
|
||||||
|
} else if (langkey.includes("2")) {
|
||||||
|
language = "Englischer Sub";
|
||||||
|
}
|
||||||
|
const redirectgs = baseUrl + element.selectFirst("a.watchEpisode").attr("href");
|
||||||
|
const hoster = element.selectFirst("a h4").text;
|
||||||
|
if (hoster == "Streamtape" && hosterSelection.includes("Streamtape")) {
|
||||||
|
const body = (await new Client().get(redirectgs)).body;
|
||||||
|
const quality = `Streamtape ${language}`;
|
||||||
|
const vids = await streamTapeExtractor(body.match(/https:\/\/streamtape\.com\/e\/[a-zA-Z0-9]+/g)[0], quality);
|
||||||
|
for (const vid of vids) {
|
||||||
|
videos.push(vid);
|
||||||
|
}
|
||||||
|
} else if (hoster == "VOE" && hosterSelection.includes("VOE")) {
|
||||||
|
const body = (await new Client().get(redirectgs)).body;
|
||||||
|
const quality = `VOE ${language}`;
|
||||||
|
const vids = await voeExtractor(body.match(/https:\/\/voe\.sx\/e\/[a-zA-Z0-9]+/g)[0], quality);
|
||||||
|
for (const vid of vids) {
|
||||||
|
videos.push(vid);
|
||||||
|
}
|
||||||
|
} else if (hoster == "Vidoza" && hosterSelection.includes("Vidoza")) {
|
||||||
|
const body = (await new Client().get(redirectgs)).body;
|
||||||
|
const quality = `Vidoza ${language}`;
|
||||||
|
const match = body.match(/https:\/\/[^\s]*\.vidoza\.net\/[^\s]*\.mp4/g);
|
||||||
|
if (match.length > 0) {
|
||||||
|
videos.push({ url: match[0], originalUrl: match[0], quality });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.sortVideos(videos);
|
||||||
|
}
|
||||||
|
sortVideos(videos) {
|
||||||
|
const preference = new SharedPreferences();
|
||||||
|
const hoster = preference.get("preferred_hoster");
|
||||||
|
const subPreference = preference.get("preferred_lang");
|
||||||
|
videos.sort((a, b) => {
|
||||||
|
let qualityMatchA = 0;
|
||||||
|
if (a.quality.includes(hoster) &&
|
||||||
|
a.quality.includes(subPreference)) {
|
||||||
|
qualityMatchA = 1;
|
||||||
|
}
|
||||||
|
let qualityMatchB = 0;
|
||||||
|
if (b.quality.includes(hoster) &&
|
||||||
|
b.quality.includes(subPreference)) {
|
||||||
|
qualityMatchB = 1;
|
||||||
|
}
|
||||||
|
return qualityMatchB - qualityMatchA;
|
||||||
|
});
|
||||||
|
return videos;
|
||||||
|
}
|
||||||
|
getSourcePreferences() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"key": "preferred_lang",
|
||||||
|
"listPreference": {
|
||||||
|
"title": "Bevorzugte Sprache",
|
||||||
|
"summary": "",
|
||||||
|
"valueIndex": 0,
|
||||||
|
"entries": [
|
||||||
|
"Deutscher Sub",
|
||||||
|
"Deutscher Dub",
|
||||||
|
"Englischer Sub"
|
||||||
|
],
|
||||||
|
"entryValues": [
|
||||||
|
"Deutscher Sub",
|
||||||
|
"Deutscher Dub",
|
||||||
|
"Englischer Sub"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "preferred_hoster",
|
||||||
|
"listPreference": {
|
||||||
|
"title": "Standard-Hoster",
|
||||||
|
"summary": "",
|
||||||
|
"valueIndex": 0,
|
||||||
|
"entries": [
|
||||||
|
"Streamtape",
|
||||||
|
"VOE",
|
||||||
|
"Vidoza"
|
||||||
|
],
|
||||||
|
"entryValues": [
|
||||||
|
"Streamtape",
|
||||||
|
"VOE",
|
||||||
|
"Vidoza"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "hoster_selection",
|
||||||
|
"multiSelectListPreference": {
|
||||||
|
"title": "Hoster auswählen",
|
||||||
|
"summary": "",
|
||||||
|
"entries": [
|
||||||
|
"Streamtape",
|
||||||
|
"VOE",
|
||||||
|
"Vidoza"
|
||||||
|
],
|
||||||
|
"entryValues": [
|
||||||
|
"Streamtape",
|
||||||
|
"VOE",
|
||||||
|
"Vidoza"
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
"Streamtape",
|
||||||
|
"VOE",
|
||||||
|
"Vidoza"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
482
javascript/anime/src/en/allanime.js
Normal file
482
javascript/anime/src/en/allanime.js
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
const mangayomiSources = [{
|
||||||
|
"name": "AllAnime",
|
||||||
|
"lang": "en",
|
||||||
|
"baseUrl": "https://allanime.to",
|
||||||
|
"apiUrl": "https://api.allanime.day/api",
|
||||||
|
"iconUrl": "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/en.allanime.png",
|
||||||
|
"typeSource": "single",
|
||||||
|
"isManga": false,
|
||||||
|
"isNsfw": false,
|
||||||
|
"version": "0.0.1",
|
||||||
|
"apiUrl": "",
|
||||||
|
"dateFormat": "",
|
||||||
|
"dateFormatLocale": "",
|
||||||
|
"pkgName": "anime/src/en/allanime.js"
|
||||||
|
}];
|
||||||
|
|
||||||
|
class DefaultExtension extends MProvider {
|
||||||
|
async request(body) {
|
||||||
|
const apiUrl = this.source.apiUrl;
|
||||||
|
const baseUrl = this.source.baseUrl;
|
||||||
|
return (await new Client().get(apiUrl + body, { "Referer": baseUrl })).body
|
||||||
|
}
|
||||||
|
async getPopular(page) {
|
||||||
|
const encodedGql = `?variables=%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22type%22:%20%22anime%22,%0A%20%20%20%20%20%20%20%20%20%20%22size%22:%2026,%0A%20%20%20%20%20%20%20%20%20%20%22dateRange%22:%201,%0A%20%20%20%20%20%20%20%20%20%20%22page%22:%20${page}%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20&query=%0A%20%20%20%20%20%20%20%20query($type:%20VaildPopularTypeEnumType!,%20$size:%20Int!,%20$dateRange:%20Int,%20$page:%20Int)%20%7B%0A%20%20%20%20%20%20%20%20%20%20queryPopular(type:%20$type,%20size:%20$size,%20dateRange:%20$dateRange,%20page:%20$page)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20recommendations%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20anyCard%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_id%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20englishName%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nativeName%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20thumbnail%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20slugTime%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20`
|
||||||
|
const resList = JSON.parse(await this.request(encodedGql)).data.queryPopular.recommendations.filter(e => e.anyCard !== null);
|
||||||
|
const preferences = new SharedPreferences();
|
||||||
|
const titleStyle = preferences.get("preferred_title_style");
|
||||||
|
const list = [];
|
||||||
|
for (const anime of resList) {
|
||||||
|
let title;
|
||||||
|
if (titleStyle === "romaji") {
|
||||||
|
title = anime.anyCard.name;
|
||||||
|
} else if (titleStyle === "eng") {
|
||||||
|
title = anime.anyCard.englishName || anime.anyCard.name;
|
||||||
|
} else {
|
||||||
|
title = anime.anyCard.nativeName || anime.anyCard.name;
|
||||||
|
}
|
||||||
|
const name = title;
|
||||||
|
const imageUrl = anime.anyCard.thumbnail;
|
||||||
|
const link = `/bangumi/${anime.anyCard._id}/${anime.anyCard.name.replace(/[^a-zA-Z0-9]/g, "-")
|
||||||
|
.replace(/-{2,}/g, "-")
|
||||||
|
.toLowerCase()}`;
|
||||||
|
list.push({ name, imageUrl, link });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
list: list,
|
||||||
|
hasNextPage: list.length === 26
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLatestUpdates(page) {
|
||||||
|
return await this.search("", page, []);
|
||||||
|
}
|
||||||
|
async search(query, page, filters) {
|
||||||
|
query = query.replace(" ", "%20");
|
||||||
|
const encodedGql = `?variables=%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22search%22:%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22query%22:%20%22${query}%22,%0A%20%20%20%20%20%20%20%20%20%20%20%20%22allowAdult%22:%20false,%0A%20%20%20%20%20%20%20%20%20%20%20%20%22allowUnknown%22:%20false%0A%20%20%20%20%20%20%20%20%20%20%7D,%0A%20%20%20%20%20%20%20%20%20%20%22countryOrigin%22:%20%22ALL%22,%0A%20%20%20%20%20%20%20%20%20%20%22limit%22:%2026,%0A%20%20%20%20%20%20%20%20%20%20%22page%22:%20${page}%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20&query=%0A%20%20%20%20%20%20%20%20query($search:%20SearchInput,%20$limit:%20Int,%20$countryOrigin:%20VaildCountryOriginEnumType,%20$page:%20Int)%20%7B%0A%20%20%20%20%20%20%20%20%20%20shows(search:%20$search,%20limit:%20$limit,%20countryOrigin:%20$countryOrigin,%20page:%20$page)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20_id%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20nativeName%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20englishName%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20thumbnail%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20slugTime%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20`;
|
||||||
|
const resList = JSON.parse(await this.request(encodedGql)).data.shows.edges;
|
||||||
|
const preferences = new SharedPreferences();
|
||||||
|
const titleStyle = preferences.get("preferred_title_style");
|
||||||
|
const list = [];
|
||||||
|
for (const anime of resList) {
|
||||||
|
let title;
|
||||||
|
if (titleStyle === "romaji") {
|
||||||
|
title = anime.name;
|
||||||
|
} else if (titleStyle === "eng") {
|
||||||
|
title = anime.englishName || anime.name;
|
||||||
|
} else {
|
||||||
|
title = anime.nativeName || anime.name;
|
||||||
|
}
|
||||||
|
const name = title;
|
||||||
|
const imageUrl = anime.thumbnail;
|
||||||
|
const link = `/bangumi/${anime._id}/${anime.name.replace(/[^a-zA-Z0-9]/g, "-")
|
||||||
|
.replace(/-{2,}/g, "-")
|
||||||
|
.toLowerCase()}`;
|
||||||
|
list.push({ name, imageUrl, link });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
list: list,
|
||||||
|
hasNextPage: list.length === 26
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async getDetail(url) {
|
||||||
|
const id = url.substringAfter('bangumi/').substringBefore('/');
|
||||||
|
const encodedGql = `?variables=%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22id%22:%20%22${id}%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20&query=%0A%20%20%20%20%20%20%20%20query($id:%20String!)%20%7B%0A%20%20%20%20%20%20%20%20%20%20show(_id:%20$id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20thumbnail%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20description%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20type%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20season%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20score%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20genres%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20status%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20studios%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20availableEpisodesDetail%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20`;
|
||||||
|
const show = JSON.parse(await this.request(encodedGql)).data.show;
|
||||||
|
const genre = show.genres || [];
|
||||||
|
const status = this.parseStatus(show.status);
|
||||||
|
const author = show.studios.length > 0 ? show.studios[0] : "";
|
||||||
|
let description = "";
|
||||||
|
description = description.concat(show.description, "\n\n", `Type: ${show.type || "Unknown"}`, `\nAired: ${show.season?.quarter || "-"} ${show.season?.year || "-"}`, `\nScore: ${show.score || "-"}★`);
|
||||||
|
let episodesSub = [];
|
||||||
|
for (const episode of show.availableEpisodesDetail.sub) {
|
||||||
|
const num = parseInt(episode) || 1;
|
||||||
|
const name = `Episode ${num}`;
|
||||||
|
const url = JSON.stringify({
|
||||||
|
showId: id,
|
||||||
|
translationType: ["sub"],
|
||||||
|
episodeString: episode
|
||||||
|
});
|
||||||
|
const scanlator = "sub";
|
||||||
|
episodesSub.push({ num, name, url, scanlator });
|
||||||
|
}
|
||||||
|
let episodesDub = [];
|
||||||
|
for (const episode of show.availableEpisodesDetail.dub) {
|
||||||
|
const num = parseInt(episode) || 1;
|
||||||
|
const name = `Episode ${num}`;
|
||||||
|
const url = JSON.stringify({
|
||||||
|
showId: id,
|
||||||
|
translationType: ["dub"],
|
||||||
|
episodeString: episode
|
||||||
|
});
|
||||||
|
const scanlator = "dub";
|
||||||
|
episodesDub.push({ num, name, url, scanlator });
|
||||||
|
}
|
||||||
|
let episodes = [];
|
||||||
|
if (episodesSub.length > 0 && episodesSub.length) {
|
||||||
|
episodes = episodesSub.map(ep => {
|
||||||
|
const f = episodesDub.filter(e => e.num === ep.num);
|
||||||
|
if (f.length > 0) {
|
||||||
|
const url = JSON.parse(ep.url);
|
||||||
|
return {
|
||||||
|
"name": ep.name, "url": JSON.stringify({
|
||||||
|
showId: url.showId,
|
||||||
|
translationType: ['sub', 'dub'],
|
||||||
|
episodeString: url.episodeString
|
||||||
|
}), scanlator: `sub, dub`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ep;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
episodes = episodesDub;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
description, author, status, genre, episodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parseStatus(string) {
|
||||||
|
switch (string) {
|
||||||
|
case "Releasing":
|
||||||
|
return 0;
|
||||||
|
case "Finished":
|
||||||
|
return 1;
|
||||||
|
case "Not Yet Released":
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async getVideoList(url) {
|
||||||
|
const baseUrl = this.source.baseUrl;
|
||||||
|
const preferences = new SharedPreferences();
|
||||||
|
const subPref = preferences.get("preferred_sub");
|
||||||
|
const ep = JSON.parse(url);
|
||||||
|
const translationType = ep.translationType.filter(t => t === subPref);
|
||||||
|
if (translationType.length == 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const encodedGql = `?variables=%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22showId%22:%20%22${ep.showId}%22,%0A%20%20%20%20%20%20%20%20%20%20%22episodeString%22:%20%22${ep.episodeString}%22,%0A%20%20%20%20%20%20%20%20%20%20%22translationType%22:%20%22${translationType[0]}%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20&query=%0A%20%20%20%20%20%20%20%20query(%0A%20%20%20%20%20%20%20%20%20%20$showId:%20String!%0A%20%20%20%20%20%20%20%20%20%20$episodeString:%20String!%0A%20%20%20%20%20%20%20%20%20%20$translationType:%20VaildTranslationTypeEnumType!%0A%20%20%20%20%20%20%20%20)%20%7B%0A%20%20%20%20%20%20%20%20%20%20episode(%0A%20%20%20%20%20%20%20%20%20%20%20%20showId:%20$showId%0A%20%20%20%20%20%20%20%20%20%20%20%20episodeString:%20$episodeString%0A%20%20%20%20%20%20%20%20%20%20%20%20translationType:%20$translationType%0A%20%20%20%20%20%20%20%20%20%20)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20sourceUrls%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20`;
|
||||||
|
const videoJson = JSON.parse(await this.request(encodedGql));
|
||||||
|
const videos = [];
|
||||||
|
const altHosterSelection = preferences.get('alt_hoster_selection');
|
||||||
|
for (const video of videoJson.data.episode.sourceUrls) {
|
||||||
|
const videoUrl = this.decryptSource(video.sourceUrl);
|
||||||
|
let quality = "";
|
||||||
|
if (videoUrl.includes("/apivtwo/") && altHosterSelection.some(element => 'player' === element)) {
|
||||||
|
quality = `internal ${video.sourceName}`;
|
||||||
|
const vids = await new AllAnimeExtractor({ "Referer": baseUrl }, "https://allanime.to").videoFromUrl(videoUrl, quality);
|
||||||
|
for (const vid of vids) {
|
||||||
|
videos.push(vid);
|
||||||
|
}
|
||||||
|
} else if (["vidstreaming", "https://gogo", "playgo1.cc", "playtaku"].some(element => videoUrl.includes(element)) && altHosterSelection.some(element => 'vidstreaming' === element)) {
|
||||||
|
const vids = await gogoCdnExtractor(videoUrl);
|
||||||
|
for (const vid of vids) {
|
||||||
|
videos.push(vid);
|
||||||
|
}
|
||||||
|
} else if (["dood", "d0"].some(element => videoUrl.includes(element)) && altHosterSelection.some(element => 'dood' === element)) {
|
||||||
|
const vids = await doodExtractor(videoUrl);
|
||||||
|
for (const vid of vids) {
|
||||||
|
videos.push(vid);
|
||||||
|
}
|
||||||
|
} else if (videoUrl.includes("ok.ru") && altHosterSelection.some(element => 'okru' === element)) {
|
||||||
|
const vids = await okruExtractor(videoUrl);
|
||||||
|
for (const vid of vids) {
|
||||||
|
videos.push(vid);
|
||||||
|
}
|
||||||
|
} else if (videoUrl.includes("mp4upload.com") && altHosterSelection.some(element => 'mp4upload' === element)) {
|
||||||
|
const vids = await mp4UploadExtractor(videoUrl);
|
||||||
|
for (const vid of vids) {
|
||||||
|
videos.push(vid);
|
||||||
|
}
|
||||||
|
} else if (videoUrl.includes("streamlare.com") && altHosterSelection.some(element => 'streamlare' === element)) {
|
||||||
|
const vids = await streamlareExtractor(videoUrl);
|
||||||
|
for (const vid of vids) {
|
||||||
|
videos.push(vid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.sortVideos(videos);
|
||||||
|
}
|
||||||
|
sortVideos(videos) {
|
||||||
|
const preferences = new SharedPreferences();
|
||||||
|
const hoster = preferences.get("preferred_hoster");
|
||||||
|
const quality = preferences.get("preferred_quality");
|
||||||
|
videos.sort((a, b) => {
|
||||||
|
let qualityMatchA = 0;
|
||||||
|
if (a.quality.includes(hoster) &&
|
||||||
|
a.quality.includes(quality)) {
|
||||||
|
qualityMatchA = 1;
|
||||||
|
}
|
||||||
|
let qualityMatchB = 0;
|
||||||
|
if (b.quality.includes(hoster) &&
|
||||||
|
b.quality.includes(quality)) {
|
||||||
|
qualityMatchB = 1;
|
||||||
|
}
|
||||||
|
return qualityMatchB - qualityMatchA;
|
||||||
|
});
|
||||||
|
return videos;
|
||||||
|
}
|
||||||
|
decryptSource(str) {
|
||||||
|
if (str.startsWith("-")) {
|
||||||
|
return str.substring(str.lastIndexOf('-') + 1)
|
||||||
|
.match(/.{1,2}/g)
|
||||||
|
.map(hex => parseInt(hex, 16))
|
||||||
|
.map(byte => String.fromCharCode(byte ^ 56))
|
||||||
|
.join("");
|
||||||
|
} else {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getSourcePreferences() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"key": "preferred_title_style",
|
||||||
|
"listPreference": {
|
||||||
|
"title": "Preferred Title Style",
|
||||||
|
"summary": "",
|
||||||
|
"valueIndex": 0,
|
||||||
|
"entries": ["Romaji", "English", "Native"],
|
||||||
|
"entryValues": ["romaji", "eng", "native"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "preferred_quality",
|
||||||
|
"listPreference": {
|
||||||
|
"title": "Preferred quality",
|
||||||
|
"summary": "",
|
||||||
|
"valueIndex": 0,
|
||||||
|
"entries": [
|
||||||
|
"2160p",
|
||||||
|
"1440p",
|
||||||
|
"1080p",
|
||||||
|
"720p",
|
||||||
|
"480p",
|
||||||
|
"360p",
|
||||||
|
"240p",
|
||||||
|
"80p"],
|
||||||
|
"entryValues": [
|
||||||
|
"2160",
|
||||||
|
"1440",
|
||||||
|
"1080",
|
||||||
|
"720",
|
||||||
|
"480",
|
||||||
|
"360",
|
||||||
|
"240",
|
||||||
|
"80"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "preferred_sub",
|
||||||
|
"listPreference": {
|
||||||
|
"title": "Prefer subs or dubs?",
|
||||||
|
"summary": "",
|
||||||
|
"valueIndex": 0,
|
||||||
|
"entries": ["Subs", "Dubs"],
|
||||||
|
"entryValues": ["sub", "dub"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "preferred_hoster",
|
||||||
|
"listPreference": {
|
||||||
|
"title": "Preferred Video Server",
|
||||||
|
"summary": "",
|
||||||
|
"valueIndex": 0,
|
||||||
|
"entries": [
|
||||||
|
"Ac", "Ak", "Kir", "Rab", "Luf-mp4",
|
||||||
|
"Si-Hls", "S-mp4", "Ac-Hls", "Uv-mp4", "Pn-Hls",
|
||||||
|
"vidstreaming", "okru", "mp4upload", "streamlare", "doodstream"
|
||||||
|
],
|
||||||
|
"entryValues": [
|
||||||
|
"Ac", "Ak", "Kir", "Rab", "Luf-mp4",
|
||||||
|
"Si-Hls", "S-mp4", "Ac-Hls", "Uv-mp4", "Pn-Hls",
|
||||||
|
"vidstreaming", "okru", "mp4upload", "streamlare", "doodstream"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "alt_hoster_selection",
|
||||||
|
"multiSelectListPreference": {
|
||||||
|
"title": "Enable/Disable Alternative Hosts",
|
||||||
|
"summary": "",
|
||||||
|
"entries": [
|
||||||
|
"player",
|
||||||
|
"vidstreaming",
|
||||||
|
"okru",
|
||||||
|
"mp4upload",
|
||||||
|
"streamlare",
|
||||||
|
"doodstream"
|
||||||
|
],
|
||||||
|
"entryValues": [
|
||||||
|
"player",
|
||||||
|
"vidstreaming",
|
||||||
|
"okru",
|
||||||
|
"mp4upload",
|
||||||
|
"streamlare",
|
||||||
|
"doodstream"
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
"player",
|
||||||
|
"vidstreaming",
|
||||||
|
"okru",
|
||||||
|
"mp4upload",
|
||||||
|
"streamlare",
|
||||||
|
"doodstream"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AllAnimeExtractor {
|
||||||
|
constructor(headers, baseUrl) {
|
||||||
|
this.headers = headers;
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesIntoHumanReadable(bytes) {
|
||||||
|
const kilobyte = 1000;
|
||||||
|
const megabyte = kilobyte * 1000;
|
||||||
|
const gigabyte = megabyte * 1000;
|
||||||
|
const terabyte = gigabyte * 1000;
|
||||||
|
|
||||||
|
if (bytes >= 0 && bytes < kilobyte) {
|
||||||
|
return `${bytes} b/s`;
|
||||||
|
} else if (bytes >= kilobyte && bytes < megabyte) {
|
||||||
|
return `${Math.floor(bytes / kilobyte)} kb/s`;
|
||||||
|
} else if (bytes >= megabyte && bytes < gigabyte) {
|
||||||
|
return `${Math.floor(bytes / megabyte)} mb/s`;
|
||||||
|
} else if (bytes >= gigabyte && bytes < terabyte) {
|
||||||
|
return `${Math.floor(bytes / gigabyte)} gb/s`;
|
||||||
|
} else if (bytes >= terabyte) {
|
||||||
|
return `${Math.floor(bytes / terabyte)} tb/s`;
|
||||||
|
} else {
|
||||||
|
return `${bytes} bits/s`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async videoFromUrl(url, name) {
|
||||||
|
const videoList = [];
|
||||||
|
const endPointResponse = JSON.parse((await new Client().get(`${this.baseUrl}/getVersion`, this.headers)).body);
|
||||||
|
const endPoint = endPointResponse.episodeIframeHead;
|
||||||
|
|
||||||
|
const resp = await new Client().get(endPoint + url.replace("/clock?", "/clock.json?"), this.headers);
|
||||||
|
|
||||||
|
if (resp.statusCode !== 200) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const linkJson = JSON.parse(resp.body);
|
||||||
|
for (const link of linkJson.links) {
|
||||||
|
const subtitles = [];
|
||||||
|
if (link.subtitles && link.subtitles.length > 0) {
|
||||||
|
subtitles.push(...link.subtitles.map(sub => {
|
||||||
|
const label = sub.label ? ` - ${sub.label}` : '';
|
||||||
|
return { file: sub.src, label: `${sub.lang}${label}` };
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (link.mp4) {
|
||||||
|
videoList.push({
|
||||||
|
url:
|
||||||
|
link.link,
|
||||||
|
quality: `Original (${name} - ${link.resolutionStr})`,
|
||||||
|
originalUrl: link.link,
|
||||||
|
subtitles,
|
||||||
|
});
|
||||||
|
} else if (link.hls) {
|
||||||
|
const headers =
|
||||||
|
{
|
||||||
|
'Host': link.link.match(/^(?:https?:\/\/)?(?:www\.)?([^\/]+)/)[1],
|
||||||
|
'Origin': endPoint,
|
||||||
|
'Referer': `${endPoint}/`
|
||||||
|
};
|
||||||
|
const resp = await new Client().get(link.link, headers);
|
||||||
|
|
||||||
|
if (resp.statusCode === 200) {
|
||||||
|
const masterPlaylist = resp.body;
|
||||||
|
const audios = [];
|
||||||
|
if (masterPlaylist.includes('#EXT-X-MEDIA:TYPE=AUDIO')) {
|
||||||
|
const audioInfo = masterPlaylist.substringAfter('#EXT-X-MEDIA:TYPE=AUDIO').substringBefore('\n');
|
||||||
|
const language = audioInfo.substringAfter('NAME="').substringBefore('"');
|
||||||
|
const url = audioInfo.substringAfter('URI="').substringBefore('"');
|
||||||
|
audios.push({ file: url, label: language });
|
||||||
|
}
|
||||||
|
if (!masterPlaylist.includes('#EXT-X-STREAM-INF:')) {
|
||||||
|
if (audios.length === 0) {
|
||||||
|
videoList.push({ url: link.link, quality: `${name} - ${link.resolutionStr}`, originalUrl: link.link, subtitles, headers });
|
||||||
|
} else {
|
||||||
|
videoList.push({ url: link.link, quality: `${name} - ${link.resolutionStr}`, originalUrl: link.link, subtitles, audios, headers });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
masterPlaylist.substringAfter('#EXT-X-STREAM-INF:').split('#EXT-X-STREAM-INF:').forEach(it => {
|
||||||
|
let bandwidth = '';
|
||||||
|
if (it.includes('AVERAGE-BANDWIDTH')) {
|
||||||
|
bandwidth = ` ${this.bytesIntoHumanReadable(it.substringAfter('AVERAGE-BANDWIDTH=').substringBefore(','))}`;
|
||||||
|
}
|
||||||
|
const quality = `${it.substringAfter('RESOLUTION=').substringAfter('x').substringBefore(',')}p${bandwidth} (${name} - ${link.resolutionStr})`;
|
||||||
|
let videoUrl = it.substringAfter('\n').substringBefore('\n');
|
||||||
|
|
||||||
|
if (!videoUrl.startsWith('http')) {
|
||||||
|
videoUrl = resp.request.url.substringBeforeLast('/') + `/${videoUrl}`;
|
||||||
|
}
|
||||||
|
const headers =
|
||||||
|
{
|
||||||
|
'Host': videoUrl.match(/^(?:https?:\/\/)?(?:www\.)?([^\/]+)/)[1],
|
||||||
|
'Origin': endPoint,
|
||||||
|
'Referer': `${endPoint}/`
|
||||||
|
};
|
||||||
|
if (audios.length === 0) {
|
||||||
|
videoList.push({ url: videoUrl, quality, originalUrl: videoUrl, subtitles, headers });
|
||||||
|
} else {
|
||||||
|
videoList.push({ url: videoUrl, quality, originalUrl: videoUrl, subtitles, audios, headers });
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (link.crIframe) {
|
||||||
|
for (const stream of link.portData.streams) {
|
||||||
|
if (stream.format === 'adaptive_dash') {
|
||||||
|
videoList.push({
|
||||||
|
url:
|
||||||
|
stream.url,
|
||||||
|
quality: `Original (AC - Dash${stream.hardsub_lang.length === 0 ? '' : ` - Hardsub: ${stream.hardsub_lang}`})`,
|
||||||
|
originalUrl: stream.url,
|
||||||
|
subtitles,
|
||||||
|
});
|
||||||
|
} else if (stream.format === 'adaptive_hls') {
|
||||||
|
const resp = await new Client().get(stream.url, { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0' })
|
||||||
|
if (resp.statusCode === 200) {
|
||||||
|
const masterPlaylist = resp.body;
|
||||||
|
masterPlaylist.substringAfter('#EXT-X-STREAM-INF:').split('#EXT-X-STREAM-INF:').forEach(t => {
|
||||||
|
const quality = `${t.substringAfter('RESOLUTION=').substringAfter('x').substringBefore(',')}p (AC - HLS${stream.hardsub_lang.length === 0 ? '' : ` - Hardsub: ${stream.hardsub_lang}`})`;
|
||||||
|
const videoUrl = t.substringAfter('\n').substringBefore('\n');
|
||||||
|
videoList.push({ url: videoUrl, quality, originalUrl: videoUrl, subtitles });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (link.dash) {
|
||||||
|
const audios = link.rawUrls && link.rawUrls.audios ? link.rawUrls.audios.map(it => { return { file: it.url, label: this.bytesIntoHumanReadable(it.bandwidth) }; }) : [];
|
||||||
|
const videos = link.rawUrls && link.rawUrls.vids ? link.rawUrls.vids.map
|
||||||
|
(it => {
|
||||||
|
if (!audios) {
|
||||||
|
return { url: it.url, quality: `${name} - ${it.height} ${this.bytesIntoHumanReadable(it.bandwidth)}`, originalUrl: it.url, subtitles };
|
||||||
|
} else {
|
||||||
|
return { url: it.url, quality: `${name} - ${it.height} ${this.bytesIntoHumanReadable(it.bandwidth)}`, originalUrl: it.url, audios, subtitles };
|
||||||
|
}
|
||||||
|
}) : [];
|
||||||
|
|
||||||
|
if (videos.length > 0) {
|
||||||
|
videoList.push(...videos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return videoList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BIN
javascript/icon/de.aniworld.png
Normal file
BIN
javascript/icon/de.aniworld.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
BIN
javascript/icon/en.allanime.png
Normal file
BIN
javascript/icon/en.allanime.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
Reference in New Issue
Block a user