Compare commits

..

10 Commits

Author SHA1 Message Date
mrjvs
5468a4677b Merge pull request #282 from movie-web/dev
v3.0.14
2023-04-25 17:47:13 +02:00
mrjvs
85cfba1a7a Merge branch 'master' into dev 2023-04-25 17:41:12 +02:00
mrjvs
fd6895c326 Merge pull request #281 from movie-web/fix-referer-maybe
Fix referer maybe
2023-04-25 17:39:11 +02:00
mrjvs
dfc3d9e50f Merge branch 'dev' into fix-referer-maybe 2023-04-25 17:38:27 +02:00
mrjvs
fcdf45d3f5 bump version for real 2023-04-25 17:37:49 +02:00
mrjvs
592837e2a6 bump version for a small release 2023-04-25 17:35:59 +02:00
mrjvs
9b3c1ffa28 add some dev routes back 2023-04-25 17:35:09 +02:00
mrjvs
7cb9ccaf14 referrer policy 2023-04-25 17:35:03 +02:00
mrjvs
4c0c61b0b9 Merge pull request #278 from yilmazcabuk/dev
style: sort imports according to ESLint rules
2023-04-25 00:55:41 +02:00
Yılmaz ÇABUK
4880d46dc4 style: sort imports according to ESLint rules
This commit updates the import statements in the codebase to comply with ESLint rules for import ordering. All imports have been sorted alphabetically and grouped according to the specified import groups in the ESLint configuration. This improves the codebase's consistency and maintainability.
2023-04-24 18:41:54 +03:00
134 changed files with 482 additions and 295 deletions

View File

@@ -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,
},
};

View File

@@ -29,6 +29,9 @@
<!-- prevent darkreader extension from messing with our already dark site -->
<meta name="darkreader-lock" />
<!-- disabling referrer can fix some provider problems -->
<meta name="referrer" content="no-referrer" />
<title>movie-web</title>
</head>
<body>

View File

@@ -1,6 +1,6 @@
{
"name": "movie-web",
"version": "3.0.13",
"version": "3.0.14",
"private": true,
"homepage": "https://movie-web.app",
"dependencies": {
@@ -82,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",

View File

@@ -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();

View File

@@ -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}`;

View File

@@ -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 {

View File

@@ -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

View File

@@ -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;

View File

@@ -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"

View File

@@ -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<MWQuery, MWMediaMeta[]>();
cache.setCompare((a, b) => {

View File

@@ -1,4 +1,5 @@
import { compareTitle } from "@/utils/titleMatch";
import { proxiedFetch } from "../helpers/fetch";
import { registerProvider } from "../helpers/register";
import {

View File

@@ -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 = {

View File

@@ -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";

View File

@@ -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);

View File

@@ -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;

View File

@@ -1,4 +1,5 @@
import { useSettings } from "@/state/settings";
import { Icon, Icons } from "./Icon";
export const colors = ["#ffffff", "#00ffff", "#ffff00"];

View File

@@ -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 {

View File

@@ -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 (
<>

View File

@@ -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";

View File

@@ -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"

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -1,5 +1,6 @@
import React, { createRef, useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { useFade } from "@/hooks/useFade";
interface BackdropProps {

View File

@@ -1,4 +1,5 @@
import { useTranslation } from "react-i18next";
import { Icon, Icons } from "@/components/Icon";
export function BrandPill(props: {

View File

@@ -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: {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -1,4 +1,5 @@
import { ReactNode } from "react";
import { Icon, Icons } from "@/components/Icon";
interface SectionHeadingProps {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -1,12 +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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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";

View File

@@ -1,4 +1,5 @@
import { Link as LinkRouter } from "react-router-dom";
import { Icon, Icons } from "@/components/Icon";
interface IArrowLinkPropsBase {

View File

@@ -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";

View File

@@ -1,8 +1,9 @@
/// <reference types="chromecast-caf-sender"/>
import { isChromecastAvailable } from "@/setup/chromecast";
import { useEffect, useRef, useState } from "react";
import { isChromecastAvailable } from "@/setup/chromecast";
export function useChromecastAvailable() {
const [available, setAvailable] = useState<boolean | null>(null);

View File

@@ -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";

View File

@@ -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) ||

View File

@@ -1,6 +1,7 @@
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);

View File

@@ -3,11 +3,12 @@ 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";

View File

@@ -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 (
@@ -40,15 +40,23 @@ function App() {
/>
{/* other */}
<Route
exact
path="/dev"
component={lazy(
() => import("@/views/developer/DeveloperView")
)}
/>
<Route
exact
path="/dev/video"
component={lazy(
() => import("@/views/developer/VideoTesterView")
)}
/>
{/* developer routes that can abuse workers are disabled in production */}
{process.env.NODE_ENV === "development" ? (
<>
<Route
exact
path="/dev"
component={lazy(
() => import("@/views/developer/DeveloperView")
)}
/>
<Route
exact
path="/dev/test"
@@ -56,13 +64,7 @@ function App() {
() => import("@/views/developer/TestView")
)}
/>
<Route
exact
path="/dev/video"
component={lazy(
() => import("@/views/developer/VideoTesterView")
)}
/>
<Route
exact
path="/dev/providers"

View File

@@ -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();

View File

@@ -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;

View File

@@ -1,4 +1,5 @@
import ReactGA from "react-ga4";
import { GA_ID } from "@/setup/constants";
ReactGA.initialize([

View File

@@ -1,14 +1,13 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
// Languages
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";
import fr from "./locales/fr/translation.json";
import { captionLanguages } from "./iso6391";
const locales = {
en: {

View File

@@ -1,7 +1,8 @@
import * as Sentry from "@sentry/react";
import { CaptureConsole, HttpClient } from "@sentry/integrations";
import { SENTRY_DSN } from "@/setup/constants";
import * as Sentry from "@sentry/react";
import { conf } from "@/setup/config";
import { SENTRY_DSN } from "@/setup/constants";
Sentry.init({
dsn: SENTRY_DSN,

View File

@@ -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";

View File

@@ -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<BookmarkStoreData>()
.setKey("mw-bookmarks")

View File

@@ -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";

View File

@@ -1,4 +1,5 @@
import { createVersionedStore } from "@/utils/storage";
import { MWSettingsData, MWSettingsDataV1 } from "./types";
export const SettingsStore = createVersionedStore<MWSettingsData>()

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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<WatchedStoreData>()

View File

@@ -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;

View File

@@ -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?:

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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";

View File

@@ -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();

View File

@@ -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;

View File

@@ -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();

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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();

View File

@@ -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() {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,4 +1,5 @@
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo";
export function ShowTitleAction() {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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() {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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]);

View File

@@ -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<typeof useLocation>,
controls: ControlMethods

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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<HTMLButtonElement>) => void;
icon: Icons;

View File

@@ -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;

View File

@@ -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: {

View File

@@ -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<typeof useFloatingRouter>;

View File

@@ -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() {

Some files were not shown because too many files have changed in this diff Show More