diff --git a/.eslintrc.js b/.eslintrc.js index 3bba5beb..d75c57d9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -8,27 +8,28 @@ const a11yOff = Object.keys(require("eslint-plugin-jsx-a11y").rules).reduce( module.exports = { env: { - browser: true + browser: true, }, extends: [ "airbnb", "airbnb/hooks", "plugin:@typescript-eslint/recommended", - "prettier", - "plugin:prettier/recommended" + "plugin:prettier/recommended", ], ignorePatterns: ["public/*", "dist/*", "/*.js", "/*.ts"], parser: "@typescript-eslint/parser", parserOptions: { project: "./tsconfig.json", - tsconfigRootDir: "./" + tsconfigRootDir: "./", }, settings: { "import/resolver": { - typescript: {} - } + typescript: { + project: "./tsconfig.json", + }, + }, }, - plugins: ["@typescript-eslint", "import"], + plugins: ["@typescript-eslint", "import", "prettier"], rules: { "react/jsx-uses-react": "off", "react/react-in-jsx-scope": "off", @@ -54,16 +55,44 @@ module.exports = { "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], "react/jsx-filename-extension": [ "error", - { extensions: [".js", ".tsx", ".jsx"] } + { extensions: [".js", ".tsx", ".jsx"] }, ], "import/extensions": [ "error", "ignorePackages", { ts: "never", - tsx: "never" - } + tsx: "never", + }, ], - ...a11yOff - } + "import/order": [ + "error", + { + groups: [ + "builtin", + "external", + "internal", + ["sibling", "parent"], + "index", + "unknown", + ], + "newlines-between": "always", + alphabetize: { + order: "asc", + caseInsensitive: true, + }, + }, + ], + "sort-imports": [ + "error", + { + ignoreCase: false, + ignoreDeclarationSort: true, + ignoreMemberSort: false, + memberSyntaxSortOrder: ["none", "all", "multiple", "single"], + allowSeparatedGroups: true, + }, + ], + ...a11yOff, + }, }; diff --git a/README.md b/README.md index 1167c00a..aaaa12cb 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Discord Server

-movie-web is a web app for watching movies easily. Check it out at **[movie.squeezebox.dev](https://movie.squeezebox.dev)**. +movie-web is a web app for watching movies easily. Check it out at **[movie-web.app](https://movie-web.app)**. This service works by displaying video files from third-party providers inside an intuitive and aesthetic user interface. diff --git a/package.json b/package.json index a9917a43..a4cb6bf2 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,13 @@ "name": "movie-web", "version": "3.0.14", "private": true, - "homepage": "https://movie.squeezebox.dev", + "homepage": "https://movie-web.app", "dependencies": { "@formkit/auto-animate": "^1.0.0-beta.5", "@headlessui/react": "^1.5.0", "@react-spring/web": "^9.7.1", + "@sentry/integrations": "^7.49.0", + "@sentry/react": "^7.49.0", "@use-gesture/react": "^10.2.24", "core-js": "^3.29.1", "crypto-js": "^4.1.1", @@ -80,7 +82,7 @@ "eslint-config-airbnb": "19.0.4", "eslint-config-prettier": "^8.6.0", "eslint-import-resolver-typescript": "^2.5.0", - "eslint-plugin-import": "^2.25.4", + "eslint-plugin-import": "^2.27.5", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "7.29.4", diff --git a/src/__tests__/providers/providers.test.ts b/src/__tests__/providers/providers.test.ts index 079821c9..35c77d5d 100644 --- a/src/__tests__/providers/providers.test.ts +++ b/src/__tests__/providers/providers.test.ts @@ -1,9 +1,10 @@ import { describe, it } from "vitest"; + import "@/backend"; -import { getProviders } from "@/backend/helpers/register"; -import { MWMediaType } from "@/backend/metadata/types"; -import { runProvider } from "@/backend/helpers/run"; import { testData } from "@/__tests__/providers/testdata"; +import { getProviders } from "@/backend/helpers/register"; +import { runProvider } from "@/backend/helpers/run"; +import { MWMediaType } from "@/backend/metadata/types"; describe("providers", () => { const providers = getProviders(); diff --git a/src/backend/embeds/streamm4u.ts b/src/backend/embeds/streamm4u.ts index b28b7ab8..abdc1486 100644 --- a/src/backend/embeds/streamm4u.ts +++ b/src/backend/embeds/streamm4u.ts @@ -1,11 +1,11 @@ import { MWEmbedType } from "@/backend/helpers/embed"; +import { proxiedFetch } from "@/backend/helpers/fetch"; import { registerEmbedScraper } from "@/backend/helpers/register"; import { + MWEmbedStream, MWStreamQuality, MWStreamType, - MWEmbedStream, } from "@/backend/helpers/streams"; -import { proxiedFetch } from "@/backend/helpers/fetch"; const HOST = "streamm4u.club"; const URL_BASE = `https://${HOST}`; diff --git a/src/backend/helpers/captions.ts b/src/backend/helpers/captions.ts index b5e40108..c50b8e1c 100644 --- a/src/backend/helpers/captions.ts +++ b/src/backend/helpers/captions.ts @@ -1,8 +1,9 @@ +import DOMPurify from "dompurify"; +import { detect, list, parse } from "subsrt-ts"; +import { ContentCaption } from "subsrt-ts/dist/types/handler"; + import { mwFetch, proxiedFetch } from "@/backend/helpers/fetch"; import { MWCaption } from "@/backend/helpers/streams"; -import DOMPurify from "dompurify"; -import { parse, detect, list } from "subsrt-ts"; -import { ContentCaption } from "subsrt-ts/dist/types/handler"; export const customCaption = "external-custom"; export function makeCaptionId(caption: MWCaption, isLinked: boolean): string { diff --git a/src/backend/helpers/fetch.ts b/src/backend/helpers/fetch.ts index 393ff7f8..9ed16b7c 100644 --- a/src/backend/helpers/fetch.ts +++ b/src/backend/helpers/fetch.ts @@ -1,6 +1,7 @@ -import { conf } from "@/setup/config"; import { ofetch } from "ofetch"; +import { conf } from "@/setup/config"; + let proxyUrlIndex = Math.floor(Math.random() * conf().PROXY_URLS.length); // round robins all proxy urls diff --git a/src/backend/helpers/provider.ts b/src/backend/helpers/provider.ts index 95f5e374..6eed4560 100644 --- a/src/backend/helpers/provider.ts +++ b/src/backend/helpers/provider.ts @@ -1,7 +1,7 @@ -import { DetailedMeta } from "../metadata/getmeta"; -import { MWMediaType } from "../metadata/types"; import { MWEmbed } from "./embed"; import { MWStream } from "./streams"; +import { DetailedMeta } from "../metadata/getmeta"; +import { MWMediaType } from "../metadata/types"; export type MWProviderScrapeResult = { stream?: MWStream; diff --git a/src/backend/metadata/getmeta.ts b/src/backend/metadata/getmeta.ts index c0c9e92c..215448e5 100644 --- a/src/backend/metadata/getmeta.ts +++ b/src/backend/metadata/getmeta.ts @@ -1,13 +1,14 @@ import { FetchError } from "ofetch"; -import { makeUrl, proxiedFetch } from "../helpers/fetch"; + import { - formatJWMeta, JWMediaResult, JWSeasonMetaResult, JW_API_BASE, + formatJWMeta, mediaTypeToJW, } from "./justwatch"; import { MWMediaMeta, MWMediaType } from "./types"; +import { makeUrl, proxiedFetch } from "../helpers/fetch"; type JWExternalIdType = | "eidr" diff --git a/src/backend/metadata/search.ts b/src/backend/metadata/search.ts index 1c3c4598..10cbb285 100644 --- a/src/backend/metadata/search.ts +++ b/src/backend/metadata/search.ts @@ -1,13 +1,14 @@ import { SimpleCache } from "@/utils/cache"; -import { proxiedFetch } from "../helpers/fetch"; + import { - formatJWMeta, JWContentTypes, JWMediaResult, JW_API_BASE, + formatJWMeta, mediaTypeToJW, } from "./justwatch"; import { MWMediaMeta, MWQuery } from "./types"; +import { proxiedFetch } from "../helpers/fetch"; const cache = new SimpleCache(); cache.setCompare((a, b) => { diff --git a/src/backend/providers/flixhq.ts b/src/backend/providers/flixhq.ts index d9440213..fb5a0bb1 100644 --- a/src/backend/providers/flixhq.ts +++ b/src/backend/providers/flixhq.ts @@ -1,4 +1,5 @@ import { compareTitle } from "@/utils/titleMatch"; + import { proxiedFetch } from "../helpers/fetch"; import { registerProvider } from "../helpers/register"; import { diff --git a/src/backend/providers/gdriveplayer.ts b/src/backend/providers/gdriveplayer.ts index a2a0063d..2023b67d 100644 --- a/src/backend/providers/gdriveplayer.ts +++ b/src/backend/providers/gdriveplayer.ts @@ -1,9 +1,10 @@ -import { unpack } from "unpacker"; import CryptoJS from "crypto-js"; +import { unpack } from "unpacker"; import { registerProvider } from "@/backend/helpers/register"; -import { MWMediaType } from "@/backend/metadata/types"; import { MWStreamQuality } from "@/backend/helpers/streams"; +import { MWMediaType } from "@/backend/metadata/types"; + import { proxiedFetch } from "../helpers/fetch"; const format = { diff --git a/src/backend/providers/m4ufree.ts b/src/backend/providers/m4ufree.ts index f4e79f5b..0fe5303d 100644 --- a/src/backend/providers/m4ufree.ts +++ b/src/backend/providers/m4ufree.ts @@ -1,4 +1,5 @@ import { MWEmbed, MWEmbedType } from "@/backend/helpers/embed"; + import { proxiedFetch } from "../helpers/fetch"; import { registerProvider } from "../helpers/register"; import { MWMediaType } from "../metadata/types"; diff --git a/src/backend/providers/superstream/index.ts b/src/backend/providers/superstream/index.ts index 3c499739..bf9ce9dd 100644 --- a/src/backend/providers/superstream/index.ts +++ b/src/backend/providers/superstream/index.ts @@ -1,15 +1,15 @@ -import { registerProvider } from "@/backend/helpers/register"; -import { MWMediaType } from "@/backend/metadata/types"; - -import { customAlphabet } from "nanoid"; import CryptoJS from "crypto-js"; +import { customAlphabet } from "nanoid"; + import { proxiedFetch } from "@/backend/helpers/fetch"; +import { registerProvider } from "@/backend/helpers/register"; import { MWCaption, MWCaptionType, MWStreamQuality, MWStreamType, } from "@/backend/helpers/streams"; +import { MWMediaType } from "@/backend/metadata/types"; import { compareTitle } from "@/utils/titleMatch"; const nanoid = customAlphabet("0123456789abcdef", 32); diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 9a74f84d..eefeef01 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,6 +1,7 @@ -import { Icon, Icons } from "@/components/Icon"; import { ReactNode } from "react"; +import { Icon, Icons } from "@/components/Icon"; + interface Props { icon?: Icons; onClick?: () => void; diff --git a/src/components/CaptionColorSelector.tsx b/src/components/CaptionColorSelector.tsx index 3d286f78..7df66320 100644 --- a/src/components/CaptionColorSelector.tsx +++ b/src/components/CaptionColorSelector.tsx @@ -1,4 +1,5 @@ import { useSettings } from "@/state/settings"; + import { Icon, Icons } from "./Icon"; export const colors = ["#ffffff", "#00ffff", "#ffff00"]; diff --git a/src/components/Dropdown.tsx b/src/components/Dropdown.tsx index 9321e1fe..e2fac636 100644 --- a/src/components/Dropdown.tsx +++ b/src/components/Dropdown.tsx @@ -1,6 +1,6 @@ +import { Listbox, Transition } from "@headlessui/react"; import React, { Fragment } from "react"; -import { Listbox, Transition } from "@headlessui/react"; import { Icon, Icons } from "@/components/Icon"; export interface OptionItem { diff --git a/src/components/Overlay.tsx b/src/components/Overlay.tsx index 83e61f8f..2129f68d 100644 --- a/src/components/Overlay.tsx +++ b/src/components/Overlay.tsx @@ -1,6 +1,7 @@ -import { Transition } from "@/components/Transition"; import { Helmet } from "react-helmet"; +import { Transition } from "@/components/Transition"; + export function Overlay(props: { children: React.ReactNode }) { return ( <> diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index 2b937549..2513e409 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -1,6 +1,8 @@ -import { MWMediaType, MWQuery } from "@/backend/metadata/types"; import { useState } from "react"; import { useTranslation } from "react-i18next"; + +import { MWMediaType, MWQuery } from "@/backend/metadata/types"; + import { DropdownButton } from "./buttons/DropdownButton"; import { Icon, Icons } from "./Icon"; import { TextInputControl } from "./text-inputs/TextInputControl"; diff --git a/src/components/Transition.tsx b/src/components/Transition.tsx index f7d0d533..b46df9b1 100644 --- a/src/components/Transition.tsx +++ b/src/components/Transition.tsx @@ -1,8 +1,8 @@ -import { Fragment, ReactNode } from "react"; import { Transition as HeadlessTransition, TransitionClasses, } from "@headlessui/react"; +import { Fragment, ReactNode } from "react"; type TransitionAnimations = | "slide-down" diff --git a/src/components/buttons/DropdownButton.tsx b/src/components/buttons/DropdownButton.tsx index a49403e8..8e252231 100644 --- a/src/components/buttons/DropdownButton.tsx +++ b/src/components/buttons/DropdownButton.tsx @@ -4,10 +4,11 @@ import React, { useEffect, useState, } from "react"; -import { Icon, Icons } from "@/components/Icon"; +import { Icon, Icons } from "@/components/Icon"; import { BackdropContainer, useBackdrop } from "@/components/layout/Backdrop"; -import { ButtonControlProps, ButtonControl } from "./ButtonControl"; + +import { ButtonControl, ButtonControlProps } from "./ButtonControl"; export interface OptionItem { id: string; diff --git a/src/components/buttons/EditButton.tsx b/src/components/buttons/EditButton.tsx index bcdd3cfd..4571af10 100644 --- a/src/components/buttons/EditButton.tsx +++ b/src/components/buttons/EditButton.tsx @@ -1,7 +1,9 @@ -import { Icon, Icons } from "@/components/Icon"; import { useAutoAnimate } from "@formkit/auto-animate/react"; import { useCallback } from "react"; import { useTranslation } from "react-i18next"; + +import { Icon, Icons } from "@/components/Icon"; + import { ButtonControl } from "./ButtonControl"; export interface EditButtonProps { diff --git a/src/components/buttons/IconButton.tsx b/src/components/buttons/IconButton.tsx index b247a440..0a33a878 100644 --- a/src/components/buttons/IconButton.tsx +++ b/src/components/buttons/IconButton.tsx @@ -1,5 +1,6 @@ import { Icon, Icons } from "@/components/Icon"; -import { ButtonControlProps, ButtonControl } from "./ButtonControl"; + +import { ButtonControl, ButtonControlProps } from "./ButtonControl"; export interface IconButtonProps extends ButtonControlProps { icon: Icons; diff --git a/src/components/layout/Backdrop.tsx b/src/components/layout/Backdrop.tsx index 57719e29..7e022347 100644 --- a/src/components/layout/Backdrop.tsx +++ b/src/components/layout/Backdrop.tsx @@ -1,5 +1,6 @@ import React, { createRef, useEffect, useState } from "react"; import { createPortal } from "react-dom"; + import { useFade } from "@/hooks/useFade"; interface BackdropProps { diff --git a/src/components/layout/BrandPill.tsx b/src/components/layout/BrandPill.tsx index 45fe75e2..3c7e1fea 100644 --- a/src/components/layout/BrandPill.tsx +++ b/src/components/layout/BrandPill.tsx @@ -1,4 +1,5 @@ import { useTranslation } from "react-i18next"; + import { Icon, Icons } from "@/components/Icon"; export function BrandPill(props: { diff --git a/src/components/layout/ErrorBoundary.tsx b/src/components/layout/ErrorBoundary.tsx index bde7c11d..645a4a9e 100644 --- a/src/components/layout/ErrorBoundary.tsx +++ b/src/components/layout/ErrorBoundary.tsx @@ -1,10 +1,11 @@ import { Component } from "react"; +import { Trans, useTranslation } from "react-i18next"; + import { IconPatch } from "@/components/buttons/IconPatch"; import { Icons } from "@/components/Icon"; import { Link } from "@/components/text/Link"; import { Title } from "@/components/text/Title"; import { conf } from "@/setup/config"; -import { Trans, useTranslation } from "react-i18next"; interface ErrorShowcaseProps { error: { diff --git a/src/components/layout/Modal.tsx b/src/components/layout/Modal.tsx index b3e7a22e..11ed75b7 100644 --- a/src/components/layout/Modal.tsx +++ b/src/components/layout/Modal.tsx @@ -1,8 +1,9 @@ -import { Overlay } from "@/components/Overlay"; -import { Transition } from "@/components/Transition"; import { ReactNode } from "react"; import { createPortal } from "react-dom"; +import { Overlay } from "@/components/Overlay"; +import { Transition } from "@/components/Transition"; + interface Props { show: boolean; children?: ReactNode; diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx index 836c6206..df6d464b 100644 --- a/src/components/layout/Navigation.tsx +++ b/src/components/layout/Navigation.tsx @@ -1,10 +1,12 @@ import { ReactNode, useState } from "react"; import { Link } from "react-router-dom"; + import { IconPatch } from "@/components/buttons/IconPatch"; import { Icons } from "@/components/Icon"; -import { conf } from "@/setup/config"; import { useBannerSize } from "@/hooks/useBanner"; +import { conf } from "@/setup/config"; import SettingsModal from "@/views/SettingsModal"; + import { BrandPill } from "./BrandPill"; export interface NavigationProps { diff --git a/src/components/layout/SectionHeading.tsx b/src/components/layout/SectionHeading.tsx index fda60bae..bd57bb2d 100644 --- a/src/components/layout/SectionHeading.tsx +++ b/src/components/layout/SectionHeading.tsx @@ -1,4 +1,5 @@ import { ReactNode } from "react"; + import { Icon, Icons } from "@/components/Icon"; interface SectionHeadingProps { diff --git a/src/components/media/MediaCard.tsx b/src/components/media/MediaCard.tsx index a2e331d4..3769245e 100644 --- a/src/components/media/MediaCard.tsx +++ b/src/components/media/MediaCard.tsx @@ -1,10 +1,12 @@ -import { Link } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import { DotList } from "@/components/text/DotList"; -import { MWMediaMeta } from "@/backend/metadata/types"; +import { Link } from "react-router-dom"; + import { JWMediaToId } from "@/backend/metadata/justwatch"; -import { Icons } from "../Icon"; +import { MWMediaMeta } from "@/backend/metadata/types"; +import { DotList } from "@/components/text/DotList"; + import { IconPatch } from "../buttons/IconPatch"; +import { Icons } from "../Icon"; export interface MediaCardProps { media: MWMediaMeta; diff --git a/src/components/media/WatchedMediaCard.tsx b/src/components/media/WatchedMediaCard.tsx index 935ceb84..346c77b6 100644 --- a/src/components/media/WatchedMediaCard.tsx +++ b/src/components/media/WatchedMediaCard.tsx @@ -1,6 +1,8 @@ +import { useMemo } from "react"; + import { MWMediaMeta } from "@/backend/metadata/types"; import { useWatchedContext } from "@/state/watched"; -import { useMemo } from "react"; + import { MediaCard } from "./MediaCard"; export interface WatchedMediaCardProps { diff --git a/src/components/popout/FloatingCard.tsx b/src/components/popout/FloatingCard.tsx index 8d894f16..5a837d01 100644 --- a/src/components/popout/FloatingCard.tsx +++ b/src/components/popout/FloatingCard.tsx @@ -1,11 +1,14 @@ +import { animated, easings, useSpringValue } from "@react-spring/web"; +import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; + import { FloatingCardAnchorPosition } from "@/components/popout/positions/FloatingCardAnchorPosition"; import { FloatingCardMobilePosition } from "@/components/popout/positions/FloatingCardMobilePosition"; import { useIsMobile } from "@/hooks/useIsMobile"; import { PopoutSection } from "@/video/components/popouts/PopoutUtils"; -import { useSpringValue, animated, easings } from "@react-spring/web"; -import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; -import { Icon, Icons } from "../Icon"; + import { FloatingDragHandle, MobilePopoutSpacer } from "./FloatingDragHandle"; +import { Icon, Icons } from "../Icon"; interface FloatingCardProps { children?: ReactNode; @@ -133,13 +136,15 @@ export const FloatingCardView = { action?: React.ReactNode; backText?: string; }) { + const { t } = useTranslation(); + let left = (
- {props.backText || "Go back"} + {props.backText || t("videoPlayer.popouts.back")}
); if (props.close) diff --git a/src/components/popout/FloatingContainer.tsx b/src/components/popout/FloatingContainer.tsx index 0735d912..73c6f31f 100644 --- a/src/components/popout/FloatingContainer.tsx +++ b/src/components/popout/FloatingContainer.tsx @@ -1,4 +1,3 @@ -import { Transition } from "@/components/Transition"; import React, { ReactNode, useCallback, @@ -8,6 +7,8 @@ import React, { } from "react"; import { createPortal } from "react-dom"; +import { Transition } from "@/components/Transition"; + interface Props { children?: ReactNode; onClose?: () => void; diff --git a/src/components/popout/FloatingView.tsx b/src/components/popout/FloatingView.tsx index 4c21f136..d9986318 100644 --- a/src/components/popout/FloatingView.tsx +++ b/src/components/popout/FloatingView.tsx @@ -1,6 +1,7 @@ +import { ReactNode } from "react"; + import { Transition } from "@/components/Transition"; import { useIsMobile } from "@/hooks/useIsMobile"; -import { ReactNode } from "react"; interface Props { children?: ReactNode; diff --git a/src/components/popout/positions/FloatingCardAnchorPosition.tsx b/src/components/popout/positions/FloatingCardAnchorPosition.tsx index 4e022834..b3041b6d 100644 --- a/src/components/popout/positions/FloatingCardAnchorPosition.tsx +++ b/src/components/popout/positions/FloatingCardAnchorPosition.tsx @@ -1,6 +1,7 @@ -import { createFloatingAnchorEvent } from "@/components/popout/FloatingAnchor"; import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; +import { createFloatingAnchorEvent } from "@/components/popout/FloatingAnchor"; + interface AnchorPositionProps { children?: ReactNode; id: string; diff --git a/src/components/popout/positions/FloatingCardMobilePosition.tsx b/src/components/popout/positions/FloatingCardMobilePosition.tsx index dece3ccc..d4a7f518 100644 --- a/src/components/popout/positions/FloatingCardMobilePosition.tsx +++ b/src/components/popout/positions/FloatingCardMobilePosition.tsx @@ -1,4 +1,4 @@ -import { useSpring, animated, config } from "@react-spring/web"; +import { animated, config, useSpring } from "@react-spring/web"; import { useDrag } from "@use-gesture/react"; import { ReactNode, useEffect, useRef, useState } from "react"; diff --git a/src/components/text/ArrowLink.tsx b/src/components/text/ArrowLink.tsx index 1bcfddcf..ad51319e 100644 --- a/src/components/text/ArrowLink.tsx +++ b/src/components/text/ArrowLink.tsx @@ -1,4 +1,5 @@ import { Link as LinkRouter } from "react-router-dom"; + import { Icon, Icons } from "@/components/Icon"; interface IArrowLinkPropsBase { diff --git a/src/hooks/useBanner.tsx b/src/hooks/useBanner.tsx index 9288914e..3781adff 100644 --- a/src/hooks/useBanner.tsx +++ b/src/hooks/useBanner.tsx @@ -1,12 +1,12 @@ import { - ReactNode, - createContext, - useState, - useMemo, Dispatch, + ReactNode, SetStateAction, - useEffect, + createContext, useContext, + useEffect, + useMemo, + useState, } from "react"; import { useMeasure } from "react-use"; diff --git a/src/hooks/useChromecastAvailable.ts b/src/hooks/useChromecastAvailable.ts index 6190a288..501d6048 100644 --- a/src/hooks/useChromecastAvailable.ts +++ b/src/hooks/useChromecastAvailable.ts @@ -1,8 +1,9 @@ /// -import { isChromecastAvailable } from "@/setup/chromecast"; import { useEffect, useRef, useState } from "react"; +import { isChromecastAvailable } from "@/setup/chromecast"; + export function useChromecastAvailable() { const [available, setAvailable] = useState(null); diff --git a/src/hooks/useScrape.ts b/src/hooks/useScrape.ts index 05f3c387..a375e618 100644 --- a/src/hooks/useScrape.ts +++ b/src/hooks/useScrape.ts @@ -1,8 +1,9 @@ +import { useEffect, useState } from "react"; + import { findBestStream } from "@/backend/helpers/scrape"; import { MWStream } from "@/backend/helpers/streams"; import { DetailedMeta } from "@/backend/metadata/getmeta"; import { MWMediaType } from "@/backend/metadata/types"; -import { useEffect, useState } from "react"; export interface ScrapeEventLog { type: "provider" | "embed"; diff --git a/src/hooks/useSearchQuery.ts b/src/hooks/useSearchQuery.ts index 093a99c2..d431a0d0 100644 --- a/src/hooks/useSearchQuery.ts +++ b/src/hooks/useSearchQuery.ts @@ -1,7 +1,8 @@ -import { MWMediaType, MWQuery } from "@/backend/metadata/types"; import { useState } from "react"; import { generatePath, useHistory, useRouteMatch } from "react-router-dom"; +import { MWMediaType, MWQuery } from "@/backend/metadata/types"; + function getInitialValue(params: { type: string; query: string }) { const type = Object.values(MWMediaType).find((v) => params.type === v) || diff --git a/src/hooks/useVolumeToggle.ts b/src/hooks/useVolumeToggle.ts index 636b787b..766ae7e6 100644 --- a/src/hooks/useVolumeToggle.ts +++ b/src/hooks/useVolumeToggle.ts @@ -1,18 +1,19 @@ +import { useState } from "react"; + import { useControls } from "@/video/state/logic/controls"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; -import { useState } from "react"; export function useVolumeControl(descriptor: string) { const [storedVolume, setStoredVolume] = useState(1); const controls = useControls(descriptor); const mediaPlaying = useMediaPlaying(descriptor); - const toggleVolume = () => { + const toggleVolume = (isKeyboardEvent = false) => { if (mediaPlaying.volume > 0) { setStoredVolume(mediaPlaying.volume); - controls.setVolume(0); + controls.setVolume(0, isKeyboardEvent); } else { - controls.setVolume(storedVolume > 0 ? storedVolume : 1); + controls.setVolume(storedVolume > 0 ? storedVolume : 1, isKeyboardEvent); } }; diff --git a/src/index.tsx b/src/index.tsx index 1ba12d5e..1bf99f70 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,12 +3,14 @@ import React, { Suspense } from "react"; import ReactDOM from "react-dom"; import { BrowserRouter, HashRouter } from "react-router-dom"; import type { ReactNode } from "react-router-dom/node_modules/@types/react/index"; -import { ErrorBoundary } from "@/components/layout/ErrorBoundary"; -import { conf } from "@/setup/config"; import { registerSW } from "virtual:pwa-register"; +import { ErrorBoundary } from "@/components/layout/ErrorBoundary"; import App from "@/setup/App"; +import { conf } from "@/setup/config"; + import "@/setup/ga"; +import "@/setup/sentry"; import "@/setup/i18n"; import "@/setup/index.css"; import "@/backend"; diff --git a/src/setup/App.tsx b/src/setup/App.tsx index 2d8a99a6..992549e0 100644 --- a/src/setup/App.tsx +++ b/src/setup/App.tsx @@ -1,16 +1,16 @@ import { lazy } from "react"; import { Redirect, Route, Switch } from "react-router-dom"; -import { BookmarkContextProvider } from "@/state/bookmark"; -import { WatchedContextProvider } from "@/state/watched"; -import { SettingsProvider } from "@/state/settings"; -import { NotFoundPage } from "@/views/notfound/NotFoundView"; -import { MediaView } from "@/views/media/MediaView"; -import { SearchView } from "@/views/search/SearchView"; import { MWMediaType } from "@/backend/metadata/types"; -import { V2MigrationView } from "@/views/other/v2Migration"; import { BannerContextProvider } from "@/hooks/useBanner"; import { Layout } from "@/setup/Layout"; +import { BookmarkContextProvider } from "@/state/bookmark"; +import { SettingsProvider } from "@/state/settings"; +import { WatchedContextProvider } from "@/state/watched"; +import { MediaView } from "@/views/media/MediaView"; +import { NotFoundPage } from "@/views/notfound/NotFoundView"; +import { V2MigrationView } from "@/views/other/v2Migration"; +import { SearchView } from "@/views/search/SearchView"; function App() { return ( diff --git a/src/setup/Layout.tsx b/src/setup/Layout.tsx index 599547f6..23348dfe 100644 --- a/src/setup/Layout.tsx +++ b/src/setup/Layout.tsx @@ -1,8 +1,9 @@ +import { ReactNode } from "react"; +import { useTranslation } from "react-i18next"; + import { Banner } from "@/components/Banner"; import { useBannerSize } from "@/hooks/useBanner"; import { useIsOnline } from "@/hooks/usePing"; -import { ReactNode } from "react"; -import { useTranslation } from "react-i18next"; export function Layout(props: { children: ReactNode }) { const { t } = useTranslation(); diff --git a/src/setup/config.ts b/src/setup/config.ts index 8947d43c..f1db01da 100644 --- a/src/setup/config.ts +++ b/src/setup/config.ts @@ -1,4 +1,4 @@ -import { APP_VERSION, GITHUB_LINK, DISCORD_LINK } from "./constants"; +import { APP_VERSION, DISCORD_LINK, GITHUB_LINK } from "./constants"; interface Config { APP_VERSION: string; diff --git a/src/setup/constants.ts b/src/setup/constants.ts index 927aecbc..f8a1cc59 100644 --- a/src/setup/constants.ts +++ b/src/setup/constants.ts @@ -2,3 +2,5 @@ export const APP_VERSION = import.meta.env.PACKAGE_VERSION; export const DISCORD_LINK = "https://discord.gg/Jhqt4Xzpfb"; export const GITHUB_LINK = "https://github.com/movie-web/movie-web"; export const GA_ID = "G-44YVXRL61C"; +export const SENTRY_DSN = + "https://b267ab7d52674c23af4e4e6cf2956251@o4505053491167232.ingest.sentry.io/4505053495296000"; diff --git a/src/setup/ga.ts b/src/setup/ga.ts index 219cd3c5..1fbf488b 100644 --- a/src/setup/ga.ts +++ b/src/setup/ga.ts @@ -1,4 +1,5 @@ import ReactGA from "react-ga4"; + import { GA_ID } from "@/setup/constants"; ReactGA.initialize([ diff --git a/src/setup/i18n.ts b/src/setup/i18n.ts index 3b18e3f5..56ac9b0f 100644 --- a/src/setup/i18n.ts +++ b/src/setup/i18n.ts @@ -1,15 +1,27 @@ import i18n from "i18next"; -import { initReactI18next } from "react-i18next"; import LanguageDetector from "i18next-browser-languagedetector"; +import { initReactI18next } from "react-i18next"; // Languages -import en from "./locales/en/translation.json"; import { captionLanguages } from "./iso6391"; +import en from "./locales/en/translation.json"; +import fr from "./locales/fr/translation.json"; +import nl from "./locales/nl/translation.json"; +import tr from "./locales/tr/translation.json"; const locales = { en: { translation: en, }, + nl: { + translation: nl, + }, + tr: { + translation: tr, + }, + fr: { + translation: fr, + }, }; i18n // detect user language diff --git a/src/setup/iso6391.ts b/src/setup/iso6391.ts index c20580b8..28d42806 100644 --- a/src/setup/iso6391.ts +++ b/src/setup/iso6391.ts @@ -217,7 +217,7 @@ export const captionLanguages: CaptionLanguageOption[] = [ id: "none", englishName: "None", name: "None", - nativeName: "No caption language selected", + nativeName: "Lorem ipsum", }, { id: "aa", diff --git a/src/setup/locales/en/translation.json b/src/setup/locales/en/translation.json index f0cf677c..fba37d84 100644 --- a/src/setup/locales/en/translation.json +++ b/src/setup/locales/en/translation.json @@ -69,6 +69,7 @@ "playbackSpeed": "Playback speed" }, "popouts": { + "back": "Go back", "sources": "Sources", "seasons": "Seasons", "captions": "Captions", @@ -108,7 +109,7 @@ }, "settings": { "title": "Settings", - "language":"Language", + "language": "Language", "captionLanguage": "Caption Language" }, "v3": { diff --git a/src/setup/locales/fr/translation.json b/src/setup/locales/fr/translation.json index fe9d73eb..44c575bc 100644 --- a/src/setup/locales/fr/translation.json +++ b/src/setup/locales/fr/translation.json @@ -16,16 +16,34 @@ "placeholder": "Que voulez-vous voir?" }, "media": { - "title": "Impossible de trouver ce média", - "description": "Nous n'avons pas pu trouver le média que vous avez demandé. Soit il a été supprimé, soit vous avez altéré l'URL." + "movie": "Films", + "series": "Séries", + "stopEditing": "Arrêter l'édition", + "errors": { + "genericTitle": "Oups, c'est coupé !", + "failedMeta": "Impossible de charger les métadonnées", + "mediaFailed": "Nous n'avons pas réussi à récupérer le média que vous avez demandé. Veuillez vérifier votre connexion Internet et réessayer.", + "videoFailed": "Nous avons rencontré une erreur lors de la lecture de la vidéo que vous avez demandée. Si cela se reproduit, veuillez signaler le problème au serveur <0>Discord ou sur <1>GitHub." + } }, - "provider": { - "title": "Ce fournisseur a été désactivé", - "description": "Nous avons eu des problèmes avec le fournisseur ou bien il était trop instable pour être utilisé, donc nous avons dû le désactiver." + "seasons": { + "seasonAndEpisode": "S{{saison}} E{{épisode}}" }, - "page": { - "title": "Impossible de trouver cette page", - "description": "Nous avons cherché partout : sous les poubelles, dans le placard, derrière le proxy, mais nous n'avons finalement pas pu trouver la page que vous recherchez." + "notFound": { + "genericTitle": "Introuvable", + "backArrow": "Retour à l'accueil", + "media": { + "title": "Impossible de trouver ce média", + "description": "Nous n'avons pas trouvé le média que vous avez demandé. Soit il a été supprimé, soit vous avez modifié l'URL." + }, + "provider": { + "title": "Ce fournisseur a été désactivé", + "description": "Nous avons eu des problèmes avec le fournisseur ou il était trop instable pour être utilisé, nous avons donc dû le désactiver." + }, + "page": { + "title": "Impossible de trouver cette page", + "description": "Nous avons cherché partout : sous les poubelles, dans le placard, derrière le proxy, mais nous n'avons finalement pas trouvé la page que vous cherchez." + } }, "searchBar": { "movie": "Film", @@ -51,9 +69,12 @@ "playbackSpeed": "Vitesse" }, "popouts": { + "back": "Retourner", "sources": "Sources", "seasons": "Saisons", "captions": "Sous-titres", + "playbackSpeed": "Vitesse de lecture", + "customPlaybackSpeed": "Vitesse de lecture personnalisée", "captionPreferences": { "title": "Personnaliser", "delay": "Délai", @@ -77,13 +98,19 @@ "seasons": "Choisissez la saison que vous voulez regarder", "episode": "Sélectionnez un épisode", "captions": "Choisissez une langue de sous-titres", - "captionPreferences": "Personnalisez l'apparence des sous-titres" + "captionPreferences": "Personnalisez l'apparence des sous-titres", + "playbackSpeed": "Changer la vitesse de lecture" } }, "errors": { "fatalError": "Le lecteur vidéo a rencontré une erreur fatale, veuillez la signaler au serveur <0>Discord ou sur <1>GitHub." } }, + "settings": { + "title": "Paramètres", + "language": "Language", + "captionLanguage": "Langue des sous-titres" + }, "v3": { "newSiteTitle": "Nouvelle version disponible!", "newDomain": "https://movie-web.app", diff --git a/src/setup/locales/nl/translation.json b/src/setup/locales/nl/translation.json new file mode 100644 index 00000000..94e796e8 --- /dev/null +++ b/src/setup/locales/nl/translation.json @@ -0,0 +1,128 @@ +{ + "global": { + "name": "movie-web" + }, + "search": { + "loading_series": "We zoeken je favoriete series...", + "loading_movie": "We zoeken je favoriete films...", + "loading": "Aan het zoeken...", + "allResults": "Dat is het!", + "noResults": "We konden helaas niets vinden.", + "allFailed": "Het is niet gelukt de media te laden, probeer het nog eens.", + "headingTitle": "Zoekresultaten", + "bookmarks": "Opgeslagen", + "continueWatching": "Kijk verder", + "title": "Wat wil je graag kijken?", + "placeholder": "Wat wil je graag kijken?" + }, + "media": { + "movie": "Film", + "series": "Serie", + "stopEditing": "Stop met bewerken", + "errors": { + "genericTitle": "Oeps, hier ging iets mis!", + "failedMeta": "Het is niet gelukt de meta-informatie op te halen/", + "mediaFailed": "Het is niet gelukt deze media op te halen. Controleer of je een internetverbinding hebt en probeer het nog een keer.", + "videoFailed": "Er ging iets mis tijdens het spelen van deze video. Als dit blijft gebeuren, deel het dan in de <0>Discord server of maak een <1>GitHub issue." + } + }, + "seasons": { + "seasonAndEpisode": "S{{season}} A{{episode}}" + }, + "notFound": { + "genericTitle": "Pagina niet gevonden", + "backArrow": "Naar de home-pagina", + "media": { + "title": "We konden deze media niet vinden.", + "description": "We konden dit stukje media niet vinden. Het is mogelijk verwijderd, of jij hebt zelf de URL aangepast." + }, + "provider": { + "title": "Deze bron is niet langer beschikbaar", + "description": "Deze bron was helaas te instabiel, we hebben hem jammer genoeg uit moeten zetten." + }, + "page": { + "title": "Pagina niet gevonden", + "description": "We hebben echt alles geprobeerd, zelfs tijdrijzen; echter hebben we deze pagina helaas niet kunnen vinden." + } + }, + "searchBar": { + "movie": "Films", + "series": "Series", + "Search": "Zoeken" + }, + "videoPlayer": { + "findingBestVideo": "De beste video voor jou aan het zoeken...", + "noVideos": "Helaas konden we dat filmpje niet vinden", + "loading": "Aan het laden...", + "backToHome": "Naar de home-pagina", + "backToHomeShort": "Terug", + "seasonAndEpisode": "S{{season}} A{{episode}}", + "timeLeft": "Nog {{timeLeft}}", + "finishAt": "Afgelopen om {{timeFinished}}", + "buttons": { + "episodes": "Afleveringen", + "source": "Bron", + "captions": "Ondertiteling", + "download": "Download", + "settings": "Instellingen", + "pictureInPicture": "Beeld-in-beeld", + "playbackSpeed": "Afspeelsnelheid" + }, + "popouts": { + "back": "Terug", + "sources": "Bronnen", + "seasons": "Seizoenen", + "captions": "Ondertiteling", + "playbackSpeed": "Afspeelsnelheid", + "customPlaybackSpeed": "Andere snelheden", + "captionPreferences": { + "title": "Instellingen", + "delay": "Vertraging", + "fontSize": "Lettergrootte", + "opacity": "Doorzichtbaarheid", + "color": "Kleur" + }, + "episode": "A{{index}} - {{title}}", + "noCaptions": "Geen ondertiteling", + "linkedCaptions": "Gelinkte ondertiteling", + "customCaption": "Eigen ondertiteling", + "uploadCustomCaption": "Ondertiteling uploaden", + "noEmbeds": "We hebben geen filmpjes kunnen vinden voor deze bron.", + + "errors": { + "loadingWentWong": "Er ging iets mis tijdens het laden van de afleveringen voor {{seasonTitle}}", + "embedsError": "Er ging iets mis tijdens het laden van de embeds voor dit dingetje dat je waarschijnlijk leuk vindt" + }, + "descriptions": { + "sources": "Welke bron wil je graag gebruiken", + "embeds": "Welk filmpje wil je gebruiken?", + "seasons": "Welk seizoen wil je kijken?", + "episode": "Kies een aflevering", + "captions": "Kies een taal voor de ondertiteling", + "captionPreferences": "Pas de ondertiteling aan aan je voorkeuren", + "playbackSpeed": "Pas de afspeelsnelhijd aan" + } + }, + "errors": { + "fatalError": "De videospeler is helaas ontploft, rapporteer deze fout op de <0>Discord server of op <1>GitHub." + } + }, + "settings": { + "title": "Instellingen", + "language": "Taal", + "captionLanguage": "Taal voor de Ondertiteling" + }, + "v3": { + "newSiteTitle": "De nieuwe versie is uit!", + "newDomain": "https://movie-web.app", + "newDomainText": "We gaan binnenkort verhuizen naar een nieuw domein: <0>https://movie-web.app. Pas je bladwijzers aan naar het nieuwe domein, want het oude domein gaat stoppen met werken op {{date}}.", + "tireless": "We hebben mega hard gewerkt aan deze nieuwe versie, dus we hopen dat je er van gaat genieten.", + "leaveAnnouncement": "Let's go!" + }, + "casting": { + "casting": "Aan het casten..." + }, + "errors": { + "offline": "Controleer je internetverbinding" + } +} diff --git a/src/setup/locales/tr/translation.json b/src/setup/locales/tr/translation.json new file mode 100644 index 00000000..326cc35d --- /dev/null +++ b/src/setup/locales/tr/translation.json @@ -0,0 +1,128 @@ +{ + "global": { + "name": "movie-web" + }, + "search": { + "loading_series": "Favori dizileriniz aranıyor...", + "loading_movie": "Favori filmleriniz aranıyor...", + "loading": "Yükleniyor...", + "allResults": "Bu kadarını bulabildik!", + "noResults": "Hiçbir şey bulamadık!", + "allFailed": "Medya bulunamadı, tekrar deneyin!", + "headingTitle": "Arama sonuçları", + "bookmarks": "Yerimleri", + "continueWatching": "İzlemeye devam edin", + "title": "Ne izlemek istersiniz?", + "placeholder": "Ne izlemek istersiniz?" + }, + "media": { + "movie": "Film", + "series": "Dizi", + "stopEditing": "Düzenlemeyi durdur", + "errors": { + "genericTitle": "Hay aksi, bozuldu!", + "failedMeta": "Önbilgi yüklenemedi", + "mediaFailed": "İstediğiniz medyaya istek atarken hata oluştu, internet bağlantınızı kontrol edin ve tekrar deneyin.", + "videoFailed": "İstediğiniz videoyu oynatırken bir sorunla karşılaştık. Bu durum devam ederse lütfen bunu <0>Discord sunucumuza veya <1>GitHub üzerinden bildiriniz." + } + }, + "seasons": { + "seasonAndEpisode": "S{{season}} B{{episode}}" + }, + "notFound": { + "genericTitle": "Bulunamadı", + "backArrow": "Geri", + "media": { + "title": "Medya bulunamadı", + "description": "İstediğiniz medyayı bulamadık. URL'i yanlış girdiniz ya da medya kaldırıldı." + }, + "provider": { + "title": "Bu sağlayıcı devre dışı bırakıldı", + "description": "Sağlayıcı ile ilgili bir sorun oluştu ya da kullanılacak kadar stabil değildi bu yüzden devre dışı bırakmak zorunda kaldık." + }, + "page": { + "title": "Sayfa bulunamadı", + "description": "Her yere baktık: bazanın altına, dolabın içine hatta ara sunucuya ama maalesef aradığınız sayfayı bulamadık." + } + }, + "searchBar": { + "movie": "Film", + "series": "Dizi", + "Search": "Ara" + }, + "videoPlayer": { + "findingBestVideo": "Sizin için en iyi videoyu buluyoruz...", + "noVideos": "Hay aksi, hiçbir video bulamadık", + "loading": "Yükleniyor...", + "backToHome": "Ana sayfaya dön", + "backToHomeShort": "Geri", + "seasonAndEpisode": "S{{season}} B{{episode}}", + "timeLeft": "{{timeLeft}} kaldı", + "finishAt": "{{timeFinished, datetime}}'de/da bitiyor", + "buttons": { + "episodes": "Bölümler", + "source": "Kaynak", + "captions": "Altyazılar", + "download": "İndir", + "settings": "Ayarlar", + "pictureInPicture": "Resim içinde Resim", + "playbackSpeed": "Oynatma Hızı" + }, + "popouts": { + "back": "Geri git", + "sources": "Kaynaklar", + "seasons": "Sezonlar", + "captions": "Altyazılar", + "playbackSpeed": "Oynatma hızı", + "customPlaybackSpeed": "Özel oynatma hızı", + "captionPreferences": { + "title": "Kişiselleştirme", + "delay": "Gecikme", + "fontSize": "Boyut", + "opacity": "Opaklık", + "color": "Renk" + }, + "episode": "B{{index}} - {{title}}", + "noCaptions": "Altyazı yok", + "linkedCaptions": "Kaynak Altyazıları", + "customCaption": "Özel altyazı", + "uploadCustomCaption": "Altyazı yükle", + "noEmbeds": "Bu kaynak için gömülü video bulunamadı", + + "errors": { + "loadingWentWong": "{{seasonTitle}} için bölümler yüklenirken bir hata oluştu", + "embedsError": "İstediğiniz şey için gömülü video bulunurken bir hata oluştu" + }, + "descriptions": { + "sources": "Hangi sağlayıcıyı kullanmak istersiniz?", + "embeds": "Görüntülemek istediğiniz videoyu seçiniz", + "seasons": "İzlemek istediğiniz sezonu seçiniz", + "episode": "Bir bölüm seçiniz", + "captions": "Altyazı dili seçiniz", + "captionPreferences": "Altyazıları istediğiniz gibi ayarlayın", + "playbackSpeed": "Oynatma hızınızı değiştirin" + } + }, + "errors": { + "fatalError": "Video oynatıcıda bir hata oluştu, lütfen bunu <0>Discord sunucumuzda ya da <1>GitHub üzeriden bildiriniz." + } + }, + "settings": { + "title": "Ayarlar", + "language": "Dil", + "captionLanguage": "Altyazı Dili" + }, + "v3": { + "newSiteTitle": "Yeni sürüm yayınlandı!", + "newDomain": "https://movie-web.app", + "newDomainText": "movie-web yakında yeni bir alan adına taşınacak: <0>https://movie-web.app. <1>{{date}} tarihinde eski site çalışmayacağı için yerimlerinizi güncellemeyi unutmayın.", + "tireless": "Bu yeni güncelleme için gece gündüz çalıştık, umarız aylardan beri hazırladığımız bu güncellemeyi beğenirsiniz.", + "leaveAnnouncement": "Götür beni!" + }, + "casting": { + "casting": "Cihaza aktarılıyor..." + }, + "errors": { + "offline": "İnternet bağlantınızı kontrol ediniz" + } +} diff --git a/src/setup/sentry.tsx b/src/setup/sentry.tsx new file mode 100644 index 00000000..268b31d7 --- /dev/null +++ b/src/setup/sentry.tsx @@ -0,0 +1,16 @@ +import { CaptureConsole, HttpClient } from "@sentry/integrations"; +import * as Sentry from "@sentry/react"; + +import { conf } from "@/setup/config"; +import { SENTRY_DSN } from "@/setup/constants"; + +Sentry.init({ + dsn: SENTRY_DSN, + release: `movie-web@${conf().APP_VERSION}`, + sampleRate: 0.5, + integrations: [ + new Sentry.BrowserTracing(), + new CaptureConsole(), + new HttpClient(), + ], +}); diff --git a/src/state/bookmark/context.tsx b/src/state/bookmark/context.tsx index 6252ceac..9dca821f 100644 --- a/src/state/bookmark/context.tsx +++ b/src/state/bookmark/context.tsx @@ -1,6 +1,8 @@ +import { ReactNode, createContext, useContext, useMemo } from "react"; + import { MWMediaMeta } from "@/backend/metadata/types"; import { useStore } from "@/utils/storage"; -import { createContext, ReactNode, useContext, useMemo } from "react"; + import { BookmarkStore } from "./store"; import { BookmarkStoreData } from "./types"; diff --git a/src/state/bookmark/store.ts b/src/state/bookmark/store.ts index 11bec1c5..1b7a2053 100644 --- a/src/state/bookmark/store.ts +++ b/src/state/bookmark/store.ts @@ -1,6 +1,7 @@ import { createVersionedStore } from "@/utils/storage"; -import { migrateV1Bookmarks, OldBookmarks } from "../watched/migrations/v2"; + import { BookmarkStoreData } from "./types"; +import { OldBookmarks, migrateV1Bookmarks } from "../watched/migrations/v2"; export const BookmarkStore = createVersionedStore() .setKey("mw-bookmarks") diff --git a/src/state/settings/context.tsx b/src/state/settings/context.tsx index 8efba361..4810f925 100644 --- a/src/state/settings/context.tsx +++ b/src/state/settings/context.tsx @@ -1,6 +1,8 @@ -import { useStore } from "@/utils/storage"; -import { createContext, ReactNode, useContext, useMemo } from "react"; +import { ReactNode, createContext, useContext, useMemo } from "react"; + import { LangCode } from "@/setup/iso6391"; +import { useStore } from "@/utils/storage"; + import { SettingsStore } from "./store"; import { MWSettingsData } from "./types"; diff --git a/src/state/settings/store.ts b/src/state/settings/store.ts index 55ede71e..19d84e15 100644 --- a/src/state/settings/store.ts +++ b/src/state/settings/store.ts @@ -1,4 +1,5 @@ import { createVersionedStore } from "@/utils/storage"; + import { MWSettingsData, MWSettingsDataV1 } from "./types"; export const SettingsStore = createVersionedStore() diff --git a/src/state/watched/context.tsx b/src/state/watched/context.tsx index f45baf71..3ce17b2a 100644 --- a/src/state/watched/context.tsx +++ b/src/state/watched/context.tsx @@ -1,16 +1,18 @@ -import { DetailedMeta } from "@/backend/metadata/getmeta"; -import { MWMediaType } from "@/backend/metadata/types"; -import { useStore } from "@/utils/storage"; import { - createContext, ReactNode, + createContext, useCallback, useContext, useMemo, useRef, } from "react"; + +import { DetailedMeta } from "@/backend/metadata/getmeta"; +import { MWMediaType } from "@/backend/metadata/types"; +import { useStore } from "@/utils/storage"; + import { VideoProgressStore } from "./store"; -import { StoreMediaItem, WatchedStoreItem, WatchedStoreData } from "./types"; +import { StoreMediaItem, WatchedStoreData, WatchedStoreItem } from "./types"; const FIVETEEN_MINUTES = 15 * 60; const FIVE_MINUTES = 5 * 60; diff --git a/src/state/watched/migrations/v2.ts b/src/state/watched/migrations/v2.ts index de3dad44..8f7a56b6 100644 --- a/src/state/watched/migrations/v2.ts +++ b/src/state/watched/migrations/v2.ts @@ -2,6 +2,7 @@ import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta"; import { searchForMedia } from "@/backend/metadata/search"; import { MWMediaMeta, MWMediaType } from "@/backend/metadata/types"; import { compareTitle } from "@/utils/titleMatch"; + import { WatchedStoreData, WatchedStoreItem } from "../types"; interface OldMediaBase { diff --git a/src/state/watched/store.ts b/src/state/watched/store.ts index 84eefd67..95adef28 100644 --- a/src/state/watched/store.ts +++ b/src/state/watched/store.ts @@ -1,5 +1,6 @@ import { createVersionedStore } from "@/utils/storage"; -import { migrateV2Videos, OldData } from "./migrations/v2"; + +import { OldData, migrateV2Videos } from "./migrations/v2"; import { WatchedStoreData } from "./types"; export const VideoProgressStore = createVersionedStore() diff --git a/src/video/components/VideoPlayer.tsx b/src/video/components/VideoPlayer.tsx index 8e5888a1..6dc8983a 100644 --- a/src/video/components/VideoPlayer.tsx +++ b/src/video/components/VideoPlayer.tsx @@ -1,36 +1,38 @@ +import { ReactNode, useCallback, useState } from "react"; + import { Transition } from "@/components/Transition"; import { useIsMobile } from "@/hooks/useIsMobile"; import { AirplayAction } from "@/video/components/actions/AirplayAction"; import { BackdropAction } from "@/video/components/actions/BackdropAction"; +import { CastingTextAction } from "@/video/components/actions/CastingTextAction"; +import { ChromecastAction } from "@/video/components/actions/ChromecastAction"; import { FullscreenAction } from "@/video/components/actions/FullscreenAction"; import { HeaderAction } from "@/video/components/actions/HeaderAction"; +import { KeyboardShortcutsAction } from "@/video/components/actions/KeyboardShortcutsAction"; import { LoadingAction } from "@/video/components/actions/LoadingAction"; import { MiddlePauseAction } from "@/video/components/actions/MiddlePauseAction"; import { MobileCenterAction } from "@/video/components/actions/MobileCenterAction"; import { PageTitleAction } from "@/video/components/actions/PageTitleAction"; import { PauseAction } from "@/video/components/actions/PauseAction"; +import { PictureInPictureAction } from "@/video/components/actions/PictureInPictureAction"; import { ProgressAction } from "@/video/components/actions/ProgressAction"; import { SeriesSelectionAction } from "@/video/components/actions/SeriesSelectionAction"; import { ShowTitleAction } from "@/video/components/actions/ShowTitleAction"; -import { KeyboardShortcutsAction } from "@/video/components/actions/KeyboardShortcutsAction"; import { SkipTimeAction } from "@/video/components/actions/SkipTimeAction"; import { TimeAction } from "@/video/components/actions/TimeAction"; import { VolumeAction } from "@/video/components/actions/VolumeAction"; import { VideoPlayerError } from "@/video/components/parts/VideoPlayerError"; +import { PopoutProviderAction } from "@/video/components/popouts/PopoutProviderAction"; import { VideoPlayerBase, VideoPlayerBaseProps, } from "@/video/components/VideoPlayerBase"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; -import { ReactNode, useCallback, useState } from "react"; -import { PopoutProviderAction } from "@/video/components/popouts/PopoutProviderAction"; -import { ChromecastAction } from "@/video/components/actions/ChromecastAction"; -import { CastingTextAction } from "@/video/components/actions/CastingTextAction"; -import { PictureInPictureAction } from "@/video/components/actions/PictureInPictureAction"; + import { CaptionRendererAction } from "./actions/CaptionRendererAction"; -import { SettingsAction } from "./actions/SettingsAction"; import { DividerAction } from "./actions/DividerAction"; +import { SettingsAction } from "./actions/SettingsAction"; import { VolumeAdjustedAction } from "./actions/VolumeAdjustedAction"; type Props = VideoPlayerBaseProps; diff --git a/src/video/components/VideoPlayerBase.tsx b/src/video/components/VideoPlayerBase.tsx index 18f34ab0..62290da2 100644 --- a/src/video/components/VideoPlayerBase.tsx +++ b/src/video/components/VideoPlayerBase.tsx @@ -1,15 +1,17 @@ +import { useRef } from "react"; + import { CastingInternal } from "@/video/components/internal/CastingInternal"; import { WrapperRegisterInternal } from "@/video/components/internal/WrapperRegisterInternal"; import { VideoErrorBoundary } from "@/video/components/parts/VideoErrorBoundary"; import { useInterface } from "@/video/state/logic/interface"; import { useMeta } from "@/video/state/logic/meta"; -import { useRef } from "react"; -import { - useVideoPlayerDescriptor, - VideoPlayerContextProvider, -} from "../state/hooks"; + import { MetaAction } from "./actions/MetaAction"; import { VideoElementInternal } from "./internal/VideoElementInternal"; +import { + VideoPlayerContextProvider, + useVideoPlayerDescriptor, +} from "../state/hooks"; export interface VideoPlayerBaseProps { children?: diff --git a/src/video/components/actions/AirplayAction.tsx b/src/video/components/actions/AirplayAction.tsx index e963166e..58cad17b 100644 --- a/src/video/components/actions/AirplayAction.tsx +++ b/src/video/components/actions/AirplayAction.tsx @@ -1,8 +1,10 @@ +import { useCallback } from "react"; + import { Icons } from "@/components/Icon"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useMisc } from "@/video/state/logic/misc"; -import { useCallback } from "react"; + import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; interface Props { diff --git a/src/video/components/actions/BackdropAction.tsx b/src/video/components/actions/BackdropAction.tsx index e0a1f9eb..2aa60d38 100644 --- a/src/video/components/actions/BackdropAction.tsx +++ b/src/video/components/actions/BackdropAction.tsx @@ -1,8 +1,9 @@ +import React, { useCallback, useEffect, useRef, useState } from "react"; + import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useInterface } from "@/video/state/logic/interface"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; -import React, { useCallback, useEffect, useRef, useState } from "react"; interface BackdropActionProps { children?: React.ReactNode; diff --git a/src/video/components/actions/CaptionRendererAction.tsx b/src/video/components/actions/CaptionRendererAction.tsx index 664cffef..5c12b3cb 100644 --- a/src/video/components/actions/CaptionRendererAction.tsx +++ b/src/video/components/actions/CaptionRendererAction.tsx @@ -1,9 +1,11 @@ -import { Transition } from "@/components/Transition"; -import { useSettings } from "@/state/settings"; -import { sanitize, parseSubtitles } from "@/backend/helpers/captions"; -import { ContentCaption } from "subsrt-ts/dist/types/handler"; import { useRef } from "react"; import { useAsync } from "react-use"; +import { ContentCaption } from "subsrt-ts/dist/types/handler"; + +import { parseSubtitles, sanitize } from "@/backend/helpers/captions"; +import { Transition } from "@/components/Transition"; +import { useSettings } from "@/state/settings"; + import { useVideoPlayerDescriptor } from "../../state/hooks"; import { useProgress } from "../../state/logic/progress"; import { useSource } from "../../state/logic/source"; diff --git a/src/video/components/actions/CastingTextAction.tsx b/src/video/components/actions/CastingTextAction.tsx index d95a0351..780129b2 100644 --- a/src/video/components/actions/CastingTextAction.tsx +++ b/src/video/components/actions/CastingTextAction.tsx @@ -1,7 +1,8 @@ +import { useTranslation } from "react-i18next"; + import { Icon, Icons } from "@/components/Icon"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useMisc } from "@/video/state/logic/misc"; -import { useTranslation } from "react-i18next"; export function CastingTextAction() { const { t } = useTranslation(); diff --git a/src/video/components/actions/ChromecastAction.tsx b/src/video/components/actions/ChromecastAction.tsx index 7334af67..56106177 100644 --- a/src/video/components/actions/ChromecastAction.tsx +++ b/src/video/components/actions/ChromecastAction.tsx @@ -1,8 +1,9 @@ +import { useCallback, useEffect, useRef, useState } from "react"; + import { Icons } from "@/components/Icon"; import { VideoPlayerIconButton } from "@/video/components/parts/VideoPlayerIconButton"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useMisc } from "@/video/state/logic/misc"; -import { useCallback, useEffect, useRef, useState } from "react"; interface Props { className?: string; diff --git a/src/video/components/actions/DividerAction.tsx b/src/video/components/actions/DividerAction.tsx index ac1090f7..5778e16f 100644 --- a/src/video/components/actions/DividerAction.tsx +++ b/src/video/components/actions/DividerAction.tsx @@ -1,6 +1,6 @@ +import { MWMediaType } from "@/backend/metadata/types"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useMeta } from "@/video/state/logic/meta"; -import { MWMediaType } from "@/backend/metadata/types"; export function DividerAction() { const descriptor = useVideoPlayerDescriptor(); diff --git a/src/video/components/actions/FullscreenAction.tsx b/src/video/components/actions/FullscreenAction.tsx index 8d5a5f3c..feb1a64f 100644 --- a/src/video/components/actions/FullscreenAction.tsx +++ b/src/video/components/actions/FullscreenAction.tsx @@ -1,9 +1,11 @@ +import { useCallback } from "react"; + import { Icons } from "@/components/Icon"; import { canFullscreen } from "@/utils/detectFeatures"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useInterface } from "@/video/state/logic/interface"; -import { useCallback } from "react"; + import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; interface Props { diff --git a/src/video/components/actions/KeyboardShortcutsAction.tsx b/src/video/components/actions/KeyboardShortcutsAction.tsx index ba5ffc32..9040d8a5 100644 --- a/src/video/components/actions/KeyboardShortcutsAction.tsx +++ b/src/video/components/actions/KeyboardShortcutsAction.tsx @@ -1,11 +1,12 @@ import { useEffect, useRef } from "react"; + +import { useVolumeControl } from "@/hooks/useVolumeToggle"; +import { getPlayerState } from "@/video/state/cache"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useInterface } from "@/video/state/logic/interface"; -import { getPlayerState } from "@/video/state/cache"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useProgress } from "@/video/state/logic/progress"; -import { useVolumeControl } from "@/hooks/useVolumeToggle"; export function KeyboardShortcutsAction() { const descriptor = useVideoPlayerDescriptor(); @@ -60,7 +61,7 @@ export function KeyboardShortcutsAction() { // Mute case "m": - toggleVolume(); + toggleVolume(true); break; // Decrease volume diff --git a/src/video/components/actions/MetaAction.tsx b/src/video/components/actions/MetaAction.tsx index 35b2543d..db5ad6b4 100644 --- a/src/video/components/actions/MetaAction.tsx +++ b/src/video/components/actions/MetaAction.tsx @@ -1,9 +1,10 @@ +import { useEffect } from "react"; + import { MWCaption } from "@/backend/helpers/streams"; import { DetailedMeta } from "@/backend/metadata/getmeta"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useMeta } from "@/video/state/logic/meta"; import { useProgress } from "@/video/state/logic/progress"; -import { useEffect } from "react"; export type WindowMeta = { meta: DetailedMeta; diff --git a/src/video/components/actions/MiddlePauseAction.tsx b/src/video/components/actions/MiddlePauseAction.tsx index 1ed2fefc..fd5ba4f7 100644 --- a/src/video/components/actions/MiddlePauseAction.tsx +++ b/src/video/components/actions/MiddlePauseAction.tsx @@ -1,8 +1,9 @@ +import { useCallback } from "react"; + import { Icon, Icons } from "@/components/Icon"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; -import { useCallback } from "react"; export function MiddlePauseAction() { const descriptor = useVideoPlayerDescriptor(); diff --git a/src/video/components/actions/PageTitleAction.tsx b/src/video/components/actions/PageTitleAction.tsx index 21a2bf23..b3bf975e 100644 --- a/src/video/components/actions/PageTitleAction.tsx +++ b/src/video/components/actions/PageTitleAction.tsx @@ -1,5 +1,7 @@ -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { Helmet } from "react-helmet"; + +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; + import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo"; export function PageTitleAction() { diff --git a/src/video/components/actions/PauseAction.tsx b/src/video/components/actions/PauseAction.tsx index d57e4f4d..bfa39b65 100644 --- a/src/video/components/actions/PauseAction.tsx +++ b/src/video/components/actions/PauseAction.tsx @@ -1,8 +1,10 @@ +import { useCallback } from "react"; + import { Icons } from "@/components/Icon"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; -import { useCallback } from "react"; + import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; interface Props { diff --git a/src/video/components/actions/PictureInPictureAction.tsx b/src/video/components/actions/PictureInPictureAction.tsx index d60ec446..ac1094b7 100644 --- a/src/video/components/actions/PictureInPictureAction.tsx +++ b/src/video/components/actions/PictureInPictureAction.tsx @@ -1,13 +1,15 @@ +import { useCallback } from "react"; +import { useTranslation } from "react-i18next"; + import { Icons } from "@/components/Icon"; import { useIsMobile } from "@/hooks/useIsMobile"; -import { useTranslation } from "react-i18next"; -import { useControls } from "@/video/state/logic/controls"; -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; -import { useCallback } from "react"; import { canPictureInPicture, canWebkitPictureInPicture, } from "@/utils/detectFeatures"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useControls } from "@/video/state/logic/controls"; + import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; interface Props { diff --git a/src/video/components/actions/ProgressAction.tsx b/src/video/components/actions/ProgressAction.tsx index f8d28036..1e4ce3cf 100644 --- a/src/video/components/actions/ProgressAction.tsx +++ b/src/video/components/actions/ProgressAction.tsx @@ -1,3 +1,5 @@ +import { useCallback, useEffect, useRef } from "react"; + import { makePercentage, makePercentageString, @@ -7,7 +9,6 @@ import { getPlayerState } from "@/video/state/cache"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useProgress } from "@/video/state/logic/progress"; -import { useCallback, useEffect, useRef } from "react"; export function ProgressAction() { const descriptor = useVideoPlayerDescriptor(); diff --git a/src/video/components/actions/SeriesSelectionAction.tsx b/src/video/components/actions/SeriesSelectionAction.tsx index 4595eabe..d228b047 100644 --- a/src/video/components/actions/SeriesSelectionAction.tsx +++ b/src/video/components/actions/SeriesSelectionAction.tsx @@ -1,12 +1,13 @@ -import { Icons } from "@/components/Icon"; +import { useTranslation } from "react-i18next"; + import { MWMediaType } from "@/backend/metadata/types"; -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; -import { useMeta } from "@/video/state/logic/meta"; +import { Icons } from "@/components/Icon"; +import { FloatingAnchor } from "@/components/popout/FloatingAnchor"; import { VideoPlayerIconButton } from "@/video/components/parts/VideoPlayerIconButton"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useInterface } from "@/video/state/logic/interface"; -import { useTranslation } from "react-i18next"; -import { FloatingAnchor } from "@/components/popout/FloatingAnchor"; +import { useMeta } from "@/video/state/logic/meta"; interface Props { className?: string; diff --git a/src/video/components/actions/SettingsAction.tsx b/src/video/components/actions/SettingsAction.tsx index b012639a..df7b52e4 100644 --- a/src/video/components/actions/SettingsAction.tsx +++ b/src/video/components/actions/SettingsAction.tsx @@ -1,11 +1,12 @@ +import { useTranslation } from "react-i18next"; + import { Icons } from "@/components/Icon"; -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { FloatingAnchor } from "@/components/popout/FloatingAnchor"; +import { useIsMobile } from "@/hooks/useIsMobile"; import { VideoPlayerIconButton } from "@/video/components/parts/VideoPlayerIconButton"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useInterface } from "@/video/state/logic/interface"; -import { useIsMobile } from "@/hooks/useIsMobile"; -import { useTranslation } from "react-i18next"; -import { FloatingAnchor } from "@/components/popout/FloatingAnchor"; interface Props { className?: string; diff --git a/src/video/components/actions/ShowTitleAction.tsx b/src/video/components/actions/ShowTitleAction.tsx index a40c3faa..6ab9cac8 100644 --- a/src/video/components/actions/ShowTitleAction.tsx +++ b/src/video/components/actions/ShowTitleAction.tsx @@ -1,4 +1,5 @@ import { useVideoPlayerDescriptor } from "@/video/state/hooks"; + import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo"; export function ShowTitleAction() { diff --git a/src/video/components/actions/SkipTimeAction.tsx b/src/video/components/actions/SkipTimeAction.tsx index 117d31f0..11a5054d 100644 --- a/src/video/components/actions/SkipTimeAction.tsx +++ b/src/video/components/actions/SkipTimeAction.tsx @@ -2,6 +2,7 @@ import { Icons } from "@/components/Icon"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useProgress } from "@/video/state/logic/progress"; + import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; interface Props { diff --git a/src/video/components/actions/TimeAction.tsx b/src/video/components/actions/TimeAction.tsx index bab9e101..46a27b44 100644 --- a/src/video/components/actions/TimeAction.tsx +++ b/src/video/components/actions/TimeAction.tsx @@ -1,11 +1,12 @@ -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useTranslation } from "react-i18next"; + +import { useIsMobile } from "@/hooks/useIsMobile"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useControls } from "@/video/state/logic/controls"; +import { useInterface } from "@/video/state/logic/interface"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useProgress } from "@/video/state/logic/progress"; -import { useInterface } from "@/video/state/logic/interface"; import { VideoPlayerTimeFormat } from "@/video/state/types"; -import { useIsMobile } from "@/hooks/useIsMobile"; -import { useControls } from "@/video/state/logic/controls"; function durationExceedsHour(secs: number): boolean { return secs > 60 * 60; diff --git a/src/video/components/actions/VolumeAction.tsx b/src/video/components/actions/VolumeAction.tsx index c3aee7c1..e6922ab3 100644 --- a/src/video/components/actions/VolumeAction.tsx +++ b/src/video/components/actions/VolumeAction.tsx @@ -1,3 +1,5 @@ +import { useCallback, useEffect, useRef, useState } from "react"; + import { Icon, Icons } from "@/components/Icon"; import { makePercentage, @@ -10,7 +12,6 @@ import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useInterface } from "@/video/state/logic/interface"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; -import { useCallback, useEffect, useRef, useState } from "react"; interface Props { className?: string; diff --git a/src/video/components/actions/list-entries/CaptionsSelectionAction.tsx b/src/video/components/actions/list-entries/CaptionsSelectionAction.tsx index 8dfe2ec3..631eeba0 100644 --- a/src/video/components/actions/list-entries/CaptionsSelectionAction.tsx +++ b/src/video/components/actions/list-entries/CaptionsSelectionAction.tsx @@ -1,5 +1,7 @@ -import { Icons } from "@/components/Icon"; import { useTranslation } from "react-i18next"; + +import { Icons } from "@/components/Icon"; + import { PopoutListAction } from "../../popouts/PopoutUtils"; interface Props { diff --git a/src/video/components/actions/list-entries/DownloadAction.tsx b/src/video/components/actions/list-entries/DownloadAction.tsx index 76910efd..29b5244e 100644 --- a/src/video/components/actions/list-entries/DownloadAction.tsx +++ b/src/video/components/actions/list-entries/DownloadAction.tsx @@ -1,10 +1,12 @@ -import { Icons } from "@/components/Icon"; -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; -import { useSource } from "@/video/state/logic/source"; -import { MWStreamType } from "@/backend/helpers/streams"; -import { normalizeTitle } from "@/utils/normalizeTitle"; import { useTranslation } from "react-i18next"; + +import { MWStreamType } from "@/backend/helpers/streams"; +import { Icons } from "@/components/Icon"; +import { normalizeTitle } from "@/utils/normalizeTitle"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useMeta } from "@/video/state/logic/meta"; +import { useSource } from "@/video/state/logic/source"; + import { PopoutListAction } from "../../popouts/PopoutUtils"; export function DownloadAction() { diff --git a/src/video/components/actions/list-entries/PlaybackSpeedSelectionAction.tsx b/src/video/components/actions/list-entries/PlaybackSpeedSelectionAction.tsx index 983f345e..fdc3549f 100644 --- a/src/video/components/actions/list-entries/PlaybackSpeedSelectionAction.tsx +++ b/src/video/components/actions/list-entries/PlaybackSpeedSelectionAction.tsx @@ -1,5 +1,7 @@ -import { Icons } from "@/components/Icon"; import { useTranslation } from "react-i18next"; + +import { Icons } from "@/components/Icon"; + import { PopoutListAction } from "../../popouts/PopoutUtils"; interface Props { diff --git a/src/video/components/actions/list-entries/SourceSelectionAction.tsx b/src/video/components/actions/list-entries/SourceSelectionAction.tsx index 23e20f1c..8e84b020 100644 --- a/src/video/components/actions/list-entries/SourceSelectionAction.tsx +++ b/src/video/components/actions/list-entries/SourceSelectionAction.tsx @@ -1,7 +1,9 @@ -import { Icons } from "@/components/Icon"; import { useTranslation } from "react-i18next"; -import { PopoutListAction } from "../../popouts/PopoutUtils"; + +import { Icons } from "@/components/Icon"; + import { QualityDisplayAction } from "./QualityDisplayAction"; +import { PopoutListAction } from "../../popouts/PopoutUtils"; interface Props { onClick?: () => any; diff --git a/src/video/components/controllers/MetaController.tsx b/src/video/components/controllers/MetaController.tsx index 9159a0ab..ee6bc696 100644 --- a/src/video/components/controllers/MetaController.tsx +++ b/src/video/components/controllers/MetaController.tsx @@ -1,9 +1,10 @@ +import { useEffect } from "react"; + import { MWCaption } from "@/backend/helpers/streams"; import { MWSeasonWithEpisodeMeta } from "@/backend/metadata/types"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { VideoPlayerMeta } from "@/video/state/types"; -import { useEffect } from "react"; interface MetaControllerProps { data?: VideoPlayerMeta; diff --git a/src/video/components/controllers/ProgressListenerController.tsx b/src/video/components/controllers/ProgressListenerController.tsx index 1a1d2bd1..78e27bc8 100644 --- a/src/video/components/controllers/ProgressListenerController.tsx +++ b/src/video/components/controllers/ProgressListenerController.tsx @@ -1,10 +1,11 @@ -import { useEffect, useMemo, useRef } from "react"; import throttle from "lodash.throttle"; +import { useEffect, useMemo, useRef } from "react"; + import { useVideoPlayerDescriptor } from "@/video/state/hooks"; -import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; -import { useProgress } from "@/video/state/logic/progress"; import { useControls } from "@/video/state/logic/controls"; +import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMisc } from "@/video/state/logic/misc"; +import { useProgress } from "@/video/state/logic/progress"; interface Props { startAt?: number; diff --git a/src/video/components/controllers/SeriesController.tsx b/src/video/components/controllers/SeriesController.tsx index 481d3ce2..ba01d248 100644 --- a/src/video/components/controllers/SeriesController.tsx +++ b/src/video/components/controllers/SeriesController.tsx @@ -1,8 +1,9 @@ -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; -import { useMeta } from "@/video/state/logic/meta"; import { useEffect, useRef } from "react"; import { useHistory } from "react-router-dom"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useMeta } from "@/video/state/logic/meta"; + interface SeriesControllerProps { onSelect?: (state: { episodeId?: string; seasonId?: string }) => void; } diff --git a/src/video/components/controllers/SourceController.tsx b/src/video/components/controllers/SourceController.tsx index fe98a685..cf7475b8 100644 --- a/src/video/components/controllers/SourceController.tsx +++ b/src/video/components/controllers/SourceController.tsx @@ -1,3 +1,5 @@ +import { useEffect, useRef } from "react"; + import { getCaptionUrl, makeCaptionId } from "@/backend/helpers/captions"; import { MWCaption, @@ -9,7 +11,6 @@ import { useSettings } from "@/state/settings"; import { useInitialized } from "@/video/components/hooks/useInitialized"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; -import { useEffect, useRef } from "react"; interface SourceControllerProps { source: string; diff --git a/src/video/components/hooks/useCurrentSeriesEpisodeInfo.ts b/src/video/components/hooks/useCurrentSeriesEpisodeInfo.ts index 88ab2e31..6eb51170 100644 --- a/src/video/components/hooks/useCurrentSeriesEpisodeInfo.ts +++ b/src/video/components/hooks/useCurrentSeriesEpisodeInfo.ts @@ -1,8 +1,9 @@ -import { MWMediaType } from "@/backend/metadata/types"; -import { useMeta } from "@/video/state/logic/meta"; import { useMemo } from "react"; import { useTranslation } from "react-i18next"; +import { MWMediaType } from "@/backend/metadata/types"; +import { useMeta } from "@/video/state/logic/meta"; + export function useCurrentSeriesEpisodeInfo(descriptor: string) { const meta = useMeta(descriptor); const { t } = useTranslation(); diff --git a/src/video/components/hooks/useInitialized.ts b/src/video/components/hooks/useInitialized.ts index d46b786c..197b7dc5 100644 --- a/src/video/components/hooks/useInitialized.ts +++ b/src/video/components/hooks/useInitialized.ts @@ -1,6 +1,7 @@ -import { useMisc } from "@/video/state/logic/misc"; import { useMemo } from "react"; +import { useMisc } from "@/video/state/logic/misc"; + export function useInitialized(descriptor: string): { initialized: boolean } { const misc = useMisc(descriptor); const initialized = useMemo(() => !!misc.initalized, [misc]); diff --git a/src/video/components/hooks/useSyncPopouts.ts b/src/video/components/hooks/useSyncPopouts.ts index a7edee77..2a63b923 100644 --- a/src/video/components/hooks/useSyncPopouts.ts +++ b/src/video/components/hooks/useSyncPopouts.ts @@ -1,8 +1,9 @@ -import { ControlMethods, useControls } from "@/video/state/logic/controls"; -import { useInterface } from "@/video/state/logic/interface"; import { useEffect, useRef } from "react"; import { useHistory, useLocation } from "react-router-dom"; +import { ControlMethods, useControls } from "@/video/state/logic/controls"; +import { useInterface } from "@/video/state/logic/interface"; + function syncRouteToPopout( location: ReturnType, controls: ControlMethods diff --git a/src/video/components/internal/CastingInternal.tsx b/src/video/components/internal/CastingInternal.tsx index 9de8c1b1..8fc3556d 100644 --- a/src/video/components/internal/CastingInternal.tsx +++ b/src/video/components/internal/CastingInternal.tsx @@ -1,10 +1,11 @@ +import { useEffect, useMemo, useRef } from "react"; + import { useChromecastAvailable } from "@/hooks/useChromecastAvailable"; import { getPlayerState } from "@/video/state/cache"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { updateMisc, useMisc } from "@/video/state/logic/misc"; import { createCastingStateProvider } from "@/video/state/providers/castingStateProvider"; import { setProvider, unsetStateProvider } from "@/video/state/providers/utils"; -import { useEffect, useMemo, useRef } from "react"; export function CastingInternal() { const descriptor = useVideoPlayerDescriptor(); diff --git a/src/video/components/internal/VideoElementInternal.tsx b/src/video/components/internal/VideoElementInternal.tsx index dde47b71..8f2e3a92 100644 --- a/src/video/components/internal/VideoElementInternal.tsx +++ b/src/video/components/internal/VideoElementInternal.tsx @@ -1,9 +1,10 @@ +import { useEffect, useMemo, useRef } from "react"; + import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMisc } from "@/video/state/logic/misc"; import { setProvider, unsetStateProvider } from "@/video/state/providers/utils"; import { createVideoStateProvider } from "@/video/state/providers/videoStateProvider"; -import { useEffect, useMemo, useRef } from "react"; interface Props { autoPlay?: boolean; diff --git a/src/video/components/internal/WrapperRegisterInternal.tsx b/src/video/components/internal/WrapperRegisterInternal.tsx index 16457419..3dac4e13 100644 --- a/src/video/components/internal/WrapperRegisterInternal.tsx +++ b/src/video/components/internal/WrapperRegisterInternal.tsx @@ -1,7 +1,8 @@ +import { useEffect } from "react"; + import { getPlayerState } from "@/video/state/cache"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { updateMisc } from "@/video/state/logic/misc"; -import { useEffect } from "react"; export function WrapperRegisterInternal(props: { wrapper: HTMLDivElement | null; diff --git a/src/video/components/parts/VideoErrorBoundary.tsx b/src/video/components/parts/VideoErrorBoundary.tsx index 5c7cf291..8228f057 100644 --- a/src/video/components/parts/VideoErrorBoundary.tsx +++ b/src/video/components/parts/VideoErrorBoundary.tsx @@ -1,10 +1,12 @@ +import { Component } from "react"; +import { Trans } from "react-i18next"; +import type { ReactNode } from "react-router-dom/node_modules/@types/react/index"; + import { MWMediaMeta } from "@/backend/metadata/types"; import { ErrorMessage } from "@/components/layout/ErrorBoundary"; import { Link } from "@/components/text/Link"; import { conf } from "@/setup/config"; -import { Component } from "react"; -import { Trans } from "react-i18next"; -import type { ReactNode } from "react-router-dom/node_modules/@types/react/index"; + import { VideoPlayerHeader } from "./VideoPlayerHeader"; interface ErrorBoundaryState { diff --git a/src/video/components/parts/VideoPlayerError.tsx b/src/video/components/parts/VideoPlayerError.tsx index 6ac7125c..d6fd0306 100644 --- a/src/video/components/parts/VideoPlayerError.tsx +++ b/src/video/components/parts/VideoPlayerError.tsx @@ -1,10 +1,12 @@ +import { ReactNode } from "react"; + import { IconPatch } from "@/components/buttons/IconPatch"; import { Icons } from "@/components/Icon"; import { Title } from "@/components/text/Title"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useError } from "@/video/state/logic/error"; import { useMeta } from "@/video/state/logic/meta"; -import { ReactNode } from "react"; + import { VideoPlayerHeader } from "./VideoPlayerHeader"; interface VideoPlayerErrorProps { diff --git a/src/video/components/parts/VideoPlayerHeader.tsx b/src/video/components/parts/VideoPlayerHeader.tsx index 950f1a97..8c026c49 100644 --- a/src/video/components/parts/VideoPlayerHeader.tsx +++ b/src/video/components/parts/VideoPlayerHeader.tsx @@ -1,16 +1,17 @@ +import { useTranslation } from "react-i18next"; + import { MWMediaMeta } from "@/backend/metadata/types"; import { IconPatch } from "@/components/buttons/IconPatch"; import { Icon, Icons } from "@/components/Icon"; import { BrandPill } from "@/components/layout/BrandPill"; +import { useBannerSize } from "@/hooks/useBanner"; +import { useIsMobile } from "@/hooks/useIsMobile"; import { getIfBookmarkedFromPortable, useBookmarkContext, } from "@/state/bookmark"; import { AirplayAction } from "@/video/components/actions/AirplayAction"; import { ChromecastAction } from "@/video/components/actions/ChromecastAction"; -import { useTranslation } from "react-i18next"; -import { useIsMobile } from "@/hooks/useIsMobile"; -import { useBannerSize } from "@/hooks/useBanner"; interface VideoPlayerHeaderProps { media?: MWMediaMeta; diff --git a/src/video/components/parts/VideoPlayerIconButton.tsx b/src/video/components/parts/VideoPlayerIconButton.tsx index 156dffd5..a47eeb8d 100644 --- a/src/video/components/parts/VideoPlayerIconButton.tsx +++ b/src/video/components/parts/VideoPlayerIconButton.tsx @@ -1,6 +1,7 @@ -import { Icon, Icons } from "@/components/Icon"; import React, { forwardRef } from "react"; +import { Icon, Icons } from "@/components/Icon"; + export interface VideoPlayerIconButtonProps { onClick?: (e: React.MouseEvent) => void; icon: Icons; diff --git a/src/video/components/parts/VideoPopout.tsx b/src/video/components/parts/VideoPopout.tsx index 301d0366..cd7aa1f3 100644 --- a/src/video/components/parts/VideoPopout.tsx +++ b/src/video/components/parts/VideoPopout.tsx @@ -1,7 +1,8 @@ +import { useEffect, useRef } from "react"; + import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useInterface } from "@/video/state/logic/interface"; -import { useEffect, useRef } from "react"; interface Props { children?: React.ReactNode; diff --git a/src/video/components/popouts/CaptionSelectionPopout.tsx b/src/video/components/popouts/CaptionSelectionPopout.tsx index 3f595757..3b119ef4 100644 --- a/src/video/components/popouts/CaptionSelectionPopout.tsx +++ b/src/video/components/popouts/CaptionSelectionPopout.tsx @@ -1,3 +1,6 @@ +import { useMemo, useRef } from "react"; +import { useTranslation } from "react-i18next"; + import { customCaption, getCaptionUrl, @@ -15,8 +18,7 @@ import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useMeta } from "@/video/state/logic/meta"; import { useSource } from "@/video/state/logic/source"; -import { useMemo, useRef } from "react"; -import { useTranslation } from "react-i18next"; + import { PopoutListEntry, PopoutSection } from "./PopoutUtils"; export function CaptionSelectionPopout(props: { diff --git a/src/video/components/popouts/CaptionSettingsPopout.tsx b/src/video/components/popouts/CaptionSettingsPopout.tsx index 3e5a0cd1..a5abe5a6 100644 --- a/src/video/components/popouts/CaptionSettingsPopout.tsx +++ b/src/video/components/popouts/CaptionSettingsPopout.tsx @@ -1,13 +1,13 @@ -import { FloatingCardView } from "@/components/popout/FloatingCard"; -import { FloatingView } from "@/components/popout/FloatingView"; -import { useFloatingRouter } from "@/hooks/useFloatingRouter"; -import { useSettings } from "@/state/settings"; import { useTranslation } from "react-i18next"; -import { Slider } from "@/components/Slider"; import CaptionColorSelector, { colors, } from "@/components/CaptionColorSelector"; +import { FloatingCardView } from "@/components/popout/FloatingCard"; +import { FloatingView } from "@/components/popout/FloatingView"; +import { Slider } from "@/components/Slider"; +import { useFloatingRouter } from "@/hooks/useFloatingRouter"; +import { useSettings } from "@/state/settings"; export function CaptionSettingsPopout(props: { router: ReturnType; diff --git a/src/video/components/popouts/EpisodeSelectionPopout.tsx b/src/video/components/popouts/EpisodeSelectionPopout.tsx index 02804b84..bd152378 100644 --- a/src/video/components/popouts/EpisodeSelectionPopout.tsx +++ b/src/video/components/popouts/EpisodeSelectionPopout.tsx @@ -1,20 +1,22 @@ import { useCallback, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; import { useParams } from "react-router-dom"; -import { Icon, Icons } from "@/components/Icon"; -import { useLoading } from "@/hooks/useLoading"; -import { MWMediaType, MWSeasonWithEpisodeMeta } from "@/backend/metadata/types"; + import { getMetaFromId } from "@/backend/metadata/getmeta"; import { decodeJWId } from "@/backend/metadata/justwatch"; -import { Loading } from "@/components/layout/Loading"; +import { MWMediaType, MWSeasonWithEpisodeMeta } from "@/backend/metadata/types"; import { IconPatch } from "@/components/buttons/IconPatch"; -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; -import { useMeta } from "@/video/state/logic/meta"; -import { useControls } from "@/video/state/logic/controls"; -import { useWatchedContext } from "@/state/watched"; -import { useTranslation } from "react-i18next"; +import { Icon, Icons } from "@/components/Icon"; +import { Loading } from "@/components/layout/Loading"; +import { FloatingCardView } from "@/components/popout/FloatingCard"; import { FloatingView } from "@/components/popout/FloatingView"; import { useFloatingRouter } from "@/hooks/useFloatingRouter"; -import { FloatingCardView } from "@/components/popout/FloatingCard"; +import { useLoading } from "@/hooks/useLoading"; +import { useWatchedContext } from "@/state/watched"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useControls } from "@/video/state/logic/controls"; +import { useMeta } from "@/video/state/logic/meta"; + import { PopoutListEntry } from "./PopoutUtils"; export function EpisodeSelectionPopout() { diff --git a/src/video/components/popouts/PlaybackSpeedPopout.tsx b/src/video/components/popouts/PlaybackSpeedPopout.tsx index 1013647a..87c75980 100644 --- a/src/video/components/popouts/PlaybackSpeedPopout.tsx +++ b/src/video/components/popouts/PlaybackSpeedPopout.tsx @@ -1,12 +1,14 @@ +import { useTranslation } from "react-i18next"; + import { Icon, Icons } from "@/components/Icon"; import { FloatingCardView } from "@/components/popout/FloatingCard"; import { FloatingView } from "@/components/popout/FloatingView"; +import { Slider } from "@/components/Slider"; import { useFloatingRouter } from "@/hooks/useFloatingRouter"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; -import { useTranslation } from "react-i18next"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; -import { Slider } from "@/components/Slider"; + import { PopoutListEntry, PopoutSection } from "./PopoutUtils"; const speedSelectionOptions = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2]; diff --git a/src/video/components/popouts/PopoutAnchor.tsx b/src/video/components/popouts/PopoutAnchor.tsx index 3439f468..c0d4eb9d 100644 --- a/src/video/components/popouts/PopoutAnchor.tsx +++ b/src/video/components/popouts/PopoutAnchor.tsx @@ -1,7 +1,8 @@ +import { ReactNode, useEffect, useRef } from "react"; + import { getPlayerState } from "@/video/state/cache"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { updateInterface } from "@/video/state/logic/interface"; -import { ReactNode, useEffect, useRef } from "react"; interface Props { for: string; diff --git a/src/video/components/popouts/PopoutProviderAction.tsx b/src/video/components/popouts/PopoutProviderAction.tsx index 3c90d46d..5882dc7f 100644 --- a/src/video/components/popouts/PopoutProviderAction.tsx +++ b/src/video/components/popouts/PopoutProviderAction.tsx @@ -1,12 +1,13 @@ +import { useCallback } from "react"; + +import { PopoutFloatingCard } from "@/components/popout/FloatingCard"; +import { FloatingContainer } from "@/components/popout/FloatingContainer"; import { useSyncPopouts } from "@/video/components/hooks/useSyncPopouts"; import { EpisodeSelectionPopout } from "@/video/components/popouts/EpisodeSelectionPopout"; import { SettingsPopout } from "@/video/components/popouts/SettingsPopout"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { useInterface } from "@/video/state/logic/interface"; -import { useCallback } from "react"; -import { PopoutFloatingCard } from "@/components/popout/FloatingCard"; -import { FloatingContainer } from "@/components/popout/FloatingContainer"; import "./Popouts.css"; diff --git a/src/video/components/popouts/PopoutUtils.tsx b/src/video/components/popouts/PopoutUtils.tsx index a56d1a91..c818d086 100644 --- a/src/video/components/popouts/PopoutUtils.tsx +++ b/src/video/components/popouts/PopoutUtils.tsx @@ -1,8 +1,9 @@ -import { Icon, Icons } from "@/components/Icon"; -import { Spinner } from "@/components/layout/Spinner"; -import { ProgressRing } from "@/components/layout/ProgressRing"; import { createRef, useEffect, useRef } from "react"; +import { Icon, Icons } from "@/components/Icon"; +import { ProgressRing } from "@/components/layout/ProgressRing"; +import { Spinner } from "@/components/layout/Spinner"; + interface PopoutListEntryBaseTypes { active?: boolean; children: React.ReactNode; diff --git a/src/video/components/popouts/SettingsPopout.tsx b/src/video/components/popouts/SettingsPopout.tsx index 9c92575e..03a45620 100644 --- a/src/video/components/popouts/SettingsPopout.tsx +++ b/src/video/components/popouts/SettingsPopout.tsx @@ -2,14 +2,15 @@ import { FloatingCardView } from "@/components/popout/FloatingCard"; import { FloatingDragHandle } from "@/components/popout/FloatingDragHandle"; import { FloatingView } from "@/components/popout/FloatingView"; import { useFloatingRouter } from "@/hooks/useFloatingRouter"; -import { DownloadAction } from "@/video/components/actions/list-entries/DownloadAction"; import { CaptionsSelectionAction } from "@/video/components/actions/list-entries/CaptionsSelectionAction"; -import { SourceSelectionAction } from "@/video/components/actions/list-entries/SourceSelectionAction"; +import { DownloadAction } from "@/video/components/actions/list-entries/DownloadAction"; import { PlaybackSpeedSelectionAction } from "@/video/components/actions/list-entries/PlaybackSpeedSelectionAction"; +import { SourceSelectionAction } from "@/video/components/actions/list-entries/SourceSelectionAction"; + import { CaptionSelectionPopout } from "./CaptionSelectionPopout"; -import { SourceSelectionPopout } from "./SourceSelectionPopout"; import { CaptionSettingsPopout } from "./CaptionSettingsPopout"; import { PlaybackSpeedPopout } from "./PlaybackSpeedPopout"; +import { SourceSelectionPopout } from "./SourceSelectionPopout"; export function SettingsPopout() { const floatingRouter = useFloatingRouter(); diff --git a/src/video/components/popouts/SourceSelectionPopout.tsx b/src/video/components/popouts/SourceSelectionPopout.tsx index 62bec772..21ed0c86 100644 --- a/src/video/components/popouts/SourceSelectionPopout.tsx +++ b/src/video/components/popouts/SourceSelectionPopout.tsx @@ -1,24 +1,26 @@ import { useMemo, useRef, useState } from "react"; -import { Icons } from "@/components/Icon"; -import { useLoading } from "@/hooks/useLoading"; -import { Loading } from "@/components/layout/Loading"; -import { IconPatch } from "@/components/buttons/IconPatch"; -import { useVideoPlayerDescriptor } from "@/video/state/hooks"; -import { useMeta } from "@/video/state/logic/meta"; -import { useControls } from "@/video/state/logic/controls"; -import { MWStream } from "@/backend/helpers/streams"; +import { useTranslation } from "react-i18next"; + +import { MWEmbed, MWEmbedType } from "@/backend/helpers/embed"; +import { MWProviderScrapeResult } from "@/backend/helpers/provider"; import { getEmbedScraperByType, getProviders, } from "@/backend/helpers/register"; import { runEmbedScraper, runProvider } from "@/backend/helpers/run"; -import { MWProviderScrapeResult } from "@/backend/helpers/provider"; -import { useTranslation } from "react-i18next"; -import { MWEmbed, MWEmbedType } from "@/backend/helpers/embed"; +import { MWStream } from "@/backend/helpers/streams"; +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { Loading } from "@/components/layout/Loading"; import { FloatingCardView } from "@/components/popout/FloatingCard"; import { FloatingView } from "@/components/popout/FloatingView"; import { useFloatingRouter } from "@/hooks/useFloatingRouter"; +import { useLoading } from "@/hooks/useLoading"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useControls } from "@/video/state/logic/controls"; +import { useMeta } from "@/video/state/logic/meta"; import { useSource } from "@/video/state/logic/source"; + import { PopoutListEntry } from "./PopoutUtils"; interface EmbedEntryProps { diff --git a/src/video/state/hooks.tsx b/src/video/state/hooks.tsx index c320d81b..6c532bf7 100644 --- a/src/video/state/hooks.tsx +++ b/src/video/state/hooks.tsx @@ -1,10 +1,11 @@ import { - createContext, ReactNode, + createContext, useContext, useEffect, useState, } from "react"; + import { registerVideoPlayer, unregisterVideoPlayer } from "./init"; const VideoPlayerContext = createContext(""); diff --git a/src/video/state/init.ts b/src/video/state/init.ts index 559c4ca4..cf8f0137 100644 --- a/src/video/state/init.ts +++ b/src/video/state/init.ts @@ -1,4 +1,5 @@ import { nanoid } from "nanoid"; + import { _players } from "./cache"; import { VideoPlayerState } from "./types"; diff --git a/src/video/state/logic/controls.ts b/src/video/state/logic/controls.ts index e87a5255..0824b601 100644 --- a/src/video/state/logic/controls.ts +++ b/src/video/state/logic/controls.ts @@ -2,6 +2,7 @@ import { updateInterface } from "@/video/state/logic/interface"; import { updateMeta } from "@/video/state/logic/meta"; import { updateProgress } from "@/video/state/logic/progress"; import { VideoPlayerMeta, VideoPlayerTimeFormat } from "@/video/state/types"; + import { getPlayerState } from "../cache"; import { VideoPlayerStateController } from "../providers/providerTypes"; diff --git a/src/video/state/logic/error.ts b/src/video/state/logic/error.ts index d3958337..0407a65a 100644 --- a/src/video/state/logic/error.ts +++ b/src/video/state/logic/error.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; + import { getPlayerState } from "../cache"; import { listenEvent, sendEvent, unlistenEvent } from "../events"; import { VideoPlayerState } from "../types"; diff --git a/src/video/state/logic/interface.ts b/src/video/state/logic/interface.ts index 35ab51c6..2b064944 100644 --- a/src/video/state/logic/interface.ts +++ b/src/video/state/logic/interface.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; + import { getPlayerState } from "../cache"; import { listenEvent, sendEvent, unlistenEvent } from "../events"; import { VideoPlayerState, VideoPlayerTimeFormat } from "../types"; diff --git a/src/video/state/logic/mediaplaying.ts b/src/video/state/logic/mediaplaying.ts index ff631064..a681a0dc 100644 --- a/src/video/state/logic/mediaplaying.ts +++ b/src/video/state/logic/mediaplaying.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; + import { getPlayerState } from "../cache"; import { listenEvent, sendEvent, unlistenEvent } from "../events"; import { VideoPlayerState } from "../types"; diff --git a/src/video/state/logic/meta.ts b/src/video/state/logic/meta.ts index 35e6ad79..95907774 100644 --- a/src/video/state/logic/meta.ts +++ b/src/video/state/logic/meta.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; + import { getPlayerState } from "../cache"; import { listenEvent, sendEvent, unlistenEvent } from "../events"; import { VideoPlayerMeta, VideoPlayerState } from "../types"; diff --git a/src/video/state/logic/misc.ts b/src/video/state/logic/misc.ts index a30a146a..01088621 100644 --- a/src/video/state/logic/misc.ts +++ b/src/video/state/logic/misc.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; + import { getPlayerState } from "../cache"; import { listenEvent, sendEvent, unlistenEvent } from "../events"; import { VideoPlayerState } from "../types"; diff --git a/src/video/state/logic/progress.ts b/src/video/state/logic/progress.ts index b2482c0e..051450e5 100644 --- a/src/video/state/logic/progress.ts +++ b/src/video/state/logic/progress.ts @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; + import { getPlayerState } from "../cache"; import { listenEvent, sendEvent, unlistenEvent } from "../events"; import { VideoPlayerState } from "../types"; diff --git a/src/video/state/logic/source.ts b/src/video/state/logic/source.ts index 6f2d0afb..5fafb60c 100644 --- a/src/video/state/logic/source.ts +++ b/src/video/state/logic/source.ts @@ -1,5 +1,7 @@ -import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams"; import { useEffect, useState } from "react"; + +import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams"; + import { getPlayerState } from "../cache"; import { listenEvent, sendEvent, unlistenEvent } from "../events"; import { VideoPlayerState } from "../types"; diff --git a/src/video/state/providers/castingStateProvider.ts b/src/video/state/providers/castingStateProvider.ts index faf34dc5..e791c2f9 100644 --- a/src/video/state/providers/castingStateProvider.ts +++ b/src/video/state/providers/castingStateProvider.ts @@ -1,21 +1,23 @@ import fscreen from "fscreen"; + +import { revokeCaptionBlob } from "@/backend/helpers/captions"; import { canChangeVolume, canFullscreen, canFullscreenAnyElement, canWebkitFullscreen, } from "@/utils/detectFeatures"; -import { updateSource } from "@/video/state/logic/source"; import { getStoredVolume, setStoredVolume, } from "@/video/components/hooks/volumeStore"; -import { resetStateForSource } from "@/video/state/providers/helpers"; import { updateInterface } from "@/video/state/logic/interface"; -import { revokeCaptionBlob } from "@/backend/helpers/captions"; +import { updateSource } from "@/video/state/logic/source"; +import { resetStateForSource } from "@/video/state/providers/helpers"; + +import { VideoPlayerStateProvider } from "./providerTypes"; import { getPlayerState } from "../cache"; import { updateMediaPlaying } from "../logic/mediaplaying"; -import { VideoPlayerStateProvider } from "./providerTypes"; import { updateProgress } from "../logic/progress"; // TODO HLS for casting? diff --git a/src/video/state/providers/utils.ts b/src/video/state/providers/utils.ts index 9d5d47e5..f07e7c50 100644 --- a/src/video/state/providers/utils.ts +++ b/src/video/state/providers/utils.ts @@ -1,6 +1,7 @@ import { updateMisc } from "@/video/state/logic/misc"; -import { getPlayerState } from "../cache"; + import { VideoPlayerStateProvider } from "./providerTypes"; +import { getPlayerState } from "../cache"; export function setProvider( descriptor: string, diff --git a/src/video/state/providers/videoStateProvider.ts b/src/video/state/providers/videoStateProvider.ts index e527419b..2f8c5beb 100644 --- a/src/video/state/providers/videoStateProvider.ts +++ b/src/video/state/providers/videoStateProvider.ts @@ -1,29 +1,31 @@ -import Hls from "hls.js"; import fscreen from "fscreen"; +import Hls from "hls.js"; + +import { revokeCaptionBlob } from "@/backend/helpers/captions"; +import { MWStreamType } from "@/backend/helpers/streams"; import { canChangeVolume, canFullscreen, canFullscreenAnyElement, - canWebkitFullscreen, canPictureInPicture, + canWebkitFullscreen, canWebkitPictureInPicture, } from "@/utils/detectFeatures"; -import { MWStreamType } from "@/backend/helpers/streams"; -import { updateInterface } from "@/video/state/logic/interface"; -import { updateSource } from "@/video/state/logic/source"; import { getStoredVolume, setStoredVolume, } from "@/video/components/hooks/volumeStore"; import { updateError } from "@/video/state/logic/error"; +import { updateInterface } from "@/video/state/logic/interface"; import { updateMisc } from "@/video/state/logic/misc"; +import { updateSource } from "@/video/state/logic/source"; import { resetStateForSource } from "@/video/state/providers/helpers"; -import { revokeCaptionBlob } from "@/backend/helpers/captions"; + +import { VideoPlayerStateProvider } from "./providerTypes"; +import { handleBuffered } from "./utils"; import { getPlayerState } from "../cache"; import { updateMediaPlaying } from "../logic/mediaplaying"; -import { VideoPlayerStateProvider } from "./providerTypes"; import { updateProgress } from "../logic/progress"; -import { handleBuffered } from "./utils"; function errorMessage(err: MediaError) { switch (err.code) { diff --git a/src/video/state/types.ts b/src/video/state/types.ts index 5782d7c1..9a6f3987 100644 --- a/src/video/state/types.ts +++ b/src/video/state/types.ts @@ -1,10 +1,12 @@ +import Hls from "hls.js"; + import { MWCaption, MWStreamQuality, MWStreamType, } from "@/backend/helpers/streams"; import { DetailedMeta } from "@/backend/metadata/getmeta"; -import Hls from "hls.js"; + import { VideoPlayerStateProvider } from "./providers/providerTypes"; export type VideoPlayerMeta = { diff --git a/src/views/SettingsModal.tsx b/src/views/SettingsModal.tsx index b3ba74ed..47de7888 100644 --- a/src/views/SettingsModal.tsx +++ b/src/views/SettingsModal.tsx @@ -1,21 +1,22 @@ +import { useMemo } from "react"; +import { useTranslation } from "react-i18next"; + +import CaptionColorSelector, { + colors, +} from "@/components/CaptionColorSelector"; import { Dropdown } from "@/components/Dropdown"; import { Icon, Icons } from "@/components/Icon"; import { Modal, ModalCard } from "@/components/layout/Modal"; -import { useSettings } from "@/state/settings"; -import { useTranslation } from "react-i18next"; -import { CaptionCue } from "@/video/components/actions/CaptionRendererAction"; +import { Slider } from "@/components/Slider"; +import { conf } from "@/setup/config"; +import { appLanguageOptions } from "@/setup/i18n"; import { CaptionLanguageOption, LangCode, captionLanguages, } from "@/setup/iso6391"; -import { useMemo } from "react"; -import { appLanguageOptions } from "@/setup/i18n"; -import CaptionColorSelector, { - colors, -} from "@/components/CaptionColorSelector"; -import { Slider } from "@/components/Slider"; -import { conf } from "@/setup/config"; +import { useSettings } from "@/state/settings"; +import { CaptionCue } from "@/video/components/actions/CaptionRendererAction"; export default function SettingsModal(props: { onClose: () => void; diff --git a/src/views/developer/EmbedTesterView.tsx b/src/views/developer/EmbedTesterView.tsx index 9b659bb7..15315ea4 100644 --- a/src/views/developer/EmbedTesterView.tsx +++ b/src/views/developer/EmbedTesterView.tsx @@ -1,3 +1,5 @@ +import { ReactNode, useCallback, useEffect, useMemo, useState } from "react"; + import { MWEmbed, MWEmbedScraper, MWEmbedType } from "@/backend/helpers/embed"; import { getEmbeds } from "@/backend/helpers/register"; import { runEmbedScraper } from "@/backend/helpers/run"; @@ -7,7 +9,6 @@ import { Navigation } from "@/components/layout/Navigation"; import { ArrowLink } from "@/components/text/ArrowLink"; import { Title } from "@/components/text/Title"; import { useLoading } from "@/hooks/useLoading"; -import { ReactNode, useCallback, useEffect, useMemo, useState } from "react"; interface MediaSelectorProps { embedType: MWEmbedType; diff --git a/src/views/developer/ProviderTesterView.tsx b/src/views/developer/ProviderTesterView.tsx index 0862b2b8..45f2297b 100644 --- a/src/views/developer/ProviderTesterView.tsx +++ b/src/views/developer/ProviderTesterView.tsx @@ -1,3 +1,6 @@ +import { ReactNode, useEffect, useState } from "react"; + +import { testData } from "@/__tests__/providers/testdata"; import { MWProviderScrapeResult } from "@/backend/helpers/provider"; import { getProviders } from "@/backend/helpers/register"; import { runProvider } from "@/backend/helpers/run"; @@ -6,8 +9,6 @@ import { Navigation } from "@/components/layout/Navigation"; import { ArrowLink } from "@/components/text/ArrowLink"; import { Title } from "@/components/text/Title"; import { useLoading } from "@/hooks/useLoading"; -import { testData } from "@/__tests__/providers/testdata"; -import { ReactNode, useEffect, useState } from "react"; interface MediaSelectorProps { onSelect: (meta: DetailedMeta) => void; diff --git a/src/views/developer/VideoTesterView.tsx b/src/views/developer/VideoTesterView.tsx index 2291470e..4c3cb7e5 100644 --- a/src/views/developer/VideoTesterView.tsx +++ b/src/views/developer/VideoTesterView.tsx @@ -1,3 +1,6 @@ +import { useCallback, useState } from "react"; +import { Helmet } from "react-helmet"; + import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams"; import { DetailedMeta } from "@/backend/metadata/getmeta"; import { MWMediaType } from "@/backend/metadata/types"; @@ -8,8 +11,6 @@ import { ThinContainer } from "@/components/layout/ThinContainer"; import { MetaController } from "@/video/components/controllers/MetaController"; import { SourceController } from "@/video/components/controllers/SourceController"; import { VideoPlayer } from "@/video/components/VideoPlayer"; -import { useCallback, useState } from "react"; -import { Helmet } from "react-helmet"; interface VideoData { streamUrl: string; diff --git a/src/views/media/MediaErrorView.tsx b/src/views/media/MediaErrorView.tsx index 6e611f33..e79d3521 100644 --- a/src/views/media/MediaErrorView.tsx +++ b/src/views/media/MediaErrorView.tsx @@ -1,8 +1,9 @@ +import { Helmet } from "react-helmet"; +import { useTranslation } from "react-i18next"; + import { ErrorMessage } from "@/components/layout/ErrorBoundary"; import { useGoBack } from "@/hooks/useGoBack"; import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; -import { Helmet } from "react-helmet"; -import { useTranslation } from "react-i18next"; export function MediaFetchErrorView() { const { t } = useTranslation(); diff --git a/src/views/media/MediaView.tsx b/src/views/media/MediaView.tsx index c2ee94e7..132161dd 100644 --- a/src/views/media/MediaView.tsx +++ b/src/views/media/MediaView.tsx @@ -1,25 +1,27 @@ -import { useHistory, useParams } from "react-router-dom"; -import { Helmet } from "react-helmet"; import { useEffect, useRef, useState } from "react"; +import { Helmet } from "react-helmet"; +import { useTranslation } from "react-i18next"; +import { useHistory, useParams } from "react-router-dom"; + import { MWStream } from "@/backend/helpers/streams"; -import { SelectedMediaData, useScrape } from "@/hooks/useScrape"; import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta"; import { decodeJWId } from "@/backend/metadata/justwatch"; -import { Loading } from "@/components/layout/Loading"; -import { useLoading } from "@/hooks/useLoading"; import { MWMediaType, MWSeasonWithEpisodeMeta } from "@/backend/metadata/types"; -import { useGoBack } from "@/hooks/useGoBack"; import { IconPatch } from "@/components/buttons/IconPatch"; -import { VideoPlayer } from "@/video/components/VideoPlayer"; -import { MetaController } from "@/video/components/controllers/MetaController"; -import { SourceController } from "@/video/components/controllers/SourceController"; import { Icons } from "@/components/Icon"; -import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; -import { ProgressListenerController } from "@/video/components/controllers/ProgressListenerController"; -import { VideoPlayerMeta } from "@/video/state/types"; -import { SeriesController } from "@/video/components/controllers/SeriesController"; +import { Loading } from "@/components/layout/Loading"; +import { useGoBack } from "@/hooks/useGoBack"; +import { useLoading } from "@/hooks/useLoading"; +import { SelectedMediaData, useScrape } from "@/hooks/useScrape"; import { useWatchedItem } from "@/state/watched"; -import { useTranslation } from "react-i18next"; +import { MetaController } from "@/video/components/controllers/MetaController"; +import { ProgressListenerController } from "@/video/components/controllers/ProgressListenerController"; +import { SeriesController } from "@/video/components/controllers/SeriesController"; +import { SourceController } from "@/video/components/controllers/SourceController"; +import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; +import { VideoPlayer } from "@/video/components/VideoPlayer"; +import { VideoPlayerMeta } from "@/video/state/types"; + import { MediaFetchErrorView } from "./MediaErrorView"; import { MediaScrapeLog } from "./MediaScrapeLog"; import { NotFoundMedia, NotFoundWrapper } from "../notfound/NotFoundView"; diff --git a/src/views/notfound/NotFoundView.tsx b/src/views/notfound/NotFoundView.tsx index 3d9e7032..b7dfccf1 100644 --- a/src/views/notfound/NotFoundView.tsx +++ b/src/views/notfound/NotFoundView.tsx @@ -1,12 +1,13 @@ import { ReactNode } from "react"; +import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; + import { IconPatch } from "@/components/buttons/IconPatch"; import { Icons } from "@/components/Icon"; import { Navigation } from "@/components/layout/Navigation"; import { ArrowLink } from "@/components/text/ArrowLink"; import { Title } from "@/components/text/Title"; import { useGoBack } from "@/hooks/useGoBack"; -import { Helmet } from "react-helmet"; import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; export function NotFoundWrapper(props: { diff --git a/src/views/other/v2Migration.tsx b/src/views/other/v2Migration.tsx index 0f1e0424..1334ae26 100644 --- a/src/views/other/v2Migration.tsx +++ b/src/views/other/v2Migration.tsx @@ -1,5 +1,6 @@ -import { useEffect, useState } from "react"; import pako from "pako"; +import { useEffect, useState } from "react"; + import { MWMediaType } from "@/backend/metadata/types"; import { conf } from "@/setup/config"; diff --git a/src/views/search/HomeView.tsx b/src/views/search/HomeView.tsx index 952d1ec2..bfb64695 100644 --- a/src/views/search/HomeView.tsx +++ b/src/views/search/HomeView.tsx @@ -1,19 +1,21 @@ +import { useAutoAnimate } from "@formkit/auto-animate/react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { Trans, useTranslation } from "react-i18next"; +import { useHistory } from "react-router-dom"; + +import { Button } from "@/components/Button"; +import { EditButton } from "@/components/buttons/EditButton"; import { Icons } from "@/components/Icon"; +import { Modal, ModalCard } from "@/components/layout/Modal"; import { SectionHeading } from "@/components/layout/SectionHeading"; import { MediaGrid } from "@/components/media/MediaGrid"; +import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; import { getIfBookmarkedFromPortable, useBookmarkContext, } from "@/state/bookmark"; import { useWatchedContext } from "@/state/watched"; -import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; -import { EditButton } from "@/components/buttons/EditButton"; -import { useCallback, useEffect, useMemo, useState } from "react"; -import { useAutoAnimate } from "@formkit/auto-animate/react"; -import { useHistory } from "react-router-dom"; -import { Modal, ModalCard } from "@/components/layout/Modal"; -import { Button } from "@/components/Button"; + import { EmbedMigration } from "../other/v2Migration"; function Bookmarks() { diff --git a/src/views/search/SearchLoadingView.tsx b/src/views/search/SearchLoadingView.tsx index 307ed428..4c59d677 100644 --- a/src/views/search/SearchLoadingView.tsx +++ b/src/views/search/SearchLoadingView.tsx @@ -1,4 +1,5 @@ import { useTranslation } from "react-i18next"; + import { Loading } from "@/components/layout/Loading"; import { useSearchQuery } from "@/hooks/useSearchQuery"; diff --git a/src/views/search/SearchResultsPartial.tsx b/src/views/search/SearchResultsPartial.tsx index 63250193..5769338b 100644 --- a/src/views/search/SearchResultsPartial.tsx +++ b/src/views/search/SearchResultsPartial.tsx @@ -1,6 +1,8 @@ import { useEffect, useMemo, useState } from "react"; -import { useDebounce } from "@/hooks/useDebounce"; + import { MWQuery } from "@/backend/metadata/types"; +import { useDebounce } from "@/hooks/useDebounce"; + import { HomeView } from "./HomeView"; import { SearchLoadingView } from "./SearchLoadingView"; import { SearchResultsView } from "./SearchResultsView"; diff --git a/src/views/search/SearchResultsView.tsx b/src/views/search/SearchResultsView.tsx index 0726ae5f..25d347c9 100644 --- a/src/views/search/SearchResultsView.tsx +++ b/src/views/search/SearchResultsView.tsx @@ -1,13 +1,15 @@ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; + +import { searchForMedia } from "@/backend/metadata/search"; +import { MWMediaMeta, MWQuery } from "@/backend/metadata/types"; import { IconPatch } from "@/components/buttons/IconPatch"; import { Icons } from "@/components/Icon"; import { SectionHeading } from "@/components/layout/SectionHeading"; import { MediaGrid } from "@/components/media/MediaGrid"; import { WatchedMediaCard } from "@/components/media/WatchedMediaCard"; import { useLoading } from "@/hooks/useLoading"; -import { searchForMedia } from "@/backend/metadata/search"; -import { MWMediaMeta, MWQuery } from "@/backend/metadata/types"; + import { SearchLoadingView } from "./SearchLoadingView"; function SearchSuffix(props: { failed?: boolean; results?: number }) { diff --git a/src/views/search/SearchView.tsx b/src/views/search/SearchView.tsx index 9dfdee64..fce4ce08 100644 --- a/src/views/search/SearchView.tsx +++ b/src/views/search/SearchView.tsx @@ -1,14 +1,16 @@ import { useCallback, useState } from "react"; -import Sticky from "react-stickynode"; +import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; +import Sticky from "react-stickynode"; + import { Navigation } from "@/components/layout/Navigation"; import { ThinContainer } from "@/components/layout/ThinContainer"; +import { WideContainer } from "@/components/layout/WideContainer"; import { SearchBarInput } from "@/components/SearchBar"; import { Title } from "@/components/text/Title"; -import { useSearchQuery } from "@/hooks/useSearchQuery"; -import { WideContainer } from "@/components/layout/WideContainer"; import { useBannerSize } from "@/hooks/useBanner"; -import { Helmet } from "react-helmet"; +import { useSearchQuery } from "@/hooks/useSearchQuery"; + import { SearchResultsPartial } from "./SearchResultsPartial"; export function SearchView() { diff --git a/yarn.lock b/yarn.lock index 48e68bc8..867bedb7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1301,6 +1301,80 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@sentry-internal/tracing@7.49.0": + version "7.49.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.49.0.tgz#f589de565370884b9a13f82c98463de9b2d25dcd" + integrity sha512-ESh3+ZneQk/3HESTUmIPNrW5GVPu/HrRJU+eAJJto74vm+6vP7zDn2YV2gJ1w18O/37nc7W/bVCgZJlhZ3cwew== + dependencies: + "@sentry/core" "7.49.0" + "@sentry/types" "7.49.0" + "@sentry/utils" "7.49.0" + tslib "^1.9.3" + +"@sentry/browser@7.49.0": + version "7.49.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.49.0.tgz#5ce1cdb8d883c129d9a4e313c08a54c5ada4661b" + integrity sha512-x2DekKkQoY7/dhBzE4J25mdQ978NtPBTVQb+uZqlF/t5mp4K44TAszmPqy8lC/CmVHkp7qcpRGSCIzeboUL4KA== + dependencies: + "@sentry-internal/tracing" "7.49.0" + "@sentry/core" "7.49.0" + "@sentry/replay" "7.49.0" + "@sentry/types" "7.49.0" + "@sentry/utils" "7.49.0" + tslib "^1.9.3" + +"@sentry/core@7.49.0": + version "7.49.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.49.0.tgz#340d059f5efeff1a3359fef66d0c8e34e79ac992" + integrity sha512-AlSnCYgfEbvK8pkNluUkmdW/cD9UpvOVCa+ERQswXNRkAv5aDGCL6Ihv6fnIajE++BYuwZh0+HwZUBVKTFzoZg== + dependencies: + "@sentry/types" "7.49.0" + "@sentry/utils" "7.49.0" + tslib "^1.9.3" + +"@sentry/integrations@^7.49.0": + version "7.49.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.49.0.tgz#e123f687e0abe10d3428027e3879ce231503fc2f" + integrity sha512-qsEVkcZjw+toFGnzsVo+Cozz+hMK9LugzkfJyOFL+CyiEx9MfkEmsvRpZe1ETEWKe/VZylYU27NQzl6UNuAUjw== + dependencies: + "@sentry/types" "7.49.0" + "@sentry/utils" "7.49.0" + localforage "^1.8.1" + tslib "^1.9.3" + +"@sentry/react@^7.49.0": + version "7.49.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.49.0.tgz#9a31808d4232d3010019e09d7c706b3d4fe54960" + integrity sha512-s+ROJr1tP9zVBmoOn94JM+fu2TuoJKxkSXTEUOKoQ9P6P5ROzpDqTzHRGk6u4OjZTy5tftRyEqBGM2Iaf9Y+UA== + dependencies: + "@sentry/browser" "7.49.0" + "@sentry/types" "7.49.0" + "@sentry/utils" "7.49.0" + hoist-non-react-statics "^3.3.2" + tslib "^1.9.3" + +"@sentry/replay@7.49.0": + version "7.49.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.49.0.tgz#c7f16bc3ca0c5911f641738f8894eb596c5da00d" + integrity sha512-UY3bHoBDPOu4Dpq3m3oxNjLrq09NiFVYUfrTN4QOq1Am2SA04XbuCj/YZ+jNVy/NrFtoz9cTovK6oQbNw53jog== + dependencies: + "@sentry/core" "7.49.0" + "@sentry/types" "7.49.0" + "@sentry/utils" "7.49.0" + +"@sentry/types@7.49.0": + version "7.49.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.49.0.tgz#2c217091e13dc373682f5be2e9b5baed9d2ae695" + integrity sha512-9yXXh7iv76+O6h2ONUVx0wsL1auqJFWez62mTjWk4350SgMmWp/zUkBxnVXhmcYqscz/CepC+Loz9vITLXtgxg== + +"@sentry/utils@7.49.0": + version "7.49.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.49.0.tgz#b1b3a2af52067dd27e660c7c3062a31cdf4b94f9" + integrity sha512-JdC9yGnOgev4ISJVwmIoFsk8Zx0psDZJAj2DV7x4wMZsO6QK+YjC7G3mUED/S5D5lsrkBZ/3uvQQhr8DQI4UcQ== + dependencies: + "@sentry/types" "7.49.0" + tslib "^1.9.3" + "@surma/rollup-plugin-off-main-thread@^2.2.3": version "2.2.3" resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053" @@ -2599,7 +2673,7 @@ eslint-module-utils@^2.7.4: dependencies: debug "^3.2.7" -eslint-plugin-import@^2.25.4: +eslint-plugin-import@^2.27.5: version "2.27.5" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== @@ -3143,7 +3217,7 @@ hls.js@^1.0.7: resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.3.5.tgz#0e8b0799ecf2feb7ba199f5e95f35ba9552e04f4" integrity sha512-uybAvKS6uDe0MnWNEPnO0krWVr+8m2R0hJ/viql8H3MVK+itq8gGQuIYoFHL3rECkIpNH98Lw8YuuWMKZxp3Ew== -hoist-non-react-statics@^3.1.0: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -3217,6 +3291,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -3642,6 +3721,13 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + lilconfig@^2.0.5, lilconfig@^2.0.6: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" @@ -3652,6 +3738,13 @@ local-pkg@^0.4.2: resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963" integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g== +localforage@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -5021,7 +5114,7 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1: +tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==