From cb1f64d2ca7ab8c80d49b9a772bfcf0d22ee7675 Mon Sep 17 00:00:00 2001 From: NBA2K1 <78034913+NBA2K1@users.noreply.github.com> Date: Sat, 23 Nov 2024 18:26:07 +0100 Subject: [PATCH] Update serienstream.js Serienstream: - copied the changes from Aniworld Aniworld: - shortened getSourcePreferences() and made it more readable/maintainable - used array in getRandomString() for better readability --- javascript/anime/src/de/aniworld.js | 56 +---- javascript/anime/src/de/serienstream.js | 277 ++++++++++++------------ 2 files changed, 146 insertions(+), 187 deletions(-) diff --git a/javascript/anime/src/de/aniworld.js b/javascript/anime/src/de/aniworld.js index 98a7832a..b5ee46a2 100644 --- a/javascript/anime/src/de/aniworld.js +++ b/javascript/anime/src/de/aniworld.js @@ -173,6 +173,8 @@ class DefaultExtension extends MProvider { return videos; } getSourcePreferences() { + const hosterOptions = ["Streamtape", "VOE", "Vidoza", "Doodstream"]; + const languageOptions = ["Deutscher Sub", "Deutscher Dub", "Englischer Sub"]; return [ { "key": "preferred_lang", @@ -180,16 +182,8 @@ class DefaultExtension extends MProvider { "title": "Bevorzugte Sprache", "summary": "", "valueIndex": 0, - "entries": [ - "Deutscher Sub", - "Deutscher Dub", - "Englischer Sub" - ], - "entryValues": [ - "Deutscher Sub", - "Deutscher Dub", - "Englischer Sub" - ] + "entries": languageOptions, + "entryValues": languageOptions } }, { @@ -198,18 +192,8 @@ class DefaultExtension extends MProvider { "title": "Standard-Hoster", "summary": "", "valueIndex": 0, - "entries": [ - "Streamtape", - "VOE", - "Vidoza", - "Doodstream" - ], - "entryValues": [ - "Streamtape", - "Voe", - "Vidoza", - "Doodstream" - ] + "entries": hosterOptions, + "entryValues": hosterOptions } }, { @@ -217,24 +201,9 @@ class DefaultExtension extends MProvider { "multiSelectListPreference": { "title": "Hoster auswählen", "summary": "", - "entries": [ - "Streamtape", - "VOE", - "Vidoza", - "Doodstream" - ], - "entryValues": [ - "Streamtape", - "VOE", - "Vidoza", - "Doodstream" - ], - "values": [ - "Streamtape", - "VOE", - "Vidoza", - "Doodstream" - ] + "entries": hosterOptions, + "entryValues": hosterOptions, + "values": hosterOptions } } ]; @@ -296,10 +265,9 @@ extractAny.methods = { function getRandomString(length) { const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; - let result = ""; + const charArray = new Array(length); for (let i = 0; i < length; i++) { - const random = Math.floor(Math.random() * 61); - result += chars[random]; + charArray[i] = chars[Math.floor(Math.random() * chars.length)]; } - return result; + return charArray.join(""); } diff --git a/javascript/anime/src/de/serienstream.js b/javascript/anime/src/de/serienstream.js index 82b93410..64dca94c 100644 --- a/javascript/anime/src/de/serienstream.js +++ b/javascript/anime/src/de/serienstream.js @@ -7,16 +7,20 @@ const mangayomiSources = [{ "typeSource": "single", "isManga": false, "isNsfw": false, - "version": "0.0.1", + "version": "0.0.2", "dateFormat": "", "dateFormatLocale": "", "pkgPath": "anime/src/de/serienstream.js" }]; class DefaultExtension extends MProvider { + constructor () { + super(); + this.client = new Client(); + } async getPopular(page) { const baseUrl = this.source.baseUrl; - const res = await new Client().get(`${baseUrl}/beliebte-serien`); + const res = await this.client.get(`${baseUrl}/beliebte-serien`); const elements = new Document(res.body).select("div.seriesListContainer div"); const list = []; for (const element of elements) { @@ -33,7 +37,7 @@ class DefaultExtension extends MProvider { } async getLatestUpdates(page) { const baseUrl = this.source.baseUrl; - const res = await new Client().get(`${baseUrl}/neu`); + const res = await this.client.get(`${baseUrl}/neu`); const elements = new Document(res.body).select("div.seriesListContainer div"); const list = []; for (const element of elements) { @@ -50,13 +54,13 @@ class DefaultExtension extends MProvider { } async search(query, page, filters) { const baseUrl = this.source.baseUrl; - const res = await new Client().get(`${baseUrl}/serien`); + const res = await this.client.get(`${baseUrl}/serien`); 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 img = new Document((await this.client.get(baseUrl + link)).body).selectFirst("div.seriesCoverBox img").attr("data-src"); const imageUrl = baseUrl + img; list.push({ name, imageUrl, link }); } @@ -67,8 +71,7 @@ class DefaultExtension extends MProvider { } async getDetail(url) { const baseUrl = this.source.baseUrl; - const client = new Client(); - const res = await client.get(baseUrl + url); + const res = await this.client.get(baseUrl + url); const document = new Document(res.body); const imageUrl = baseUrl + document.selectFirst("div.seriesCoverBox img").attr("data-src"); @@ -82,18 +85,29 @@ class DefaultExtension extends MProvider { author = produzent[0].select("li").map(e => e.text).join(", "); } const seasonsElements = document.select("#stream > ul:nth-child(1) > li > a"); - const episodes = (await Promise.all(seasonsElements.map(element => this.parseEpisodesFromSeries(element, client)))).flat(); + + const promises = []; + const episodes = []; + for (const element of seasonsElements) { + promises.push(this.parseEpisodesFromSeries(element)); + } + for (const p of (await Promise.allSettled(promises))) { + if (p.status == 'fulfilled') { + episodes.push(...p.value); + } + } episodes.reverse(); - return { - name, imageUrl, description, author, status: 5, genre, episodes - }; + return { name, imageUrl, description, author, status: 5, genre, episodes }; } - async parseEpisodesFromSeries(seriesElement, client) { - const seasonId = seriesElement.getHref; - const response = await client.get(`${this.source.baseUrl}${seasonId}`); - const episodeElements = new Document(response.body).select("table.seasonEpisodesList tbody tr"); - const episodes = Array.from(episodeElements).map((episodeElement) => this.episodeFromElement(episodeElement)); - return episodes.filter(ep => Object.keys(ep).length > 0); + async parseEpisodesFromSeries(element) { + const seasonId = element.getHref; + const res = await this.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) { const titleAnchor = element.selectFirst("td.seasonEpisodeTitle a"); @@ -110,114 +124,57 @@ class DefaultExtension extends MProvider { } return name && url ? { name, url } : {}; } - getRandomString(length) { - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; - let result = ""; - for (let i = 0; i < length; i++) { - const random = Math.floor(Math.random() * 61); - result += chars[random]; - } - return result; - } - async doodExtractor(url, quality) { - let response = await new Client({ 'useDartHttpClient': true, "followRedirects": false }).get(url); - while("location" in response.headers) { - response = await new Client({ 'useDartHttpClient': true, "followRedirects": false }).get(response.headers.location); - } - const newUrl = response.request.url; - const doodhost = newUrl.match(/https:\/\/(.*?)\//, newUrl)[0].slice(8, -1); - const md5 = response.body.match(/'\/pass_md5\/(.*?)',/, newUrl)[0].slice(11, -2); - const token = md5.substring(md5.lastIndexOf("/") + 1); - const expiry = new Date().valueOf(); - const randomString = this.getRandomString(10); - - response = await new Client().get(`https://${doodhost}/pass_md5/${md5}`, {"Referer": newUrl}); - const videoUrl = `${response.body}${randomString}?token=${token}&expiry=${expiry}`; - const headers = { "User-Agent": "Mangayomi", "Referer": doodhost }; - return [{ url: videoUrl, originalUrl: videoUrl, headers: headers, quality }]; - } - async vidozaExtractor(url, quality) { - let response = await new Client({ 'useDartHttpClient': true, "followRedirects": true }).get(url); - const videoUrl = response.body.match(/https:\/\/\S*\.mp4/)[0]; - return [{ url: videoUrl, originalUrl: videoUrl, quality }]; - } async getVideoList(url) { const baseUrl = this.source.baseUrl; - const res = await new Client().get(baseUrl + url); + const res = await this.client.get(baseUrl + url, { + 'Accept': '*/*', + 'Referer': baseUrl + url, + 'Priority': 'u=0, i', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0' + }); const document = new Document(res.body); - const redirectlink = document.select("ul.row li"); - const preference = new SharedPreferences(); - const hosterSelection = preference.get("hoster_selection_new"); + let promises = []; const videos = []; - for (const element of redirectlink) { - try { + + const redirectsElements = document.select("ul.row li"); + const hosterSelection = new SharedPreferences().get("hoster_selection_new"); + const dartClient = new Client({ 'useDartHttpClient': true, "followRedirects": false }); + + for (const element of redirectsElements) { + const host = element.selectFirst("a h4").text; + + if (hosterSelection.includes(host)) { 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 location = (await new Client({ 'useDartHttpClient': true, "followRedirects": false }).get(redirectgs)).headers.location; - const quality = `${language} - Streamtape`; - const vids = await streamTapeExtractor(location, quality); - for (const vid of vids) { - videos.push(vid); - } - } else if (hoster == "VOE" && hosterSelection.includes("VOE")) { - const location = (await new Client({ 'useDartHttpClient': true, "followRedirects": false }).get(redirectgs)).headers.location; - const quality = `${language} - `; - const vids = await voeExtractor(location, quality); - for (const vid of vids) { - videos.push(vid); - } - } else if (hoster == "Vidoza" && hosterSelection.includes("Vidoza")) { - const location = (await new Client({ 'useDartHttpClient': true, "followRedirects": false }).get(redirectgs)).headers.location; - const quality = `${language} - Vidoza`; - const vids = await this.vidozaExtractor(location, quality); - for (const vid of vids) { - videos.push(vid); - } - } else if (hoster == "Doodstream" && hosterSelection.includes("Doodstream")) { - const location = (await new Client({ 'useDartHttpClient': true, "followRedirects": false }).get(redirectgs)).headers.location; - const quality = `${language} - Doodstream`; - const vids = await this.doodExtractor(location, quality); - for (const vid of vids) { - videos.push(vid); - } - } - } catch (_) { - + const lang = (langkey == 1 || langkey == 3) ? 'Deutscher' : 'Englischer'; + const type = (langkey == 1) ? 'Dub' : 'Sub'; + const redirect = baseUrl + element.selectFirst("a.watchEpisode").attr("href"); + promises.push((async (redirect, lang, type, host) => { + const location = (await dartClient.get(redirect)).headers.location; + return await extractAny(location, host.toLowerCase(), lang, type, host); + })(redirect, lang, type, host)); + } + } + for (const p of (await Promise.allSettled(promises))) { + if (p.status == 'fulfilled') { + videos.push.apply(videos, p.value); } } return this.sortVideos(videos); } sortVideos(videos) { const preference = new SharedPreferences(); - const hoster = preference.get("preferred_hoster_new"); - const subPreference = preference.get("preferred_lang"); + const hoster = RegExp(preference.get("preferred_hoster_new")); + const lang = RegExp(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; - } + let qualityMatchA = hoster.test(a.quality) * lang.test(a.quality); + let qualityMatchB = hoster.test(b.quality) * lang.test(b.quality); return qualityMatchB - qualityMatchA; }); return videos; } getSourcePreferences() { + const hosterOptions = ["Streamtape", "VOE", "Vidoza", "Doodstream"]; + const languageOptions = ["Deutscher Sub", "Deutscher Dub", "Englischer Sub"]; return [ { "key": "preferred_lang", @@ -225,16 +182,8 @@ class DefaultExtension extends MProvider { "title": "Bevorzugte Sprache", "summary": "", "valueIndex": 0, - "entries": [ - "Deutscher Sub", - "Deutscher Dub", - "Englischer Sub" - ], - "entryValues": [ - "Deutscher Sub", - "Deutscher Dub", - "Englischer Sub" - ] + "entries": languageOptions, + "entryValues": languageOptions } }, { @@ -243,16 +192,8 @@ class DefaultExtension extends MProvider { "title": "Standard-Hoster", "summary": "", "valueIndex": 0, - "entries": [ - "Streamtape", - "VOE", - "Vidoza", "Doodstream" - ], - "entryValues": [ - "Streamtape", - "VOE", - "Vidoza", "Doodstream" - ] + "entries": hosterOptions, + "entryValues": hosterOptions } }, { @@ -260,23 +201,73 @@ class DefaultExtension extends MProvider { "multiSelectListPreference": { "title": "Hoster auswählen", "summary": "", - "entries": [ - "Streamtape", - "VOE", - "Vidoza", "Doodstream" - ], - "entryValues": [ - "Streamtape", - "VOE", - "Vidoza", "Doodstream" - ], - "values": [ - "Streamtape", - "VOE", - "Vidoza", "Doodstream" - ] + "entries": hosterOptions, + "entryValues": hosterOptions, + "values": hosterOptions } } ]; } } + +async function doodExtractor(url) { + const dartClient = new Client({ 'useDartHttpClient': true, "followRedirects": false }); + let response = await dartClient.get(url); + while ("location" in response.headers) { + response = await dartClient.get(response.headers.location); + } + const newUrl = response.request.url; + const doodhost = newUrl.match(/https:\/\/(.*?)\//, newUrl)[0].slice(8, -1); + const md5 = response.body.match(/'\/pass_md5\/(.*?)',/, newUrl)[0].slice(11, -2); + const token = md5.substring(md5.lastIndexOf("/") + 1); + const expiry = new Date().valueOf(); + const randomString = getRandomString(10); + + response = await new Client().get(`https://${doodhost}/pass_md5/${md5}`, { "Referer": newUrl }); + const videoUrl = `${response.body}${randomString}?token=${token}&expiry=${expiry}`; + const headers = { "User-Agent": "Mangayomi", "Referer": doodhost }; + return [{ url: videoUrl, originalUrl: videoUrl, headers: headers, quality: '' }]; +} + +async function vidozaExtractor(url) { + let response = await new Client({ 'useDartHttpClient': true, "followRedirects": true }).get(url); + const videoUrl = response.body.match(/https:\/\/\S*\.mp4/)[0]; + return [{ url: videoUrl, originalUrl: videoUrl, quality: '' }]; +} + +_streamTapeExtractor = streamTapeExtractor; +streamTapeExtractor = async (url) => { + return await _streamTapeExtractor(url, ''); +} + +_voeExtractor = voeExtractor; +voeExtractor = async (url) => { + return (await _voeExtractor(url, '')).map(v => { + v.quality = v.quality.replace(/Voe: (\d+p?)/i, '$1'); + return v; + }); +} + +async function extractAny(link, method, lang, type, host) { + const m = extractAny.methods[method]; + return (!m) ? [] : (await m(link)).map(v => { + v.quality = v.quality ? `${lang} ${type} ${v.quality} ${host}` : `${lang} ${type} ${host}`; + return v; + }); +}; + +extractAny.methods = { + 'doodstream': doodExtractor, + 'streamtape': streamTapeExtractor, + 'vidoza': vidozaExtractor, + 'voe': voeExtractor +}; + +function getRandomString(length) { + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; + const charArray = new Array(length); + for (let i = 0; i < length; i++) { + charArray[i] = chars[Math.floor(Math.random() * chars.length)]; + } + return charArray.join(""); +}