Compare commits

...

11 Commits

Author SHA1 Message Date
William Oldham
91757c0cda Update Dockerfile to use pnpm 8 2024-04-20 10:55:38 +01:00
William Oldham
6acb51e8a3 Use caret version for engines in line with NPM standard 2024-04-20 10:53:47 +01:00
William Oldham
fe0d2c91a4 Fix linting errors 2024-04-20 10:51:37 +01:00
William Oldham
e1b9393584 Upgrade all the packages 2024-04-20 10:50:17 +01:00
William Oldham
2d9bc0149f Add engines so CI doesn't use PNPM 9 2024-04-20 10:50:06 +01:00
William Oldham
9bd5f30f40 Merge pull request #1140 from movie-web/fix/#1118
fix tmdb 404 request
2024-04-20 10:37:58 +01:00
Jorrin
0a15bb2023 consistent returns 2024-04-20 11:36:38 +02:00
Jorrin
cfa3cfd072 check for undefined 2024-04-19 19:28:49 +02:00
Jorrin
5fbe5d1ff5 fix tmdb 404 request 2024-04-19 19:26:29 +02:00
William Oldham
4712d8fc5d Merge pull request #1122 from movie-web/fix/tmdb
Use vanilla AbortController for compatability
2024-04-15 20:13:55 +01:00
William Oldham
a9d80ddf24 Use vanilla AbortController for compat 2024-04-15 20:10:44 +01:00
6 changed files with 1264 additions and 2431 deletions

View File

@@ -2,7 +2,7 @@ FROM node:20-alpine as build
WORKDIR /app WORKDIR /app
ENV PNPM_HOME="/pnpm" ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH" ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable RUN npm i -g pnpm@8
COPY package.json ./ COPY package.json ./
COPY pnpm-lock.yaml ./ COPY pnpm-lock.yaml ./

View File

