mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-29 17:36:06 +00:00
📦 NEW: Add series and captions
This commit is contained in:
parent
3b1df3a417
commit
a2c8b9f219
|
@ -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": {
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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,
|
|
||||||
// })),
|
|
||||||
// })),
|
|
||||||
// };
|
|
||||||
// },
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue