7 changed files with 7777 additions and 8022 deletions
@ -1,3 +1,4 @@ |
|||||||
export const CORS_PROXY_URL = "https://proxy-1.movie-web.workers.dev/?destination="; |
export const CORS_PROXY_URL = "https://proxy-1.movie-web.workers.dev/?destination="; |
||||||
|
export const OMDB_API_KEY = "aa0937c0"; |
||||||
export const DISCORD_LINK = "https://discord.gg/Jhqt4Xzpfb"; |
export const DISCORD_LINK = "https://discord.gg/Jhqt4Xzpfb"; |
||||||
export const GITHUB_LINK = "https://github.com/JamesHawkinss/movie-web"; |
export const GITHUB_LINK = "https://github.com/JamesHawkinss/movie-web"; |
||||||
|
@ -0,0 +1,96 @@ |
|||||||
|
import { |
||||||
|
MWMediaProvider, |
||||||
|
MWMediaType, |
||||||
|
MWPortableMedia, |
||||||
|
MWMediaStream, |
||||||
|
MWQuery, |
||||||
|
MWMediaSeasons, |
||||||
|
MWProviderMediaResult |
||||||
|
} from "providers/types"; |
||||||
|
|
||||||
|
import { CORS_PROXY_URL } from "mw_constants"; |
||||||
|
import { unpack } from "unpacker"; |
||||||
|
import CryptoJS from "crypto-js"; |
||||||
|
|
||||||
|
const format = { |
||||||
|
stringify: (cipher: any) => { |
||||||
|
const ct = cipher.ciphertext.toString(CryptoJS.enc.Base64); |
||||||
|
const iv = cipher.iv.toString() || ""; |
||||||
|
const salt = cipher.salt.toString() || ""; |
||||||
|
return JSON.stringify({ |
||||||
|
ct, |
||||||
|
iv, |
||||||
|
salt, |
||||||
|
}); |
||||||
|
}, |
||||||
|
parse: (jsonStr: string) => { |
||||||
|
const json = JSON.parse(jsonStr); |
||||||
|
const ciphertext = CryptoJS.enc.Base64.parse(json.ct); |
||||||
|
const iv = CryptoJS.enc.Hex.parse(json.iv) || ""; |
||||||
|
const salt = CryptoJS.enc.Hex.parse(json.s) || ""; |
||||||
|
|
||||||
|
const cipher = CryptoJS.lib.CipherParams.create({ |
||||||
|
ciphertext, |
||||||
|
iv, |
||||||
|
salt, |
||||||
|
}); |
||||||
|
return cipher; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
export const gDrivePlayerScraper: MWMediaProvider = { |
||||||
|
id: "gdriveplayer", |
||||||
|
enabled: true, |
||||||
|
type: [MWMediaType.MOVIE], |
||||||
|
displayName: "gdriveplayer", |
||||||
|
|
||||||
|
async getMediaFromPortable(media: MWPortableMedia): Promise<MWProviderMediaResult> { |
||||||
|
const res = await fetch(`${CORS_PROXY_URL}https://api.gdriveplayer.us/v1/imdb/${media.mediaId}`).then((d) => d.json()); |
||||||
|
|
||||||
|
return { |
||||||
|
...media, |
||||||
|
title: res.Title, |
||||||
|
year: res.Year, |
||||||
|
} as MWProviderMediaResult; |
||||||
|
}, |
||||||
|
|
||||||
|
async searchForMedia(query: MWQuery): Promise<MWProviderMediaResult[]> { |
||||||
|
const searchRes = await fetch(`${CORS_PROXY_URL}https://api.gdriveplayer.us/v1/movie/search?title=${query.searchQuery}`).then((d) => d.json()); |
||||||
|
|
||||||
|
const results: MWProviderMediaResult[] = searchRes.map((item: any) => ({ |
||||||
|
title: item.title, |
||||||
|
year: item.year, |
||||||
|
mediaId: item.imdb, |
||||||
|
})); |
||||||
|
|
||||||
|
return results; |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
async getStream(media: MWPortableMedia): Promise<MWMediaStream> { |
||||||
|
const streamRes = await fetch(`${CORS_PROXY_URL}https://database.gdriveplayer.us/player.php?imdb=${media.mediaId}`).then((d) => d.text()); |
||||||
|
const page = new DOMParser().parseFromString(streamRes, "text/html"); |
||||||
|
|
||||||
|
const script: HTMLElement | undefined = Array.from( |
||||||
|
page.querySelectorAll("script") |
||||||
|
).find((e) => e.textContent?.includes("eval")); |
||||||
|
|
||||||
|
if (!script || !script.textContent) { |
||||||
|
throw new Error("Could not find stream"); |
||||||
|
} |
||||||
|
|
||||||
|
/// NOTE: this code requires re-write, it's not safe
|
||||||
|
const data = unpack(script.textContent).split("var data=\\'")[1].split("\\'")[0].replace(/\\/g, ""); |
||||||
|
const decryptedData = unpack(CryptoJS.AES.decrypt(data, "alsfheafsjklNIWORNiolNIOWNKLNXakjsfwnBdwjbwfkjbJjkopfjweopjASoiwnrflakefneiofrt", { format }).toString(CryptoJS.enc.Utf8)); |
||||||
|
// eslint-disable-next-line
|
||||||
|
const sources = JSON.parse(JSON.stringify(eval(decryptedData.split("sources:")[1].split(",image")[0].replace(/\\/g, "").replace(/document\.referrer/g, "\"\"")))); |
||||||
|
const source = sources[sources.length - 1]; |
||||||
|
/// END
|
||||||
|
|
||||||
|
return { url: `https:${source.file}`, type: source.type, captions: [] }; |
||||||
|
}, |
||||||
|
|
||||||
|
async getSeasonDataFromMedia(media: MWPortableMedia): Promise<MWMediaSeasons> { |
||||||
|
return {} as MWMediaSeasons; |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,100 @@ |
|||||||
|
import { |
||||||
|
MWMediaProvider, |
||||||
|
MWMediaType, |
||||||
|
MWPortableMedia, |
||||||
|
MWMediaStream, |
||||||
|
MWQuery, |
||||||
|
MWMediaSeasons, |
||||||
|
MWProviderMediaResult |
||||||
|
} from "providers/types"; |
||||||
|
|
||||||
|
import { CORS_PROXY_URL, OMDB_API_KEY } from "mw_constants"; |
||||||
|
import { unpack } from "unpacker"; |
||||||
|
|
||||||
|
export const gomostreamScraper: MWMediaProvider = { |
||||||
|
id: "gomostream", |
||||||
|
enabled: true, |
||||||
|
type: [MWMediaType.MOVIE], |
||||||
|
displayName: "gomostream", |
||||||
|
|
||||||
|
async getMediaFromPortable(media: MWPortableMedia): Promise<MWProviderMediaResult> { |
||||||
|
const params = new URLSearchParams({ |
||||||
|
apikey: OMDB_API_KEY, |
||||||
|
i: media.mediaId, |
||||||
|
type: media.mediaType |
||||||
|
}); |
||||||
|
|
||||||
|
const res = await fetch( |
||||||
|
`${CORS_PROXY_URL}http://www.omdbapi.com/?${encodeURIComponent(params.toString())}`, |
||||||
|
).then(d => d.json()) |
||||||
|
|
||||||
|
return { |
||||||
|
...media, |
||||||
|
title: res.Title, |
||||||
|
year: res.Year |
||||||
|
} as MWProviderMediaResult; |
||||||
|
}, |
||||||
|
|
||||||
|
async searchForMedia(query: MWQuery): Promise<MWProviderMediaResult[]> { |
||||||
|
const term = query.searchQuery.toLowerCase(); |
||||||
|
|
||||||
|
const params = new URLSearchParams({ |
||||||
|
apikey: OMDB_API_KEY, |
||||||
|
s: term, |
||||||
|
type: query.type |
||||||
|
}); |
||||||
|
const searchRes = await fetch( |
||||||
|
`${CORS_PROXY_URL}http://www.omdbapi.com/?${encodeURIComponent(params.toString())}`, |
||||||
|
).then(d => d.json()) |
||||||
|
|
||||||
|
const results: MWProviderMediaResult[] = searchRes.Search.map((d: any) => ({ |
||||||
|
title: d.Title, |
||||||
|
year: d.Year, |
||||||
|
mediaId: d.imdbID |
||||||
|
} as MWProviderMediaResult)); |
||||||
|
|
||||||
|
return results; |
||||||
|
}, |
||||||
|
|
||||||
|
async getStream(media: MWPortableMedia): Promise<MWMediaStream> { |
||||||
|
const type = media.mediaType === MWMediaType.SERIES ? 'show' : media.mediaType; |
||||||
|
const res1 = await fetch(`${CORS_PROXY_URL}https://gomo.to/${type}/${media.mediaId}`).then((d) => d.text()); |
||||||
|
if (res1 === "Movie not available." || res1 === "Episode not available.") throw new Error(res1); |
||||||
|
|
||||||
|
const tc = res1.match(/var tc = '(.+)';/)?.[1] || ""; |
||||||
|
const _token = res1.match(/"_token": "(.+)",/)?.[1] || ""; |
||||||
|
|
||||||
|
const fd = new FormData() |
||||||
|
fd.append('tokenCode', tc) |
||||||
|
fd.append('_token', _token) |
||||||
|
|
||||||
|
const src = await fetch(`${CORS_PROXY_URL}https://gomo.to/decoding_v3.php`, { |
||||||
|
method: "POST", |
||||||
|
body: fd, |
||||||
|
headers: { |
||||||
|
'x-token': `${tc.slice(5, 13).split("").reverse().join("")}13574199` |
||||||
|
} |
||||||
|
}).then((d) => d.json()); |
||||||
|
|
||||||
|
const embedUrl = src.find((url: string) => url.includes('gomo.to')); |
||||||
|
const res2 = await fetch(`${CORS_PROXY_URL}${embedUrl}`).then((d) => d.text()); |
||||||
|
|
||||||
|
const res2DOM = new DOMParser().parseFromString(res2, "text/html"); |
||||||
|
if (res2DOM.body.innerText === "File was deleted") throw new Error("File was deleted"); |
||||||
|
|
||||||
|
const script = res2DOM.querySelectorAll("script")[8].innerHTML; |
||||||
|
const unpacked = unpack(script).split(''); |
||||||
|
unpacked.splice(0, 43); |
||||||
|
const index = unpacked.findIndex((e) => e === '"'); |
||||||
|
const streamUrl = unpacked.slice(0, index).join(''); |
||||||
|
|
||||||
|
const streamType = streamUrl.split('.').at(-1); |
||||||
|
if (streamType !== "mp4" && streamType !== "m3u8") throw new Error("Unsupported stream type"); |
||||||
|
|
||||||
|
return { url: streamUrl, type: streamType, captions: [] }; |
||||||
|
}, |
||||||
|
|
||||||
|
async getSeasonDataFromMedia(media: MWPortableMedia): Promise<MWMediaSeasons> { |
||||||
|
return {} as MWMediaSeasons; |
||||||
|
} |
||||||
|
}; |
Loading…
Reference in new issue