@@ -3,6 +3,10 @@
"version": "4.7.0", "version": "4.7.0",
"private": true, "private": true,
"homepage": "https://github.com/movie-web/movie-web", "homepage": "https://github.com/movie-web/movie-web",
"engines": {
"node": ">= 20",
"pnpm": "^8"
},
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
@@ -26,106 +30,106 @@
] ]
}, },
"dependencies": { "dependencies": {
"@formkit/auto-animate": "^0.8.1", "@formkit/auto-animate": "^0.8.2",
"@headlessui/react": "^1.7.17", "@headlessui/react": "^1.7.19",
"@ladjs/country-language": "^1.0.3", "@ladjs/country-language": "^1.0.3",
"@movie-web/providers": "^2.3.0", "@movie-web/providers": "^2.3.0",
"@noble/hashes": "^1.3.3", "@noble/hashes": "^1.4.0",
"@plasmohq/messaging": "^0.6.1", "@plasmohq/messaging": "^0.6.2",
"@react-spring/web": "^9.7.3", "@react-spring/web": "^9.7.3",
"@scure/bip39": "^1.2.2", "@scure/bip39": "^1.3.0",
"@sozialhelden/ietf-language-tags": "^5.4.2", "@sozialhelden/ietf-language-tags": "^5.4.2",
"@types/node-forge": "^1.3.10", "@types/node-forge": "^1.3.11",
"classnames": "^2.3.2", "classnames": "^2.5.1",
"core-js": "^3.34.0", "core-js": "^3.37.0",
"detect-browser": "^5.3.0", "detect-browser": "^5.3.0",
"dompurify": "^3.0.6", "dompurify": "^3.1.0",
"flag-icons": "^7.1.0", "flag-icons": "^7.2.1",
"focus-trap-react": "^10.2.3", "focus-trap-react": "^10.2.3",
"fscreen": "^1.2.0", "fscreen": "^1.2.0",
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",
"hls.js": "^1.5.7", "hls.js": "^1.5.8",
"i18next": "^23.7.11", "i18next": "^23.11.2",
"immer": "^10.0.3", "immer": "^10.0.4",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"lodash.isequal": "^4.5.0", "lodash.isequal": "^4.5.0",
"lodash.merge": "^4.6.2", "lodash.merge": "^4.6.2",
"million": "^2.6.4", "million": "^3.0.6",
"nanoid": "^5.0.4", "nanoid": "^5.0.7",
"node-forge": "^1.3.1", "node-forge": "^1.3.1",
"ofetch": "^1.3.3", "ofetch": "^1.3.4",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-ga4": "^2.1.0", "react-ga4": "^2.1.0",
"react-google-recaptcha-v3": "^1.10.1", "react-google-recaptcha-v3": "^1.10.1",
"react-helmet-async": "^2.0.4", "react-helmet-async": "^2.0.4",
"react-i18next": "^14.0.0", "react-i18next": "^14.1.0",
"react-lazy-with-preload": "^2.2.1", "react-lazy-with-preload": "^2.2.1",
"react-router-dom": "^6.21.1", "react-router-dom": "^6.22.3",
"react-sticky-el": "^2.1.0", "react-sticky-el": "^2.1.0",
"react-turnstile": "^1.1.2", "react-turnstile": "^1.1.3",
"react-use": "^17.4.2", "react-use": "^17.5.0",
"semver": "^7.5.4", "semver": "^7.6.0",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"subsrt-ts": "^2.1.2", "subsrt-ts": "^2.1.2",
"zustand": "^4.4.7" "zustand": "^4.5.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.23.6", "@babel/core": "^7.24.4",
"@babel/preset-env": "^7.23.6", "@babel/preset-env": "^7.24.4",
"@babel/preset-typescript": "^7.23.3", "@babel/preset-typescript": "^7.24.1",
"@rollup/wasm-node": "^4.9.4", "@rollup/wasm-node": "^4.15.0",
"@types/chromecast-caf-sender": "^1.0.8", "@types/chromecast-caf-sender": "^1.0.9",
"@types/crypto-js": "^4.2.1", "@types/crypto-js": "^4.2.2",
"@types/dompurify": "^3.0.5", "@types/dompurify": "^3.0.5",
"@types/fscreen": "^1.0.4", "@types/fscreen": "^1.0.4",
"@types/lodash.isequal": "^4.5.8", "@types/lodash.isequal": "^4.5.8",
"@types/lodash.merge": "^4.6.9", "@types/lodash.merge": "^4.6.9",
"@types/lodash.throttle": "^4.1.9", "@types/lodash.throttle": "^4.1.9",
"@types/node": "^20.10.5", "@types/node": "^20.12.7",
"@types/pako": "^2.0.3", "@types/pako": "^2.0.3",
"@types/react": "^18.2.45", "@types/react": "^18.2.79",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.25",
"@types/react-helmet": "^6.1.11", "@types/react-helmet": "^6.1.11",
"@types/react-router": "^5.1.20", "@types/react-router": "^5.1.20",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"@types/react-stickynode": "^4.0.3", "@types/react-stickynode": "^4.0.3",
"@types/react-transition-group": "^4.4.10", "@types/react-transition-group": "^4.4.10",
"@types/semver": "^7.5.6", "@types/semver": "^7.5.8",
"@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/eslint-plugin": "^7.7.0",
"@typescript-eslint/parser": "^6.15.0", "@typescript-eslint/parser": "^7.7.0",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.19",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"eslint-config-airbnb": "19.0.4", "eslint-config-airbnb": "19.0.4",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-prettier": "^5.1.1", "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "7.33.2", "eslint-plugin-react": "7.34.1",
"eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-react-hooks": "4.6.0",
"glob": "^10.3.10", "glob": "^10.3.12",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"jsdom": "^23.0.1", "jsdom": "^24.0.0",
"postcss": "^8.4.32", "postcss": "^8.4.38",
"postcss-rtl": "^2.0.0", "postcss-rtl": "^2.0.0",
"postcss-rtlcss": "^4.0.9", "postcss-rtlcss": "^5.1.2",
"prettier": "^3.1.1", "prettier": "^3.2.5",
"prettier-plugin-tailwindcss": "^0.5.9", "prettier-plugin-tailwindcss": "^0.5.14",
"rollup-plugin-visualizer": "^5.11.0", "rollup-plugin-visualizer": "^5.12.0",
"tailwind-scrollbar": "^3.0.5", "tailwind-scrollbar": "^3.1.0",
"tailwindcss": "^3.4.0", "tailwindcss": "^3.4.3",
"tailwindcss-themer": "^4.0.0", "tailwindcss-themer": "^4.0.0",
"type-fest": "^4.8.3", "type-fest": "^4.15.0",
"typescript": "^5.3.3", "typescript": "^5.4.5",
"vite": "^5.0.13", "vite": "^5.2.9",
"vite-plugin-checker": "^0.6.2", "vite-plugin-checker": "^0.6.4",
"vite-plugin-package-version": "^1.1.0", "vite-plugin-package-version": "^1.1.0",
"vite-plugin-pwa": "^0.17.4", "vite-plugin-pwa": "^0.19.8",
"vite-plugin-static-copy": "^1.0.0", "vite-plugin-static-copy": "^1.0.3",
"vitest": "^1.1.0", "vitest": "^1.5.0",
"workbox-window": "^7.0.0" "workbox-window": "^7.0.0"
}, },
"pnpm": { "pnpm": {

3537
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -135,13 +135,15 @@ export async function getLegacyMetaFromId(
throw err; throw err;
} }
let imdbId = data.external_ids.find((v) => v.provider === "imdb_latest") let imdbId = data.external_ids.find(
?.external_id; (v) => v.provider === "imdb_latest",
)?.external_id;
if (!imdbId) if (!imdbId)
imdbId = data.external_ids.find((v) => v.provider === "imdb")?.external_id; imdbId = data.external_ids.find((v) => v.provider === "imdb")?.external_id;
let tmdbId = data.external_ids.find((v) => v.provider === "tmdb_latest") let tmdbId = data.external_ids.find(
?.external_id; (v) => v.provider === "tmdb_latest",
)?.external_id;
if (!tmdbId) if (!tmdbId)
tmdbId = data.external_ids.find((v) => v.provider === "tmdb")?.external_id; tmdbId = data.external_ids.find((v) => v.provider === "tmdb")?.external_id;

View File

@@ -153,6 +153,12 @@ const tmdbHeaders = {
Authorization: `Bearer ${apiKey}`, Authorization: `Bearer ${apiKey}`,
}; };
function abortOnTimeout(timeout: number): AbortSignal {
const controller = new AbortController();
setTimeout(() => controller.abort(), timeout);
return controller.signal;
}
async function get<T>(url: string, params?: object): Promise<T> { async function get<T>(url: string, params?: object): Promise<T> {
if (!apiKey) throw new Error("TMDB API key not set"); if (!apiKey) throw new Error("TMDB API key not set");
try { try {
@@ -162,7 +168,7 @@ async function get<T>(url: string, params?: object): Promise<T> {
params: { params: {
...params, ...params,
}, },
signal: AbortSignal.timeout(5000), signal: abortOnTimeout(5000),
}); });
} catch (err) { } catch (err) {
return mwFetch<T>(encodeURI(url), { return mwFetch<T>(encodeURI(url), {
@@ -171,7 +177,7 @@ async function get<T>(url: string, params?: object): Promise<T> {
params: { params: {
...params, ...params,
}, },
signal: AbortSignal.timeout(30000), signal: abortOnTimeout(30000),
}); });
} }
} }

