diff --git a/src/providers/embeds/upcloud.ts b/src/providers/embeds/upcloud.ts index d2be1f9..29ff0c4 100644 --- a/src/providers/embeds/upcloud.ts +++ b/src/providers/embeds/upcloud.ts @@ -24,6 +24,34 @@ function isJSON(json: string) { } } +/* +example script segment: +switch(I9){case 0x0:II=X,IM=t;break;case 0x1:II=b,IM=D;break;case 0x2:II=x,IM=f;break;case 0x3:II=S,IM=j;break;case 0x4:II=U,IM=G;break;case 0x5:II=partKeyStartPosition_5,IM=partKeyLength_5;} +*/ +function extractKey(script: string): [number, number][] | null { + const startOfSwitch = script.lastIndexOf('switch'); + const endOfCases = script.indexOf('partKeyStartPosition'); + const switchBody = script.slice(startOfSwitch, endOfCases); + + const nums: [number, number][] = []; + const matches = switchBody.matchAll(/:[a-zA-Z]+=([a-zA-Z]+),[a-zA-Z]+=([a-zA-Z]+);/g); + for (const match of matches) { + const innerNumbers: number[] = []; + for (const varMatch of [match[1], match[2]]) { + const regex = new RegExp(`${varMatch}=0x([a-zA-Z0-9]+)`, 'g'); + const varMatches = [...script.matchAll(regex)]; + const lastMatch = varMatches[varMatches.length - 1]; + if (!lastMatch) return null; + const number = parseInt(lastMatch[1], 16); + innerNumbers.push(number); + } + + nums.push([innerNumbers[0], innerNumbers[1]]); + } + + return nums; +} + export const upcloudScraper = makeEmbed({ id: 'upcloud', name: 'UpCloud', @@ -45,20 +73,22 @@ export const upcloudScraper = makeEmbed({ let sources: { file: string; type: string } | null = null; if (!isJSON(streamRes.sources)) { - const decryptionKey = JSON.parse( - await ctx.proxiedFetcher(`https://raw.githubusercontent.com/enimax-anime/key/e4/key.txt`), - ) as [number, number][]; + const scriptJs = await ctx.proxiedFetcher(`https://rabbitstream.net/js/player/prod/e4-player.min.js`); + const decryptionKey = extractKey(scriptJs); + if (!decryptionKey) throw new Error('Key extraction failed'); let extractedKey = ''; - const sourcesArray = streamRes.sources.split(''); - for (const index of decryptionKey) { - for (let i: number = index[0]; i < index[1]; i += 1) { - extractedKey += streamRes.sources[i]; - sourcesArray[i] = ''; - } - } + let strippedSources = streamRes.sources; + let totalledOffset = 0; + decryptionKey.forEach(([a, b]) => { + const start = a + totalledOffset; + const end = start + b; + extractedKey += streamRes.sources.slice(start, end); + strippedSources = strippedSources.replace(streamRes.sources.substring(start, end), ''); + totalledOffset += b; + }); - const decryptedStream = AES.decrypt(sourcesArray.join(''), extractedKey).toString(enc.Utf8); + const decryptedStream = AES.decrypt(strippedSources, extractedKey).toString(enc.Utf8); const parsedStream = JSON.parse(decryptedStream)[0]; if (!parsedStream) throw new Error('No stream found'); sources = parsedStream;