diff --git a/mapple/mapple.js b/mapple/mapple.js index 29b6272..c634434 100644 --- a/mapple/mapple.js +++ b/mapple/mapple.js @@ -189,62 +189,56 @@ async function extractEpisodes(url) { } } +async function extractNextActionIdentifier(watchUrl) { + const htmlResponse = await soraFetch(watchUrl); + const htmlText = await htmlResponse.text(); + + const layoutMatch = htmlText.match(/]*src="([^"]*app\/watch\/movie\/[^"]*layout-[^"]*\.js)"[^>]*><\/script>]*src="([^"]*\.js)"[^>]*><\/script>]*src="[^"]*app\/watch\/movie\/[^"]*layout-[^"]*\.js"/); + + if (!beforeLayoutMatch || !beforeLayoutMatch[1]) { + throw new Error("error 2"); + } + + let targetUrl = beforeLayoutMatch[1]; + if (targetUrl.startsWith('/_next/')) { + targetUrl = 'https://mapple.uk' + targetUrl; + } else if (!targetUrl.startsWith('http')) { + targetUrl = 'https://mapple.uk/' + targetUrl; + } + + try { + const response = await soraFetch(targetUrl); + const text = await response.text(); + + let actionMatch = text.match(/createServerReference\)\("([a-f0-9]{40,})"[^"]*"getStreamUrl/); + if (!actionMatch) { + actionMatch = text.match(/createServerReference\)\("([a-f0-9]{40,})"/); + } + if (!actionMatch) { + actionMatch = text.match(/"([a-f0-9]{40,})"[^"]*"getStreamUrl/); + } + + if (actionMatch && actionMatch[1]) { + return actionMatch[1]; + } + } catch (e) { + throw new Error("error 3: " + e); + } + + throw new Error("error 4"); +} + async function extractStreamUrl(ID) { const htmlResponse = await soraFetch("https://mapple.uk/watch/" + ID); const htmlText = await htmlResponse.text(); - const jsUrlRegex = /(?:src|href)="([^"]*\.js(?:\?[^"]*)?)"/g; - const jsUrls = []; - let match; - - while ((match = jsUrlRegex.exec(htmlText)) !== null) { - let jsUrl = match[1]; - if (jsUrl.startsWith('/_next/') || jsUrl.startsWith('/static/')) { - jsUrl = 'https://mapple.uk' + jsUrl; - } else if (!jsUrl.startsWith('http')) { - jsUrl = 'https://mapple.uk/' + jsUrl; - } - jsUrls.push(jsUrl); - } - - const uniqueJsUrls = [...new Set(jsUrls)]; - console.log("Found " + uniqueJsUrls.length + " unique JS files"); - - let actionIdentifier = null; - let foundPromiseResolver = null; - const foundPromise = new Promise((resolve) => { - foundPromiseResolver = resolve; - }); - - const searchPromises = uniqueJsUrls.map(async (url) => { - try { - if (actionIdentifier) return null; - const response = await soraFetch(url); - if (actionIdentifier) return null; - const text = await response.text(); - if (actionIdentifier) return null; - const actionMatch = text.match(/createServerReference\)\("([a-f0-9]{40,})"[^"]*"getStreamUrl/); - if (actionMatch && actionMatch[1] && !actionIdentifier) { - actionIdentifier = actionMatch[1]; - console.log("Found actionIdentifier in: " + url); - foundPromiseResolver(actionIdentifier); - return actionIdentifier; - } - return null; - } catch (e) { - console.log("Error fetching " + url + ": " + e); - return null; - } - }); - - await Promise.race([ - foundPromise, - Promise.all(searchPromises) - ]); - - if (!actionIdentifier) { - throw new Error("Failed to extract action identifier from any chunk file"); - } + const actionIdentifier = await extractNextActionIdentifier("https://mapple.uk/watch/" + ID); console.log("Action Identifier: " + actionIdentifier);