View File

@@ -46,10 +46,14 @@ function Button(props: {
); );
} }
function useSeasons(mediaId: string, isLastEpisode: boolean = false) { function useSeasons(
mediaId: string | undefined,
isLastEpisode: boolean = false,
) {
const state = useAsync(async () => { const state = useAsync(async () => {
if (isLastEpisode) { if (isLastEpisode) {
const data = await getMetaFromId(MWMediaType.SERIES, mediaId ?? ""); if (!mediaId) return null;
const data = await getMetaFromId(MWMediaType.SERIES, mediaId);
if (data?.meta.type !== MWMediaType.SERIES) return null; if (data?.meta.type !== MWMediaType.SERIES) return null;
return data.meta.seasons; return data.meta.seasons;
} }
@@ -60,13 +64,14 @@ function useSeasons(mediaId: string, isLastEpisode: boolean = false) {
function useNextSeasonEpisode( function useNextSeasonEpisode(
nextSeason: MWSeasonMeta | undefined, nextSeason: MWSeasonMeta | undefined,
mediaId: string, mediaId: string | undefined,
) { ) {
const state = useAsync(async () => { const state = useAsync(async () => {
if (nextSeason) { if (nextSeason) {
if (!mediaId) return null;
const data = await getMetaFromId( const data = await getMetaFromId(
MWMediaType.SERIES, MWMediaType.SERIES,
mediaId ?? "", mediaId,
nextSeason?.id, nextSeason?.id,
); );
if (data?.meta.type !== MWMediaType.SERIES) return null; if (data?.meta.type !== MWMediaType.SERIES) return null;
@@ -106,18 +111,17 @@ export function NextEpisodeButton(props: {
const enableAutoplay = usePreferencesStore((s) => s.enableAutoplay); const enableAutoplay = usePreferencesStore((s) => s.enableAutoplay);
const isLastEpisode = const isLastEpisode =
meta?.episode?.number === meta?.episodes?.at(-1)?.number; !meta?.episode?.number || !meta?.episodes?.at(-1)?.number
? false
: meta.episode.number === meta.episodes.at(-1)!.number;
const seasons = useSeasons(meta?.tmdbId ?? "", isLastEpisode); const seasons = useSeasons(meta?.tmdbId, isLastEpisode);
const nextSeason = seasons.value?.find( const nextSeason = seasons.value?.find(
(season) => season.number === (meta?.season?.number ?? 0) + 1, (season) => season.number === (meta?.season?.number ?? 0) + 1,
); );
const nextSeasonEpisode = useNextSeasonEpisode( const nextSeasonEpisode = useNextSeasonEpisode(nextSeason, meta?.tmdbId);
nextSeason,
meta?.tmdbId ?? "",
);
let show = false; let show = false;
const hasAutoplayed = useRef(false); const hasAutoplayed = useRef(false);