👌 IMPROVE: Update code for review

This commit is contained in:
cloud 2022-12-05 07:49:00 -07:00
parent 8dcb954fdf
commit a442baa5e0
1 changed files with 227 additions and 225 deletions

View File

@ -1,12 +1,12 @@
// this scraper was taken from recloudstream/cloudstream-extensions. much love // this scraper was taken from recloudstream/cloudstream-extensions. much love
import { import {
MWMediaProvider, MWMediaProvider,
MWMediaType, MWMediaType,
MWPortableMedia, MWPortableMedia,
MWMediaStream, MWMediaStream,
MWQuery, MWQuery,
MWMediaSeasons, MWMediaSeasons,
MWProviderMediaResult, MWProviderMediaResult,
} from "providers/types"; } from "providers/types";
import { CORS_PROXY_URL, TMDB_API_KEY } from "mw_constants"; import { CORS_PROXY_URL, TMDB_API_KEY } from "mw_constants";
import { customAlphabet } from "nanoid"; import { customAlphabet } from "nanoid";
@ -22,27 +22,27 @@ const nanoid = customAlphabet("0123456789abcdef", 32);
const iv = atob("d0VpcGhUbiE="); const iv = atob("d0VpcGhUbiE=");
const key = atob("MTIzZDZjZWRmNjI2ZHk1NDIzM2FhMXc2"); const key = atob("MTIzZDZjZWRmNjI2ZHk1NDIzM2FhMXc2");
const apiUrls = [ const apiUrls = [
atob("aHR0cHM6Ly9zaG93Ym94LnNoZWd1Lm5ldC9hcGkvYXBpX2NsaWVudC9pbmRleC8="), atob("aHR0cHM6Ly9zaG93Ym94LnNoZWd1Lm5ldC9hcGkvYXBpX2NsaWVudC9pbmRleC8="),
atob("aHR0cHM6Ly9tYnBhcGkuc2hlZ3UubmV0L2FwaS9hcGlfY2xpZW50L2luZGV4Lw=="), atob("aHR0cHM6Ly9tYnBhcGkuc2hlZ3UubmV0L2FwaS9hcGlfY2xpZW50L2luZGV4Lw=="),
]; ];
const appKey = atob("bW92aWVib3g="); const appKey = atob("bW92aWVib3g=");
const appId = atob("Y29tLnRkby5zaG93Ym94"); const appId = atob("Y29tLnRkby5zaG93Ym94");
// cryptography stuff // cryptography stuff
const crypto = { const crypto = {
encrypt(str: string) { encrypt(str: string) {
return CryptoJS.TripleDES.encrypt(str, CryptoJS.enc.Utf8.parse(key), { return CryptoJS.TripleDES.encrypt(str, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv), iv: CryptoJS.enc.Utf8.parse(iv),
}).toString(); }).toString();
}, },
getVerify(str: string, str2: string, str3: string) { getVerify(str: string, str2: string, str3: string) {
if (str) { if (str) {
return CryptoJS.MD5( return CryptoJS.MD5(
CryptoJS.MD5(str2).toString() + str3 + str, CryptoJS.MD5(str2).toString() + str3 + str,
).toString(); ).toString();
} }
return null; return null;
}, },
}; };
// get expire time // get expire time
@ -50,224 +50,226 @@ const expiry = () => Math.floor(Date.now() / 1000 + 60 * 60 * 12);
// sending requests // sending requests
const get = (data: object, altApi = false) => { const get = (data: object, altApi = false) => {
const defaultData = { const defaultData = {
childmode: "0", childmode: "0",
app_version: "11.5", app_version: "11.5",
appid: appId, appid: appId,
lang: "en", lang: "en",
expired_date: `${expiry()}`, expired_date: `${expiry()}`,
platform: "android", platform: "android",
channel: "Website", channel: "Website",
}; };
const encryptedData = crypto.encrypt( const encryptedData = crypto.encrypt(
JSON.stringify({ JSON.stringify({
...defaultData, ...defaultData,
...data, ...data,
}), }),
); );
const appKeyHash = CryptoJS.MD5(appKey).toString(); const appKeyHash = CryptoJS.MD5(appKey).toString();
const verify = crypto.getVerify(encryptedData, appKey, key); const verify = crypto.getVerify(encryptedData, appKey, key);
const body = JSON.stringify({ const body = JSON.stringify({
app_key: appKeyHash, app_key: appKeyHash,
verify, verify,
encrypt_data: encryptedData, encrypt_data: encryptedData,
}); });
const b64Body = btoa(body); const b64Body = btoa(body);
const formatted = new URLSearchParams(); const formatted = new URLSearchParams();
formatted.append("data", b64Body); formatted.append("data", b64Body);
formatted.append("appid", "27"); formatted.append("appid", "27");
formatted.append("platform", "android"); formatted.append("platform", "android");
formatted.append("version", "129"); formatted.append("version", "129");
formatted.append("medium", "Website"); formatted.append("medium", "Website");
const requestUrl = altApi ? apiUrls[1] : apiUrls[0]; const requestUrl = altApi ? apiUrls[1] : apiUrls[0];
return fetch(`${CORS_PROXY_URL}${requestUrl}`, { return fetch(`${CORS_PROXY_URL}${requestUrl}`, {
method: "POST", method: "POST",
headers: { headers: {
Platform: "android", Platform: "android",
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
}, },
body: `${formatted.toString()}&token${nanoid()}`, body: `${formatted.toString()}&token${nanoid()}`,
}); });
}; };
export const superStreamScraper: MWMediaProvider = { export const superStreamScraper: MWMediaProvider = {
id: "superstream", id: "superstream",
enabled: true, enabled: true,
type: [MWMediaType.MOVIE, MWMediaType.SERIES], type: [MWMediaType.MOVIE, MWMediaType.SERIES],
displayName: "SuperStream", displayName: "SuperStream",
async getMediaFromPortable( async getMediaFromPortable(
media: MWPortableMedia, media: MWPortableMedia,
): Promise<MWProviderMediaResult> { ): Promise<MWProviderMediaResult> {
let apiQuery: any; let apiQuery: any;
if (media.episodeId) { if (media.mediaType == MWMediaType.MOVIE) {
apiQuery = { apiQuery = {
module: "TV_detail_1", module: "TV_detail_1",
display_all: "1", display_all: "1",
tid: media.mediaId, tid: media.mediaId,
}; };
} else { } else {
apiQuery = { apiQuery = {
module: "Movie_detail", module: "Movie_detail",
mid: media.mediaId, mid: media.mediaId,
}; };
} }
const detailRes = (await get(apiQuery, true).then((r) => r.json())).data; const detailRes = (await get(apiQuery, true).then((r) => r.json())).data;
return { return {
...media, ...media,
title: detailRes.title, title: detailRes.title,
year: detailRes.year, year: detailRes.year,
seasonCount: detailRes?.season?.length, seasonCount: detailRes?.season?.length,
} as MWProviderMediaResult; } as MWProviderMediaResult;
}, },
async searchForMedia(query: MWQuery): Promise<MWProviderMediaResult[]> { async searchForMedia(query: MWQuery): Promise<MWProviderMediaResult[]> {
const apiQuery = { const apiQuery = {
module: "Search3", module: "Search3",
page: "1", page: "1",
type: "all", type: "all",
keyword: query.searchQuery, keyword: query.searchQuery,
pagelimit: "20", pagelimit: "20",
}; };
const searchRes = (await get(apiQuery, true).then((r) => r.json())).data; const searchRes = (await get(apiQuery, true).then((r) => r.json())).data;
const movieResults: MWProviderMediaResult[] = (searchRes || []) const movieResults: MWProviderMediaResult[] = (searchRes || [])
.filter((item: any) => item.box_type === 1) .filter((item: any) => item.box_type === 1)
.map((item: any) => ({ .map((item: any) => ({
title: item.title, title: item.title,
year: item.year, year: item.year,
mediaId: item.id, mediaId: item.id,
})); }));
const seriesResults: MWProviderMediaResult[] = (searchRes || []) const seriesResults: MWProviderMediaResult[] = (searchRes || [])
.filter((item: any) => item.box_type === 2) .filter((item: any) => item.box_type === 2)
.map((item: any) => ({ .map((item: any) => ({
title: item.title, title: item.title,
year: item.year, year: item.year,
mediaId: item.id, mediaId: item.id,
seasonId: "1", seasonId: "1",
episodeId: "1", episodeId: "1",
})); }));
if (query.type === "movie") { if (query.type === MWMediaType.MOVIE) {
return movieResults; return movieResults;
} } else if (query.type === MWMediaType.SERIES) {
return seriesResults; return seriesResults;
}, }
return [];
},
async getStream(media: MWPortableMedia): Promise<MWMediaStream> { async getStream(media: MWPortableMedia): Promise<MWMediaStream> {
if (media.mediaType === MWMediaType.MOVIE) { if (media.mediaType === MWMediaType.MOVIE) {
const apiQuery = { const apiQuery = {
uid: "", uid: "",
module: "Movie_downloadurl_v3", module: "Movie_downloadurl_v3",
mid: media.mediaId, mid: media.mediaId,
oss: "1", oss: "1",
group: "", group: "",
}; };
const mediaRes = (await get(apiQuery).then((r) => r.json())).data; const mediaRes = (await get(apiQuery).then((r) => r.json())).data;
const hdQuality = const hdQuality =
mediaRes.list.find((quality: any) => quality.quality === "1080p") ?? mediaRes.list.find((quality: any) => quality.quality === "1080p") ??
mediaRes.list.find((quality: any) => quality.quality === "720p"); mediaRes.list.find((quality: any) => quality.quality === "720p");
const subtitleApiQuery = { const subtitleApiQuery = {
fid: hdQuality.fid, fid: hdQuality.fid,
uid: "", uid: "",
module: "Movie_srt_list_v2", module: "Movie_srt_list_v2",
mid: media.mediaId, mid: media.mediaId,
}; };
const subtitleRes = (await get(subtitleApiQuery).then((r) => r.json())) const subtitleRes = (await get(subtitleApiQuery).then((r) => r.json()))
.data; .data;
const mappedCaptions = await Promise.all( const mappedCaptions = await Promise.all(
subtitleRes.list.map(async (subtitle: any) => { subtitleRes.list.map(async (subtitle: any) => {
const captionBlob = await fetch( const captionBlob = await fetch(
`${CORS_PROXY_URL}${subtitle.subtitles[0].file_path}`, `${CORS_PROXY_URL}${subtitle.subtitles[0].file_path}`,
).then((captionRes) => captionRes.blob()); // cross-origin bypass ).then((captionRes) => captionRes.blob()); // cross-origin bypass
const captionUrl = await toWebVTT(captionBlob); // convert to vtt so it's playable const captionUrl = await toWebVTT(captionBlob); // convert to vtt so it's playable
return { return {
id: subtitle.language, id: subtitle.language,
url: captionUrl, url: captionUrl,
label: subtitle.language, label: subtitle.language,
}; };
}), }),
); );
return { url: hdQuality.path, type: "mp4", captions: mappedCaptions }; return { url: hdQuality.path, type: "mp4", captions: mappedCaptions };
} }
const apiQuery = { const apiQuery = {
uid: "", uid: "",
module: "TV_downloadurl_v3", module: "TV_downloadurl_v3",
episode: media.episodeId, episode: media.episodeId,
tid: media.mediaId, tid: media.mediaId,
season: media.seasonId, season: media.seasonId,
oss: "1", oss: "1",
group: "", group: "",
}; };
const mediaRes = (await get(apiQuery).then((r) => r.json())).data; const mediaRes = (await get(apiQuery).then((r) => r.json())).data;
const hdQuality = const hdQuality =
mediaRes.list.find((quality: any) => quality.quality === "1080p") ?? mediaRes.list.find((quality: any) => quality.quality === "1080p") ??
mediaRes.list.find((quality: any) => quality.quality === "720p"); mediaRes.list.find((quality: any) => quality.quality === "720p");
const subtitleApiQuery = { const subtitleApiQuery = {
fid: hdQuality.fid, fid: hdQuality.fid,
uid: "", uid: "",
module: "TV_srt_list_v2", module: "TV_srt_list_v2",
episode: media.episodeId, episode: media.episodeId,
tid: media.mediaId, tid: media.mediaId,
season: media.seasonId, season: media.seasonId,
}; };
const subtitleRes = (await get(subtitleApiQuery).then((r) => r.json())) const subtitleRes = (await get(subtitleApiQuery).then((r) => r.json()))
.data; .data;
const mappedCaptions = await Promise.all( const mappedCaptions = await Promise.all(
subtitleRes.list.map(async (subtitle: any) => { subtitleRes.list.map(async (subtitle: any) => {
const captionBlob = await fetch( const captionBlob = await fetch(
`${CORS_PROXY_URL}${subtitle.subtitles[0].file_path}`, `${CORS_PROXY_URL}${subtitle.subtitles[0].file_path}`,
).then((captionRes) => captionRes.blob()); // cross-origin bypass ).then((captionRes) => captionRes.blob()); // cross-origin bypass
const captionUrl = await toWebVTT(captionBlob); // convert to vtt so it's playable const captionUrl = await toWebVTT(captionBlob); // convert to vtt so it's playable
return { return {
id: subtitle.language, id: subtitle.language,
url: captionUrl, url: captionUrl,
label: subtitle.language, label: subtitle.language,
}; };
}), }),
); );
return { url: hdQuality.path, type: "mp4", captions: mappedCaptions }; return { url: hdQuality.path, type: "mp4", captions: mappedCaptions };
}, },
async getSeasonDataFromMedia( async getSeasonDataFromMedia(
media: MWPortableMedia, media: MWPortableMedia,
): Promise<MWMediaSeasons> { ): Promise<MWMediaSeasons> {
const apiQuery = { const apiQuery = {
module: "TV_detail_1", module: "TV_detail_1",
display_all: "1", display_all: "1",
tid: media.mediaId, tid: media.mediaId,
}; };
const detailRes = (await get(apiQuery, true).then((r) => r.json())).data; const detailRes = (await get(apiQuery, true).then((r) => r.json())).data;
const firstSearchResult = ( const firstSearchResult = (
await fetch( await fetch(
`https://api.themoviedb.org/3/search/tv?api_key=${TMDB_API_KEY}&language=en-US&page=1&query=${detailRes.title}&include_adult=false&first_air_date_year=${detailRes.year}`, `https://api.themoviedb.org/3/search/tv?api_key=${TMDB_API_KEY}&language=en-US&page=1&query=${detailRes.title}&include_adult=false&first_air_date_year=${detailRes.year}`,
).then((r) => r.json()) ).then((r) => r.json())
).results[0]; ).results[0];
const showDetails = await fetch( const showDetails = await fetch(
`https://api.themoviedb.org/3/tv/${firstSearchResult.id}?api_key=${TMDB_API_KEY}`, `https://api.themoviedb.org/3/tv/${firstSearchResult.id}?api_key=${TMDB_API_KEY}`,
).then((r) => r.json()); ).then((r) => r.json());
return { return {
seasons: showDetails.seasons.map((season: any) => ({ seasons: showDetails.seasons.map((season: any) => ({
sort: season.season_number, sort: season.season_number,
id: season.season_number.toString(), id: season.season_number.toString(),
type: season.season_number === 0 ? "special" : "season", type: season.season_number === 0 ? "special" : "season",
episodes: Array.from({ length: season.episode_count }).map( episodes: Array.from({ length: season.episode_count }).map(
(_, epNum) => ({ (_, epNum) => ({
title: `Episode ${epNum + 1}`, title: `Episode ${epNum + 1}`,
sort: epNum + 1, sort: epNum + 1,
id: (epNum + 1).toString(), id: (epNum + 1).toString(),
episodeNumber: epNum + 1, episodeNumber: epNum + 1,
}), }),
), ),
})), })),
}; };
}, },
}; };