|
|
|
@ -29,6 +29,32 @@ function isJSON(json: string) {
@@ -29,6 +29,32 @@ function isJSON(json: string) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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-Z0-9]+=([a-zA-Z0-9]+),[a-zA-Z0-9]+=([a-zA-Z0-9]+);/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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
registerEmbedScraper({ |
|
|
|
|
id: "upcloud", |
|
|
|
|
displayName: "UpCloud", |
|
|
|
@ -54,23 +80,31 @@ registerEmbedScraper({
@@ -54,23 +80,31 @@ registerEmbedScraper({
|
|
|
|
|
let sources: { file: string; type: string } | null = null; |
|
|
|
|
|
|
|
|
|
if (!isJSON(streamRes.sources)) { |
|
|
|
|
const decryptionKey = JSON.parse( |
|
|
|
|
await proxiedFetch<string>( |
|
|
|
|
`https://raw.githubusercontent.com/enimax-anime/key/e4/key.txt` |
|
|
|
|
) |
|
|
|
|
) as [number, number][]; |
|
|
|
|
const scriptJs = await proxiedFetch<string>( |
|
|
|
|
`https://rabbitstream.net/js/player/prod/e4-player.min.js`, |
|
|
|
|
{ |
|
|
|
|
responseType: "text" as any, |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
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(""), |
|
|
|
|
strippedSources, |
|
|
|
|
extractedKey |
|
|
|
|
).toString(enc.Utf8); |
|
|
|
|
const parsedStream = JSON.parse(decryptedStream)[0]; |
|
|
|
|