diff --git a/verseriesonline/verseriesonline.js b/verseriesonline/verseriesonline.js index c55d121..2f17e25 100644 --- a/verseriesonline/verseriesonline.js +++ b/verseriesonline/verseriesonline.js @@ -1,11 +1,11 @@ async function searchResults(keyword) { const urls = [ - `https://www.verseriesonline.net/recherche?q=${encodeURIComponent(keyword)}`, - `https://www.verseriesonline.net/recherche?q=${encodeURIComponent(keyword)}&page=2`, - `https://www.verseriesonline.net/recherche?q=${encodeURIComponent(keyword)}&page=3`, - `https://www.verseriesonline.net/recherche?q=${encodeURIComponent(keyword)}&page=4` + `https://verseriesonline.net/buscar?q=${encodeURIComponent(keyword)}`, + `https://verseriesonline.net/buscar?q=${encodeURIComponent(keyword)}&page=2`, + `https://verseriesonline.net/buscar?q=${encodeURIComponent(keyword)}&page=3`, + `https://verseriesonline.net/buscar?q=${encodeURIComponent(keyword)}&page=4` ]; - const regex = /
.*?]+href="([^"]+)"[^>]*>.*?]+src="([^"]+)"[^>]*>.*?
]*>.*?]+title="([^"]+)"/gs; + const regex = /
.*?]+href="([^"]+)"[^>]*>.*?]+data-src="([^"]+)"[^>]*>.*?]*>([^<]+)<\/a>/gs; try { const fetchPromises = urls.map(url => fetchv2(url).then(r => r.text())); const htmls = await Promise.all(fetchPromises); @@ -15,8 +15,8 @@ async function searchResults(keyword) { while ((match = regex.exec(html)) !== null) { results.push({ href: match[1].trim(), - image: "https://www.verseriesonline.net" + match[2].trim(), - title: match[3].trim().replace("regarder ","") + image: "https://verseriesonline.net" + match[2].trim(), + title: match[3].trim() }); } regex.lastIndex = 0; @@ -36,7 +36,7 @@ async function extractDetails(url) { const response = await fetchv2(url); const html = await response.text(); - const regex = /
.*?(.*?)<\/span>/s; + const regex = /
[\s\S]*?

(.*?)<\/p>/s; const match = regex.exec(html); const description = match ? match[1].trim() : "N/A"; @@ -61,31 +61,17 @@ async function extractEpisodes(url) { const response = await fetchv2(url); const html = await response.text(); - const seasonRegex = /.*?

temporada (\d+)<\/div>/gs; - const seasons = []; - let seasonMatch; - while ((seasonMatch = seasonRegex.exec(html)) !== null) { - seasons.push({ - url: seasonMatch[1].trim(), - number: parseInt(seasonMatch[2], 10) + const episodeRegex = /]*>[\s\S]*?T\s*(\d+)<\/span>\s*E\s*(\d+)<\/span>/g; + let match; + + while ((match = episodeRegex.exec(html)) !== null) { + results.push({ + season: parseInt(match[2], 10), + href: match[1].trim(), + number: parseInt(match[3], 10) }); } - await Promise.all(seasons.map(async (season) => { - const res = await fetchv2(season.url); - const seasonHtml = await res.text(); - - const episodeRegex = /.*?CapĂ­tulo (\d+)<\/span>/gs; - let epMatch; - while ((epMatch = episodeRegex.exec(seasonHtml)) !== null) { - results.push({ - season: season.number, - href: epMatch[1].trim(), - number: parseInt(epMatch[2], 10) - }); - } - })); - results.sort((a, b) => { if (a.season !== b.season) { return a.season - b.season; @@ -109,13 +95,13 @@ async function extractStreamUrl(url) { const response = await fetchv2(url); const html = await response.text(); - const blockRegex = /
]*data-hash="([^"]+)"[^>]*>([\s\S]*?)<\/div>/g; let hash = null; + const blockRegex = /]*class="play-option"[^>]*data-hash="([^"]+)"[^>]*>[\s\S]*?streamwish\.to[\s\S]*?<\/a>/g; let blockMatch; while ((blockMatch = blockRegex.exec(html)) !== null) { - const blockContent = blockMatch[2]; - if (/class="serv"[^>]*>uqload<\/span>/.test(blockContent)) { - hash = blockMatch[1].trim(); + const hashMatch = blockMatch[0].match(/data-hash="([^"]+)"/); + if (hashMatch) { + hash = hashMatch[1].trim(); break; } } @@ -127,21 +113,22 @@ async function extractStreamUrl(url) { console.log("Hash:"+ hash); console.log("Token:"+ token); - const embedResponse = await fetchv2("https://www.verseriesonline.net/hashembedlink", {}, "POST", `hash=${encodeURIComponent(hash)}&_token=${encodeURIComponent(token)}`); + const embedResponse = await fetchv2("https://www.verseriesonline.net/hashembedlink", { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}, "POST", `hash=${encodeURIComponent(hash)}&_token=${encodeURIComponent(token)}`); const embedJson = await embedResponse.json(); - const uqloadUrl = embedJson.link; + console.log("Embed JSON:"+ JSON.stringify(embedJson)); + const embedUrl = embedJson.link; - const someHtml = await fetchv2(uqloadUrl); + const someHtml = await fetchv2(embedUrl); const someText = await someHtml.text(); - const finalUrl = await uqloadExtractor(someText, uqloadUrl); + const finalUrl = await streamwishExtractor(someText, embedUrl); const streamObj = { streams: [ { title: "Server 1", streamUrl: finalUrl, headers: { - referer: "https://uqload.cx/" + referer: "" } } ], @@ -156,20 +143,129 @@ async function extractStreamUrl(url) { /* SCHEME START */ /** - * @name uqloadExtractor - * @author scigward + * @name streamwishExtractor + * @author Ibro */ -async function uqloadExtractor(html, embedUrl) { - try { - const match = html.match(/sources:\s*\[\s*"([^"]+\.mp4)"\s*\]/); - const videoSrc = match ? match[1] : ""; - return videoSrc; - } catch (error) { - console.log("uqloadExtractor error:", error.message); - return null; +async function streamwishExtractor(data, url = null) { + const obfuscatedScript = data.match(/]*>\s*(eval\(function\(p,a,c,k,e,d.*?\)[\s\S]*?)<\/script>/); + + const unpackedScript = unpack(obfuscatedScript[1]); + + const m3u8Match = unpackedScript.match(/file:"(https?:\/\/.*?\.m3u8.*?)"/); + + const m3u8Url = m3u8Match[1]; + console.log(m3u8Url); + return m3u8Url; +} + +//////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////// Helper Functions //////////////////////////// +////////////////////////////////////////////////////////////////////////////////////// + +/* +Credit to GitHub user @mnsrulz for Unpacker Node library + +Credits to @jcpiccodev for writing the full deobfuscator <3 +*/ + +/* REMOVE_START */ + +class Unbaser { + constructor(base) { + this.ALPHABET = { + 62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + 95: "' !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'", + }; + this.dictionary = {}; + this.base = base; + if (36 < base && base < 62) { + this.ALPHABET[base] = this.ALPHABET[base] || + this.ALPHABET[62].substr(0, base); + } + if (2 <= base && base <= 36) { + this.unbase = (value) => parseInt(value, base); + } + else { + try { + [...this.ALPHABET[base]].forEach((cipher, index) => { + this.dictionary[cipher] = index; + }); + } + catch (er) { + throw Error("Unsupported base encoding."); + } + this.unbase = this._dictunbaser; + } + } + _dictunbaser(value) { + let ret = 0; + [...value].reverse().forEach((cipher, index) => { + ret = ret + ((Math.pow(this.base, index)) * this.dictionary[cipher]); + }); + return ret; } } -/* SCHEME END */ +function detect(source) { + return source.replace(" ", "").startsWith("eval(function(p,a,c,k,e,"); +} +function unpack(source) { + let { payload, symtab, radix, count } = _filterargs(source); + if (count != symtab.length) { + throw Error("Malformed p.a.c.k.e.r. symtab."); + } + let unbase; + try { + unbase = new Unbaser(radix); + } + catch (e) { + throw Error("Unknown p.a.c.k.e.r. encoding."); + } + function lookup(match) { + const word = match; + let word2; + if (radix == 1) { + word2 = symtab[parseInt(word)]; + } + else { + word2 = symtab[unbase.unbase(word)]; + } + return word2 || word; + } + source = payload.replace(/\b\w+\b/g, lookup); + return _replacestrings(source); + function _filterargs(source) { + const juicers = [ + /}\('(.*)', *(\d+|\[\]), *(\d+), *'(.*)'\.split\('\|'\), *(\d+), *(.*)\)\)/, + /}\('(.*)', *(\d+|\[\]), *(\d+), *'(.*)'\.split\('\|'\)/, + ]; + for (const juicer of juicers) { + const args = juicer.exec(source); + if (args) { + let a = args; + if (a[2] == "[]") { + } + try { + return { + payload: a[1], + symtab: a[4].split("|"), + radix: parseInt(a[2]), + count: parseInt(a[3]), + }; + } + catch (ValueError) { + throw Error("Corrupted p.a.c.k.e.r. data."); + } + } + } + throw Error("Could not make sense of p.a.c.k.e.r data (unexpected code structure)"); + } + function _replacestrings(source) { + return source; + } +} +/* REMOVE_END */ + +/* SCHEME END */ \ No newline at end of file