📦 NEW: Add series and captions

This commit is contained in:
cloud 2022-12-04 13:24:40 -07:00
parent 3b1df3a417
commit a2c8b9f219
4 changed files with 96 additions and 51 deletions

View file

@ -14,6 +14,7 @@
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"srt-webvtt": "^2.0.0",
"unpacker": "^1.0.1" "unpacker": "^1.0.1"
}, },
"scripts": { "scripts": {

View file

@ -1,4 +1,6 @@
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 TMDB_API_KEY = "9a31326bc179b029cd4513c489628e79";
export const OMDB_API_KEY = "aa0937c0"; 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";

View file

@ -8,8 +8,9 @@ import {
MWMediaSeasons, MWMediaSeasons,
MWProviderMediaResult, MWProviderMediaResult,
} from "providers/types"; } from "providers/types";
import { CORS_PROXY_URL } from "mw_constants"; import { CORS_PROXY_URL, TMDB_API_KEY } from "mw_constants";
import { customAlphabet } from "nanoid"; import { customAlphabet } from "nanoid";
import toWebVTT from "srt-webvtt";
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
const nanoid = customAlphabet("0123456789abcdef", 32); const nanoid = customAlphabet("0123456789abcdef", 32);
@ -94,9 +95,8 @@ const get = (data: object, altApi = false) => {
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],
type: [MWMediaType.MOVIE], displayName: "SuperStream",
displayName: "superstream",
async getMediaFromPortable( async getMediaFromPortable(
media: MWPortableMedia, media: MWPortableMedia,
@ -147,8 +147,8 @@ export const superStreamScraper: MWMediaProvider = {
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 === "movie") {
@ -171,7 +171,29 @@ export const superStreamScraper: MWMediaProvider = {
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");
return { url: hdQuality.path, type: "mp4", captions: [] }; const subtitleApiQuery = {
fid: hdQuality.fid,
uid: "",
module: "Movie_srt_list_v2",
mid: media.mediaId,
};
const subtitleRes = (await get(subtitleApiQuery).then((r) => r.json()))
.data;
const mappedCaptions = await Promise.all(
subtitleRes.list.map(async (subtitle: any) => {
const captionBlob = await fetch(
`${CORS_PROXY_URL}${subtitle.subtitles[0].file_path}`,
).then((captionRes) => captionRes.blob()); // cross-origin bypass
const captionUrl = await toWebVTT(captionBlob); // convert to vtt so it's playable
return {
id: subtitle.language,
url: captionUrl,
label: subtitle.language,
};
}),
);
return { url: hdQuality.path, type: "mp4", captions: mappedCaptions };
} }
const apiQuery = { const apiQuery = {
@ -188,49 +210,64 @@ export const superStreamScraper: MWMediaProvider = {
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");
return { url: hdQuality.path, type: "mp4", captions: [] }; const subtitleApiQuery = {
fid: hdQuality.fid,
uid: "",
module: "TV_srt_list_v2",
episode: media.episodeId,
tid: media.mediaId,
season: media.seasonId,
};
const subtitleRes = (await get(subtitleApiQuery).then((r) => r.json()))
.data;
const mappedCaptions = await Promise.all(
subtitleRes.list.map(async (subtitle: any) => {
const captionBlob = await fetch(
`${CORS_PROXY_URL}${subtitle.subtitles[0].file_path}`,
).then((captionRes) => captionRes.blob()); // cross-origin bypass
const captionUrl = await toWebVTT(captionBlob); // convert to vtt so it's playable
return {
id: subtitle.language,
url: captionUrl,
label: subtitle.language,
};
}),
);
return { url: hdQuality.path, type: "mp4", captions: mappedCaptions };
}, },
// async getSeasonDataFromMedia( async getSeasonDataFromMedia(
// media: MWPortableMedia, media: MWPortableMedia,
// ): Promise<MWMediaSeasons> { ): Promise<MWMediaSeasons> {
// const allSeasonEpisodes = []; 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 = (
// allSeasonEpisodes.push(...detailRes.episode); 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}`,
).then((r) => r.json())
).results[0];
const showDetails = await fetch(
`https://api.themoviedb.org/3/tv/${firstSearchResult.id}?api_key=${TMDB_API_KEY}`,
).then((r) => r.json());
// if (detailRes.seasons.length > 1) { return {
// for (const season of detailRes.seasons.slice(1)) { seasons: showDetails.seasons.map((season: any) => ({
// const seasonApiQuery = { sort: season.season_number,
// module: "TV_detail_1", id: season.season_number.toString(),
// season: season.toString(), type: season.season_number === 0 ? "special" : "season",
// display_all: "1", episodes: Array.from({ length: season.episode_count }).map(
// tid: media.mediaId, (_, epNum) => ({
// }; title: `Episode ${epNum + 1}`,
// const seasonRes = ( sort: epNum + 1,
// await get(seasonApiQuery, true).then((r) => r.json()) id: (epNum + 1).toString(),
// ).data; episodeNumber: epNum + 1,
// allSeasonEpisodes.push(...seasonRes.episode); }),
// } ),
// } })),
};
// return { },
// seasons: detailRes.season.map((season: number) => ({
// sort: season,
// id: season.toString(),
// type: season === 0 ? "special" : "season",
// episodes: detailRes.episode
// .filter((episode: any) => episode.season === season)
// .map((episode: any) => ({
// title: episode.title,
// sort: episode.episode,
// id: episode.episode.toString(),
// episodeNumber: episode.episode,
// })),
// })),
// };
// },
}; };

View file

@ -7794,6 +7794,11 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
srt-webvtt@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/srt-webvtt/-/srt-webvtt-2.0.0.tgz#debd2f56dd2b6600894caa11bb78893e5fc6509b"
integrity sha512-G2Z7/Jf2NRKrmLYNSIhSYZZYE6OFlKXFp9Au2/zJBKgrioUzmrAys1x7GT01dwl6d2sEnqr5uahEIOd0JW/Rbw==
stable@^0.1.8: stable@^0.1.8:
version "0.1.8" version "0.1.8"
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"