Merge branch 'dev' of https://github.com/movie-web/movie-web into subtitle-file-type-control

This commit is contained in:
frost768 2023-04-27 21:54:24 +03:00
commit bf135a2bdf
135 changed files with 483 additions and 296 deletions

View File

@ -8,27 +8,28 @@ const a11yOff = Object.keys(require("eslint-plugin-jsx-a11y").rules).reduce(
module.exports = { module.exports = {
env: { env: {
browser: true browser: true,
}, },
extends: [ extends: [
"airbnb", "airbnb",
"airbnb/hooks", "airbnb/hooks",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"prettier", "plugin:prettier/recommended",
"plugin:prettier/recommended"
], ],
ignorePatterns: ["public/*", "dist/*", "/*.js", "/*.ts"], ignorePatterns: ["public/*", "dist/*", "/*.js", "/*.ts"],
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
parserOptions: { parserOptions: {
project: "./tsconfig.json", project: "./tsconfig.json",
tsconfigRootDir: "./" tsconfigRootDir: "./",
}, },
settings: { settings: {
"import/resolver": { "import/resolver": {
typescript: {} typescript: {
} project: "./tsconfig.json",
},
},
}, },
plugins: ["@typescript-eslint", "import"], plugins: ["@typescript-eslint", "import", "prettier"],
rules: { rules: {
"react/jsx-uses-react": "off", "react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off", "react/react-in-jsx-scope": "off",
@ -54,16 +55,44 @@ module.exports = {
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
"react/jsx-filename-extension": [ "react/jsx-filename-extension": [
"error", "error",
{ extensions: [".js", ".tsx", ".jsx"] } { extensions: [".js", ".tsx", ".jsx"] },
], ],
"import/extensions": [ "import/extensions": [
"error", "error",
"ignorePackages", "ignorePackages",
{ {
ts: "never", 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 --> <!-- prevent darkreader extension from messing with our already dark site -->
<meta name="darkreader-lock" /> <meta name="darkreader-lock" />
<!-- disabling referrer can fix some provider problems -->
<meta name="referrer" content="no-referrer" />
<title>movie-web</title> <title>movie-web</title>
</head> </head>
<body> <body>

View File

@ -1,6 +1,6 @@
{ {
"name": "movie-web", "name": "movie-web",
"version": "3.0.13", "version": "3.0.14",
"private": true, "private": true,
"homepage": "https://movie-web.app", "homepage": "https://movie-web.app",
"dependencies": { "dependencies": {
@ -82,7 +82,7 @@
"eslint-config-airbnb": "19.0.4", "eslint-config-airbnb": "19.0.4",
"eslint-config-prettier": "^8.6.0", "eslint-config-prettier": "^8.6.0",
"eslint-import-resolver-typescript": "^2.5.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-jsx-a11y": "^6.5.1",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "7.29.4", "eslint-plugin-react": "7.29.4",

View File

@ -1,9 +1,10 @@
import { describe, it } from "vitest"; import { describe, it } from "vitest";
import "@/backend"; 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 { 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", () => { describe("providers", () => {
const providers = getProviders(); const providers = getProviders();

View File

@ -1,11 +1,11 @@
import { MWEmbedType } from "@/backend/helpers/embed"; import { MWEmbedType } from "@/backend/helpers/embed";
import { proxiedFetch } from "@/backend/helpers/fetch";
import { registerEmbedScraper } from "@/backend/helpers/register"; import { registerEmbedScraper } from "@/backend/helpers/register";
import { import {
MWEmbedStream,
MWStreamQuality, MWStreamQuality,
MWStreamType, MWStreamType,
MWEmbedStream,
} from "@/backend/helpers/streams"; } from "@/backend/helpers/streams";
import { proxiedFetch } from "@/backend/helpers/fetch";
const HOST = "streamm4u.club"; const HOST = "streamm4u.club";
const URL_BASE = `https://${HOST}`; const URL_BASE = `https://${HOST}`;

View File

@ -1,8 +1,9 @@
import DOMPurify from "dompurify";
import { convert, detect, list, parse } from "subsrt-ts";
import { ContentCaption } from "subsrt-ts/dist/types/handler";
import { mwFetch, proxiedFetch } from "@/backend/helpers/fetch"; import { mwFetch, proxiedFetch } from "@/backend/helpers/fetch";
import { MWCaption, MWCaptionType } from "@/backend/helpers/streams"; import { MWCaption, MWCaptionType } from "@/backend/helpers/streams";
import DOMPurify from "dompurify";
import { parse, detect, list, convert } from "subsrt-ts";
import { ContentCaption } from "subsrt-ts/dist/types/handler";
export const customCaption = "external-custom"; export const customCaption = "external-custom";
export function makeCaptionId(caption: MWCaption, isLinked: boolean): string { export function makeCaptionId(caption: MWCaption, isLinked: boolean): string {

View File

@ -1,6 +1,7 @@
import { conf } from "@/setup/config";
import { ofetch } from "ofetch"; import { ofetch } from "ofetch";
import { conf } from "@/setup/config";
let proxyUrlIndex = Math.floor(Math.random() * conf().PROXY_URLS.length); let proxyUrlIndex = Math.floor(Math.random() * conf().PROXY_URLS.length);
// round robins all proxy urls // 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 { MWEmbed } from "./embed";
import { MWStream } from "./streams"; import { MWStream } from "./streams";
import { DetailedMeta } from "../metadata/getmeta";
import { MWMediaType } from "../metadata/types";
export type MWProviderScrapeResult = { export type MWProviderScrapeResult = {
stream?: MWStream; stream?: MWStream;

View File

@ -1,13 +1,14 @@
import { FetchError } from "ofetch"; import { FetchError } from "ofetch";
import { makeUrl, proxiedFetch } from "../helpers/fetch";
import { import {
formatJWMeta,
JWMediaResult, JWMediaResult,
JWSeasonMetaResult, JWSeasonMetaResult,
JW_API_BASE, JW_API_BASE,
formatJWMeta,
mediaTypeToJW, mediaTypeToJW,
} from "./justwatch"; } from "./justwatch";
import { MWMediaMeta, MWMediaType } from "./types"; import { MWMediaMeta, MWMediaType } from "./types";
import { makeUrl, proxiedFetch } from "../helpers/fetch";
type JWExternalIdType = type JWExternalIdType =
| "eidr" | "eidr"

View File

@ -1,13 +1,14 @@
import { SimpleCache } from "@/utils/cache"; import { SimpleCache } from "@/utils/cache";
import { proxiedFetch } from "../helpers/fetch";
import { import {
formatJWMeta,
JWContentTypes, JWContentTypes,
JWMediaResult, JWMediaResult,
JW_API_BASE, JW_API_BASE,
formatJWMeta,
mediaTypeToJW, mediaTypeToJW,
} from "./justwatch"; } from "./justwatch";
import { MWMediaMeta, MWQuery } from "./types"; import { MWMediaMeta, MWQuery } from "./types";
import { proxiedFetch } from "../helpers/fetch";
const cache = new SimpleCache<MWQuery, MWMediaMeta[]>(); const cache = new SimpleCache<MWQuery, MWMediaMeta[]>();
cache.setCompare((a, b) => { cache.setCompare((a, b) => {

View File

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

View File

@ -1,9 +1,10 @@
import { unpack } from "unpacker";
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
import { unpack } from "unpacker";
import { registerProvider } from "@/backend/helpers/register"; import { registerProvider } from "@/backend/helpers/register";
import { MWMediaType } from "@/backend/metadata/types";
import { MWStreamQuality } from "@/backend/helpers/streams"; import { MWStreamQuality } from "@/backend/helpers/streams";
import { MWMediaType } from "@/backend/metadata/types";
import { proxiedFetch } from "../helpers/fetch"; import { proxiedFetch } from "../helpers/fetch";
const format = { const format = {

View File

@ -1,4 +1,5 @@
import { MWEmbed, MWEmbedType } from "@/backend/helpers/embed"; import { MWEmbed, MWEmbedType } from "@/backend/helpers/embed";
import { proxiedFetch } from "../helpers/fetch"; import { proxiedFetch } from "../helpers/fetch";
import { registerProvider } from "../helpers/register"; import { registerProvider } from "../helpers/register";
import { MWMediaType } from "../metadata/types"; 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 CryptoJS from "crypto-js";
import { customAlphabet } from "nanoid";
import { proxiedFetch } from "@/backend/helpers/fetch"; import { proxiedFetch } from "@/backend/helpers/fetch";
import { registerProvider } from "@/backend/helpers/register";
import { import {
MWCaption, MWCaption,
MWCaptionType, MWCaptionType,
MWStreamQuality, MWStreamQuality,
MWStreamType, MWStreamType,
} from "@/backend/helpers/streams"; } from "@/backend/helpers/streams";
import { MWMediaType } from "@/backend/metadata/types";
import { compareTitle } from "@/utils/titleMatch"; import { compareTitle } from "@/utils/titleMatch";
import { import {
getMWCaptionTypeFromUrl, getMWCaptionTypeFromUrl,

View File

@ -1,6 +1,7 @@
import { Icon, Icons } from "@/components/Icon";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { Icon, Icons } from "@/components/Icon";
interface Props { interface Props {
icon?: Icons; icon?: Icons;
onClick?: () => void; onClick?: () => void;

View File

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

View File

@ -1,6 +1,6 @@
import { Listbox, Transition } from "@headlessui/react";
import React, { Fragment } from "react"; import React, { Fragment } from "react";
import { Listbox, Transition } from "@headlessui/react";
import { Icon, Icons } from "@/components/Icon"; import { Icon, Icons } from "@/components/Icon";
export interface OptionItem { export interface OptionItem {

View File

@ -1,6 +1,7 @@
import { Transition } from "@/components/Transition";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { Transition } from "@/components/Transition";
export function Overlay(props: { children: React.ReactNode }) { export function Overlay(props: { children: React.ReactNode }) {
return ( return (
<> <>

View File

@ -1,6 +1,8 @@
import { MWMediaType, MWQuery } from "@/backend/metadata/types";
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MWMediaType, MWQuery } from "@/backend/metadata/types";
import { DropdownButton } from "./buttons/DropdownButton"; import { DropdownButton } from "./buttons/DropdownButton";
import { Icon, Icons } from "./Icon"; import { Icon, Icons } from "./Icon";
import { TextInputControl } from "./text-inputs/TextInputControl"; import { TextInputControl } from "./text-inputs/TextInputControl";

View File

@ -1,8 +1,8 @@
import { Fragment, ReactNode } from "react";
import { import {
Transition as HeadlessTransition, Transition as HeadlessTransition,
TransitionClasses, TransitionClasses,
} from "@headlessui/react"; } from "@headlessui/react";
import { Fragment, ReactNode } from "react";
type TransitionAnimations = type TransitionAnimations =
| "slide-down" | "slide-down"

View File

@ -4,10 +4,11 @@ import React, {
useEffect, useEffect,
useState, useState,
} from "react"; } from "react";
import { Icon, Icons } from "@/components/Icon";
import { Icon, Icons } from "@/components/Icon";
import { BackdropContainer, useBackdrop } from "@/components/layout/Backdrop"; import { BackdropContainer, useBackdrop } from "@/components/layout/Backdrop";
import { ButtonControlProps, ButtonControl } from "./ButtonControl";
import { ButtonControl, ButtonControlProps } from "./ButtonControl";
export interface OptionItem { export interface OptionItem {
id: string; id: string;

View File

@ -1,7 +1,9 @@
import { Icon, Icons } from "@/components/Icon";
import { useAutoAnimate } from "@formkit/auto-animate/react"; import { useAutoAnimate } from "@formkit/auto-animate/react";
import { useCallback } from "react"; import { useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Icon, Icons } from "@/components/Icon";
import { ButtonControl } from "./ButtonControl"; import { ButtonControl } from "./ButtonControl";
export interface EditButtonProps { export interface EditButtonProps {

View File

@ -1,5 +1,6 @@
import { Icon, Icons } from "@/components/Icon"; import { Icon, Icons } from "@/components/Icon";
import { ButtonControlProps, ButtonControl } from "./ButtonControl";
import { ButtonControl, ButtonControlProps } from "./ButtonControl";
export interface IconButtonProps extends ButtonControlProps { export interface IconButtonProps extends ButtonControlProps {
icon: Icons; icon: Icons;

View File

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

View File

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

View File

@ -1,10 +1,11 @@
import { Component } from "react"; import { Component } from "react";
import { Trans, useTranslation } from "react-i18next";
import { IconPatch } from "@/components/buttons/IconPatch"; import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { Link } from "@/components/text/Link"; import { Link } from "@/components/text/Link";
import { Title } from "@/components/text/Title"; import { Title } from "@/components/text/Title";
import { conf } from "@/setup/config"; import { conf } from "@/setup/config";
import { Trans, useTranslation } from "react-i18next";
interface ErrorShowcaseProps { interface ErrorShowcaseProps {
error: { error: {

View File

@ -1,8 +1,9 @@
import { Overlay } from "@/components/Overlay";
import { Transition } from "@/components/Transition";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { Overlay } from "@/components/Overlay";
import { Transition } from "@/components/Transition";
interface Props { interface Props {
show: boolean; show: boolean;
children?: ReactNode; children?: ReactNode;

View File

@ -1,10 +1,12 @@
import { ReactNode, useState } from "react"; import { ReactNode, useState } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { IconPatch } from "@/components/buttons/IconPatch"; import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { conf } from "@/setup/config";
import { useBannerSize } from "@/hooks/useBanner"; import { useBannerSize } from "@/hooks/useBanner";
import { conf } from "@/setup/config";
import SettingsModal from "@/views/SettingsModal"; import SettingsModal from "@/views/SettingsModal";
import { BrandPill } from "./BrandPill"; import { BrandPill } from "./BrandPill";
export interface NavigationProps { export interface NavigationProps {

View File

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

View File

@ -1,10 +1,12 @@
import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { DotList } from "@/components/text/DotList"; import { Link } from "react-router-dom";
import { MWMediaMeta } from "@/backend/metadata/types";
import { JWMediaToId } from "@/backend/metadata/justwatch"; 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 { IconPatch } from "../buttons/IconPatch";
import { Icons } from "../Icon";
export interface MediaCardProps { export interface MediaCardProps {
media: MWMediaMeta; media: MWMediaMeta;

View File

@ -1,6 +1,8 @@
import { useMemo } from "react";
import { MWMediaMeta } from "@/backend/metadata/types"; import { MWMediaMeta } from "@/backend/metadata/types";
import { useWatchedContext } from "@/state/watched"; import { useWatchedContext } from "@/state/watched";
import { useMemo } from "react";
import { MediaCard } from "./MediaCard"; import { MediaCard } from "./MediaCard";
export interface WatchedMediaCardProps { 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 { useTranslation } from "react-i18next";
import { FloatingCardAnchorPosition } from "@/components/popout/positions/FloatingCardAnchorPosition"; import { FloatingCardAnchorPosition } from "@/components/popout/positions/FloatingCardAnchorPosition";
import { FloatingCardMobilePosition } from "@/components/popout/positions/FloatingCardMobilePosition"; import { FloatingCardMobilePosition } from "@/components/popout/positions/FloatingCardMobilePosition";
import { useIsMobile } from "@/hooks/useIsMobile"; import { useIsMobile } from "@/hooks/useIsMobile";
import { PopoutSection } from "@/video/components/popouts/PopoutUtils"; 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 { FloatingDragHandle, MobilePopoutSpacer } from "./FloatingDragHandle";
import { Icon, Icons } from "../Icon";
interface FloatingCardProps { interface FloatingCardProps {
children?: ReactNode; children?: ReactNode;

View File

@ -1,4 +1,3 @@
import { Transition } from "@/components/Transition";
import React, { import React, {
ReactNode, ReactNode,
useCallback, useCallback,
@ -8,6 +7,8 @@ import React, {
} from "react"; } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { Transition } from "@/components/Transition";
interface Props { interface Props {
children?: ReactNode; children?: ReactNode;
onClose?: () => void; onClose?: () => void;

View File

@ -1,6 +1,7 @@
import { ReactNode } from "react";
import { Transition } from "@/components/Transition"; import { Transition } from "@/components/Transition";
import { useIsMobile } from "@/hooks/useIsMobile"; import { useIsMobile } from "@/hooks/useIsMobile";
import { ReactNode } from "react";
interface Props { interface Props {
children?: ReactNode; children?: ReactNode;

View File

@ -1,6 +1,7 @@
import { createFloatingAnchorEvent } from "@/components/popout/FloatingAnchor";
import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; import { ReactNode, useCallback, useEffect, useRef, useState } from "react";
import { createFloatingAnchorEvent } from "@/components/popout/FloatingAnchor";
interface AnchorPositionProps { interface AnchorPositionProps {
children?: ReactNode; children?: ReactNode;
id: string; 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 { useDrag } from "@use-gesture/react";
import { ReactNode, useEffect, useRef, useState } from "react"; import { ReactNode, useEffect, useRef, useState } from "react";

View File

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

View File

@ -1,12 +1,12 @@
import { import {
ReactNode,
createContext,
useState,
useMemo,
Dispatch, Dispatch,
ReactNode,
SetStateAction, SetStateAction,
useEffect, createContext,
useContext, useContext,
useEffect,
useMemo,
useState,
} from "react"; } from "react";
import { useMeasure } from "react-use"; import { useMeasure } from "react-use";

View File

@ -1,8 +1,9 @@
/// <reference types="chromecast-caf-sender"/> /// <reference types="chromecast-caf-sender"/>
import { isChromecastAvailable } from "@/setup/chromecast";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { isChromecastAvailable } from "@/setup/chromecast";
export function useChromecastAvailable() { export function useChromecastAvailable() {
const [available, setAvailable] = useState<boolean | null>(null); 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 { findBestStream } from "@/backend/helpers/scrape";
import { MWStream } from "@/backend/helpers/streams"; import { MWStream } from "@/backend/helpers/streams";
import { DetailedMeta } from "@/backend/metadata/getmeta"; import { DetailedMeta } from "@/backend/metadata/getmeta";
import { MWMediaType } from "@/backend/metadata/types"; import { MWMediaType } from "@/backend/metadata/types";
import { useEffect, useState } from "react";
export interface ScrapeEventLog { export interface ScrapeEventLog {
type: "provider" | "embed"; type: "provider" | "embed";

View File

@ -1,7 +1,8 @@
import { MWMediaType, MWQuery } from "@/backend/metadata/types";
import { useState } from "react"; import { useState } from "react";
import { generatePath, useHistory, useRouteMatch } from "react-router-dom"; import { generatePath, useHistory, useRouteMatch } from "react-router-dom";
import { MWMediaType, MWQuery } from "@/backend/metadata/types";
function getInitialValue(params: { type: string; query: string }) { function getInitialValue(params: { type: string; query: string }) {
const type = const type =
Object.values(MWMediaType).find((v) => params.type === v) || 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 { useControls } from "@/video/state/logic/controls";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useState } from "react";
export function useVolumeControl(descriptor: string) { export function useVolumeControl(descriptor: string) {
const [storedVolume, setStoredVolume] = useState(1); const [storedVolume, setStoredVolume] = useState(1);

View File

@ -3,11 +3,12 @@ import React, { Suspense } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { BrowserRouter, HashRouter } from "react-router-dom"; import { BrowserRouter, HashRouter } from "react-router-dom";
import type { ReactNode } from "react-router-dom/node_modules/@types/react/index"; 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 { registerSW } from "virtual:pwa-register";
import { ErrorBoundary } from "@/components/layout/ErrorBoundary";
import App from "@/setup/App"; import App from "@/setup/App";
import { conf } from "@/setup/config";
import "@/setup/ga"; import "@/setup/ga";
import "@/setup/sentry"; import "@/setup/sentry";
import "@/setup/i18n"; import "@/setup/i18n";

View File

@ -1,16 +1,16 @@
import { lazy } from "react"; import { lazy } from "react";
import { Redirect, Route, Switch } from "react-router-dom"; 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 { MWMediaType } from "@/backend/metadata/types";
import { V2MigrationView } from "@/views/other/v2Migration";
import { BannerContextProvider } from "@/hooks/useBanner"; import { BannerContextProvider } from "@/hooks/useBanner";
import { Layout } from "@/setup/Layout"; 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() { function App() {
return ( return (
@ -40,15 +40,23 @@ function App() {
/> />
{/* other */} {/* 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" ? ( {process.env.NODE_ENV === "development" ? (
<> <>
<Route
exact
path="/dev"
component={lazy(
() => import("@/views/developer/DeveloperView")
)}
/>
<Route <Route
exact exact
path="/dev/test" path="/dev/test"
@ -56,13 +64,7 @@ function App() {
() => import("@/views/developer/TestView") () => import("@/views/developer/TestView")
)} )}
/> />
<Route
exact
path="/dev/video"
component={lazy(
() => import("@/views/developer/VideoTesterView")
)}
/>
<Route <Route
exact exact
path="/dev/providers" path="/dev/providers"

View File

@ -1,8 +1,9 @@
import { ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { Banner } from "@/components/Banner"; import { Banner } from "@/components/Banner";
import { useBannerSize } from "@/hooks/useBanner"; import { useBannerSize } from "@/hooks/useBanner";
import { useIsOnline } from "@/hooks/usePing"; import { useIsOnline } from "@/hooks/usePing";
import { ReactNode } from "react";
import { useTranslation } from "react-i18next";
export function Layout(props: { children: ReactNode }) { export function Layout(props: { children: ReactNode }) {
const { t } = useTranslation(); 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 { interface Config {
APP_VERSION: string; APP_VERSION: string;

View File

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

View File

@ -1,14 +1,13 @@
import i18n from "i18next"; import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector"; import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
// Languages // Languages
import { captionLanguages } from "./iso6391";
import en from "./locales/en/translation.json"; import en from "./locales/en/translation.json";
import fr from "./locales/fr/translation.json";
import nl from "./locales/nl/translation.json"; import nl from "./locales/nl/translation.json";
import tr from "./locales/tr/translation.json"; import tr from "./locales/tr/translation.json";
import fr from "./locales/fr/translation.json";
import { captionLanguages } from "./iso6391";
const locales = { const locales = {
en: { en: {

View File

@ -27,7 +27,7 @@
} }
}, },
"seasons": { "seasons": {
"seasonAndEpisode": "S{{saison}} E{{épisode}}" "seasonAndEpisode": "S{{season}} E{{episode}}"
}, },
"notFound": { "notFound": {
"genericTitle": "Introuvable", "genericTitle": "Introuvable",

View File

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

View File

@ -1,6 +1,8 @@
import { ReactNode, createContext, useContext, useMemo } from "react";
import { MWMediaMeta } from "@/backend/metadata/types"; import { MWMediaMeta } from "@/backend/metadata/types";
import { useStore } from "@/utils/storage"; import { useStore } from "@/utils/storage";
import { createContext, ReactNode, useContext, useMemo } from "react";
import { BookmarkStore } from "./store"; import { BookmarkStore } from "./store";
import { BookmarkStoreData } from "./types"; import { BookmarkStoreData } from "./types";

View File

@ -1,6 +1,7 @@
import { createVersionedStore } from "@/utils/storage"; import { createVersionedStore } from "@/utils/storage";
import { migrateV1Bookmarks, OldBookmarks } from "../watched/migrations/v2";
import { BookmarkStoreData } from "./types"; import { BookmarkStoreData } from "./types";
import { OldBookmarks, migrateV1Bookmarks } from "../watched/migrations/v2";
export const BookmarkStore = createVersionedStore<BookmarkStoreData>() export const BookmarkStore = createVersionedStore<BookmarkStoreData>()
.setKey("mw-bookmarks") .setKey("mw-bookmarks")

View File

@ -1,6 +1,8 @@
import { useStore } from "@/utils/storage"; import { ReactNode, createContext, useContext, useMemo } from "react";
import { createContext, ReactNode, useContext, useMemo } from "react";
import { LangCode } from "@/setup/iso6391"; import { LangCode } from "@/setup/iso6391";
import { useStore } from "@/utils/storage";
import { SettingsStore } from "./store"; import { SettingsStore } from "./store";
import { MWSettingsData } from "./types"; import { MWSettingsData } from "./types";

View File

@ -1,4 +1,5 @@
import { createVersionedStore } from "@/utils/storage"; import { createVersionedStore } from "@/utils/storage";
import { MWSettingsData, MWSettingsDataV1 } from "./types"; import { MWSettingsData, MWSettingsDataV1 } from "./types";
export const SettingsStore = createVersionedStore<MWSettingsData>() 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 { import {
createContext,
ReactNode, ReactNode,
createContext,
useCallback, useCallback,
useContext, useContext,
useMemo, useMemo,
useRef, useRef,
} from "react"; } from "react";
import { DetailedMeta } from "@/backend/metadata/getmeta";
import { MWMediaType } from "@/backend/metadata/types";
import { useStore } from "@/utils/storage";
import { VideoProgressStore } from "./store"; import { VideoProgressStore } from "./store";
import { StoreMediaItem, WatchedStoreItem, WatchedStoreData } from "./types"; import { StoreMediaItem, WatchedStoreData, WatchedStoreItem } from "./types";
const FIVETEEN_MINUTES = 15 * 60; const FIVETEEN_MINUTES = 15 * 60;
const FIVE_MINUTES = 5 * 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 { searchForMedia } from "@/backend/metadata/search";
import { MWMediaMeta, MWMediaType } from "@/backend/metadata/types"; import { MWMediaMeta, MWMediaType } from "@/backend/metadata/types";
import { compareTitle } from "@/utils/titleMatch"; import { compareTitle } from "@/utils/titleMatch";
import { WatchedStoreData, WatchedStoreItem } from "../types"; import { WatchedStoreData, WatchedStoreItem } from "../types";
interface OldMediaBase { interface OldMediaBase {

View File

@ -1,5 +1,6 @@
import { createVersionedStore } from "@/utils/storage"; import { createVersionedStore } from "@/utils/storage";
import { migrateV2Videos, OldData } from "./migrations/v2";
import { OldData, migrateV2Videos } from "./migrations/v2";
import { WatchedStoreData } from "./types"; import { WatchedStoreData } from "./types";
export const VideoProgressStore = createVersionedStore<WatchedStoreData>() export const VideoProgressStore = createVersionedStore<WatchedStoreData>()

View File

@ -1,36 +1,38 @@
import { ReactNode, useCallback, useState } from "react";
import { Transition } from "@/components/Transition"; import { Transition } from "@/components/Transition";
import { useIsMobile } from "@/hooks/useIsMobile"; import { useIsMobile } from "@/hooks/useIsMobile";
import { AirplayAction } from "@/video/components/actions/AirplayAction"; import { AirplayAction } from "@/video/components/actions/AirplayAction";
import { BackdropAction } from "@/video/components/actions/BackdropAction"; 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 { FullscreenAction } from "@/video/components/actions/FullscreenAction";
import { HeaderAction } from "@/video/components/actions/HeaderAction"; import { HeaderAction } from "@/video/components/actions/HeaderAction";
import { KeyboardShortcutsAction } from "@/video/components/actions/KeyboardShortcutsAction";
import { LoadingAction } from "@/video/components/actions/LoadingAction"; import { LoadingAction } from "@/video/components/actions/LoadingAction";
import { MiddlePauseAction } from "@/video/components/actions/MiddlePauseAction"; import { MiddlePauseAction } from "@/video/components/actions/MiddlePauseAction";
import { MobileCenterAction } from "@/video/components/actions/MobileCenterAction"; import { MobileCenterAction } from "@/video/components/actions/MobileCenterAction";
import { PageTitleAction } from "@/video/components/actions/PageTitleAction"; import { PageTitleAction } from "@/video/components/actions/PageTitleAction";
import { PauseAction } from "@/video/components/actions/PauseAction"; import { PauseAction } from "@/video/components/actions/PauseAction";
import { PictureInPictureAction } from "@/video/components/actions/PictureInPictureAction";
import { ProgressAction } from "@/video/components/actions/ProgressAction"; import { ProgressAction } from "@/video/components/actions/ProgressAction";
import { SeriesSelectionAction } from "@/video/components/actions/SeriesSelectionAction"; import { SeriesSelectionAction } from "@/video/components/actions/SeriesSelectionAction";
import { ShowTitleAction } from "@/video/components/actions/ShowTitleAction"; import { ShowTitleAction } from "@/video/components/actions/ShowTitleAction";
import { KeyboardShortcutsAction } from "@/video/components/actions/KeyboardShortcutsAction";
import { SkipTimeAction } from "@/video/components/actions/SkipTimeAction"; import { SkipTimeAction } from "@/video/components/actions/SkipTimeAction";
import { TimeAction } from "@/video/components/actions/TimeAction"; import { TimeAction } from "@/video/components/actions/TimeAction";
import { VolumeAction } from "@/video/components/actions/VolumeAction"; import { VolumeAction } from "@/video/components/actions/VolumeAction";
import { VideoPlayerError } from "@/video/components/parts/VideoPlayerError"; import { VideoPlayerError } from "@/video/components/parts/VideoPlayerError";
import { PopoutProviderAction } from "@/video/components/popouts/PopoutProviderAction";
import { import {
VideoPlayerBase, VideoPlayerBase,
VideoPlayerBaseProps, VideoPlayerBaseProps,
} from "@/video/components/VideoPlayerBase"; } from "@/video/components/VideoPlayerBase";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; 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 { CaptionRendererAction } from "./actions/CaptionRendererAction";
import { SettingsAction } from "./actions/SettingsAction";
import { DividerAction } from "./actions/DividerAction"; import { DividerAction } from "./actions/DividerAction";
import { SettingsAction } from "./actions/SettingsAction";
import { VolumeAdjustedAction } from "./actions/VolumeAdjustedAction"; import { VolumeAdjustedAction } from "./actions/VolumeAdjustedAction";
type Props = VideoPlayerBaseProps; type Props = VideoPlayerBaseProps;

View File

@ -1,15 +1,17 @@
import { useRef } from "react";
import { CastingInternal } from "@/video/components/internal/CastingInternal"; import { CastingInternal } from "@/video/components/internal/CastingInternal";
import { WrapperRegisterInternal } from "@/video/components/internal/WrapperRegisterInternal"; import { WrapperRegisterInternal } from "@/video/components/internal/WrapperRegisterInternal";
import { VideoErrorBoundary } from "@/video/components/parts/VideoErrorBoundary"; import { VideoErrorBoundary } from "@/video/components/parts/VideoErrorBoundary";
import { useInterface } from "@/video/state/logic/interface"; import { useInterface } from "@/video/state/logic/interface";
import { useMeta } from "@/video/state/logic/meta"; import { useMeta } from "@/video/state/logic/meta";
import { useRef } from "react";
import {
useVideoPlayerDescriptor,
VideoPlayerContextProvider,
} from "../state/hooks";
import { MetaAction } from "./actions/MetaAction"; import { MetaAction } from "./actions/MetaAction";
import { VideoElementInternal } from "./internal/VideoElementInternal"; import { VideoElementInternal } from "./internal/VideoElementInternal";
import {
VideoPlayerContextProvider,
useVideoPlayerDescriptor,
} from "../state/hooks";
export interface VideoPlayerBaseProps { export interface VideoPlayerBaseProps {
children?: children?:

View File

@ -1,8 +1,10 @@
import { useCallback } from "react";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useMisc } from "@/video/state/logic/misc"; import { useMisc } from "@/video/state/logic/misc";
import { useCallback } from "react";
import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton";
interface Props { interface Props {

View File

@ -1,8 +1,9 @@
import React, { useCallback, useEffect, useRef, useState } from "react";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface"; import { useInterface } from "@/video/state/logic/interface";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import React, { useCallback, useEffect, useRef, useState } from "react";
interface BackdropActionProps { interface BackdropActionProps {
children?: React.ReactNode; children?: React.ReactNode;

View File

@ -1,9 +1,11 @@
import { useCallback, useEffect, 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 { Transition } from "@/components/Transition";
import { useSettings } from "@/state/settings"; import { useSettings } from "@/state/settings";
import { sanitize, parseSubtitles } from "@/backend/helpers/captions";
import { ContentCaption } from "subsrt-ts/dist/types/handler";
import { useRef, useEffect, useCallback } from "react";
import { useAsync } from "react-use";
import { useVideoPlayerDescriptor } from "../../state/hooks"; import { useVideoPlayerDescriptor } from "../../state/hooks";
import { useProgress } from "../../state/logic/progress"; import { useProgress } from "../../state/logic/progress";
import { useSource } from "../../state/logic/source"; import { useSource } from "../../state/logic/source";

View File

@ -1,7 +1,8 @@
import { useTranslation } from "react-i18next";
import { Icon, Icons } from "@/components/Icon"; import { Icon, Icons } from "@/components/Icon";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useMisc } from "@/video/state/logic/misc"; import { useMisc } from "@/video/state/logic/misc";
import { useTranslation } from "react-i18next";
export function CastingTextAction() { export function CastingTextAction() {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -1,8 +1,9 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { VideoPlayerIconButton } from "@/video/components/parts/VideoPlayerIconButton"; import { VideoPlayerIconButton } from "@/video/components/parts/VideoPlayerIconButton";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useMisc } from "@/video/state/logic/misc"; import { useMisc } from "@/video/state/logic/misc";
import { useCallback, useEffect, useRef, useState } from "react";
interface Props { interface Props {
className?: string; className?: string;

View File

@ -1,6 +1,6 @@
import { MWMediaType } from "@/backend/metadata/types";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useMeta } from "@/video/state/logic/meta"; import { useMeta } from "@/video/state/logic/meta";
import { MWMediaType } from "@/backend/metadata/types";
export function DividerAction() { export function DividerAction() {
const descriptor = useVideoPlayerDescriptor(); const descriptor = useVideoPlayerDescriptor();

View File

@ -1,9 +1,11 @@
import { useCallback } from "react";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { canFullscreen } from "@/utils/detectFeatures"; import { canFullscreen } from "@/utils/detectFeatures";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface"; import { useInterface } from "@/video/state/logic/interface";
import { useCallback } from "react";
import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton";
interface Props { interface Props {

View File

@ -1,11 +1,12 @@
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import { useVolumeControl } from "@/hooks/useVolumeToggle";
import { getPlayerState } from "@/video/state/cache";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface"; import { useInterface } from "@/video/state/logic/interface";
import { getPlayerState } from "@/video/state/cache";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useProgress } from "@/video/state/logic/progress"; import { useProgress } from "@/video/state/logic/progress";
import { useVolumeControl } from "@/hooks/useVolumeToggle";
export function KeyboardShortcutsAction() { export function KeyboardShortcutsAction() {
const descriptor = useVideoPlayerDescriptor(); const descriptor = useVideoPlayerDescriptor();

View File

@ -1,9 +1,10 @@
import { useEffect } from "react";
import { MWCaption } from "@/backend/helpers/streams"; import { MWCaption } from "@/backend/helpers/streams";
import { DetailedMeta } from "@/backend/metadata/getmeta"; import { DetailedMeta } from "@/backend/metadata/getmeta";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useMeta } from "@/video/state/logic/meta"; import { useMeta } from "@/video/state/logic/meta";
import { useProgress } from "@/video/state/logic/progress"; import { useProgress } from "@/video/state/logic/progress";
import { useEffect } from "react";
export type WindowMeta = { export type WindowMeta = {
meta: DetailedMeta; meta: DetailedMeta;

View File

@ -1,8 +1,9 @@
import { useCallback } from "react";
import { Icon, Icons } from "@/components/Icon"; import { Icon, Icons } from "@/components/Icon";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useCallback } from "react";
export function MiddlePauseAction() { export function MiddlePauseAction() {
const descriptor = useVideoPlayerDescriptor(); const descriptor = useVideoPlayerDescriptor();

View File

@ -1,5 +1,7 @@
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo"; import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo";
export function PageTitleAction() { export function PageTitleAction() {

View File

@ -1,8 +1,10 @@
import { useCallback } from "react";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useCallback } from "react";
import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton";
interface Props { interface Props {

View File

@ -1,13 +1,15 @@
import { useCallback } from "react";
import { useTranslation } from "react-i18next";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { useIsMobile } from "@/hooks/useIsMobile"; 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 { import {
canPictureInPicture, canPictureInPicture,
canWebkitPictureInPicture, canWebkitPictureInPicture,
} from "@/utils/detectFeatures"; } from "@/utils/detectFeatures";
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls";
import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton";
interface Props { interface Props {

View File

@ -1,3 +1,5 @@
import { useCallback, useEffect, useRef } from "react";
import { import {
makePercentage, makePercentage,
makePercentageString, makePercentageString,
@ -7,7 +9,6 @@ import { getPlayerState } from "@/video/state/cache";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useProgress } from "@/video/state/logic/progress"; import { useProgress } from "@/video/state/logic/progress";
import { useCallback, useEffect, useRef } from "react";
export function ProgressAction() { export function ProgressAction() {
const descriptor = useVideoPlayerDescriptor(); 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 { MWMediaType } from "@/backend/metadata/types";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { Icons } from "@/components/Icon";
import { useMeta } from "@/video/state/logic/meta"; import { FloatingAnchor } from "@/components/popout/FloatingAnchor";
import { VideoPlayerIconButton } from "@/video/components/parts/VideoPlayerIconButton"; import { VideoPlayerIconButton } from "@/video/components/parts/VideoPlayerIconButton";
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface"; import { useInterface } from "@/video/state/logic/interface";
import { useTranslation } from "react-i18next"; import { useMeta } from "@/video/state/logic/meta";
import { FloatingAnchor } from "@/components/popout/FloatingAnchor";
interface Props { interface Props {
className?: string; className?: string;

View File

@ -1,11 +1,12 @@
import { useTranslation } from "react-i18next";
import { Icons } from "@/components/Icon"; 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 { VideoPlayerIconButton } from "@/video/components/parts/VideoPlayerIconButton";
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface"; 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 { interface Props {
className?: string; className?: string;

View File

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

View File

@ -2,6 +2,7 @@ import { Icons } from "@/components/Icon";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useProgress } from "@/video/state/logic/progress"; import { useProgress } from "@/video/state/logic/progress";
import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton"; import { VideoPlayerIconButton } from "../parts/VideoPlayerIconButton";
interface Props { interface Props {

View File

@ -1,11 +1,12 @@
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useTranslation } from "react-i18next"; 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 { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useProgress } from "@/video/state/logic/progress"; import { useProgress } from "@/video/state/logic/progress";
import { useInterface } from "@/video/state/logic/interface";
import { VideoPlayerTimeFormat } from "@/video/state/types"; import { VideoPlayerTimeFormat } from "@/video/state/types";
import { useIsMobile } from "@/hooks/useIsMobile";
import { useControls } from "@/video/state/logic/controls";
function durationExceedsHour(secs: number): boolean { function durationExceedsHour(secs: number): boolean {
return secs > 60 * 60; return secs > 60 * 60;

View File

@ -1,3 +1,5 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { Icon, Icons } from "@/components/Icon"; import { Icon, Icons } from "@/components/Icon";
import { import {
makePercentage, makePercentage,
@ -10,7 +12,6 @@ import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface"; import { useInterface } from "@/video/state/logic/interface";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useCallback, useEffect, useRef, useState } from "react";
interface Props { interface Props {
className?: string; className?: string;

View File

@ -1,5 +1,7 @@
import { Icons } from "@/components/Icon";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Icons } from "@/components/Icon";
import { PopoutListAction } from "../../popouts/PopoutUtils"; import { PopoutListAction } from "../../popouts/PopoutUtils";
interface Props { 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 { 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 { useMeta } from "@/video/state/logic/meta";
import { useSource } from "@/video/state/logic/source";
import { PopoutListAction } from "../../popouts/PopoutUtils"; import { PopoutListAction } from "../../popouts/PopoutUtils";
export function DownloadAction() { export function DownloadAction() {

View File

@ -1,5 +1,7 @@
import { Icons } from "@/components/Icon";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Icons } from "@/components/Icon";
import { PopoutListAction } from "../../popouts/PopoutUtils"; import { PopoutListAction } from "../../popouts/PopoutUtils";
interface Props { interface Props {

View File

@ -1,7 +1,9 @@
import { Icons } from "@/components/Icon";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { PopoutListAction } from "../../popouts/PopoutUtils";
import { Icons } from "@/components/Icon";
import { QualityDisplayAction } from "./QualityDisplayAction"; import { QualityDisplayAction } from "./QualityDisplayAction";
import { PopoutListAction } from "../../popouts/PopoutUtils";
interface Props { interface Props {
onClick?: () => any; onClick?: () => any;

View File

@ -1,9 +1,10 @@
import { useEffect } from "react";
import { MWCaption } from "@/backend/helpers/streams"; import { MWCaption } from "@/backend/helpers/streams";
import { MWSeasonWithEpisodeMeta } from "@/backend/metadata/types"; import { MWSeasonWithEpisodeMeta } from "@/backend/metadata/types";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { VideoPlayerMeta } from "@/video/state/types"; import { VideoPlayerMeta } from "@/video/state/types";
import { useEffect } from "react";
interface MetaControllerProps { interface MetaControllerProps {
data?: VideoPlayerMeta; data?: VideoPlayerMeta;

View File

@ -1,10 +1,11 @@
import { useEffect, useMemo, useRef } from "react";
import throttle from "lodash.throttle"; import throttle from "lodash.throttle";
import { useEffect, useMemo, useRef } from "react";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; 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 { useControls } from "@/video/state/logic/controls";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useMisc } from "@/video/state/logic/misc"; import { useMisc } from "@/video/state/logic/misc";
import { useProgress } from "@/video/state/logic/progress";
interface Props { interface Props {
startAt?: number; 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 { useEffect, useRef } from "react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useMeta } from "@/video/state/logic/meta";
interface SeriesControllerProps { interface SeriesControllerProps {
onSelect?: (state: { episodeId?: string; seasonId?: string }) => void; 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 { getCaptionUrl, makeCaptionId } from "@/backend/helpers/captions";
import { import {
MWCaption, MWCaption,
@ -9,7 +11,6 @@ import { useSettings } from "@/state/settings";
import { useInitialized } from "@/video/components/hooks/useInitialized"; import { useInitialized } from "@/video/components/hooks/useInitialized";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useEffect, useRef } from "react";
interface SourceControllerProps { interface SourceControllerProps {
source: string; 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 { useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MWMediaType } from "@/backend/metadata/types";
import { useMeta } from "@/video/state/logic/meta";
export function useCurrentSeriesEpisodeInfo(descriptor: string) { export function useCurrentSeriesEpisodeInfo(descriptor: string) {
const meta = useMeta(descriptor); const meta = useMeta(descriptor);
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -1,6 +1,7 @@
import { useMisc } from "@/video/state/logic/misc";
import { useMemo } from "react"; import { useMemo } from "react";
import { useMisc } from "@/video/state/logic/misc";
export function useInitialized(descriptor: string): { initialized: boolean } { export function useInitialized(descriptor: string): { initialized: boolean } {
const misc = useMisc(descriptor); const misc = useMisc(descriptor);
const initialized = useMemo(() => !!misc.initalized, [misc]); 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 { useEffect, useRef } from "react";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { ControlMethods, useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface";
function syncRouteToPopout( function syncRouteToPopout(
location: ReturnType<typeof useLocation>, location: ReturnType<typeof useLocation>,
controls: ControlMethods controls: ControlMethods

View File

@ -1,10 +1,11 @@
import { useEffect, useMemo, useRef } from "react";
import { useChromecastAvailable } from "@/hooks/useChromecastAvailable"; import { useChromecastAvailable } from "@/hooks/useChromecastAvailable";
import { getPlayerState } from "@/video/state/cache"; import { getPlayerState } from "@/video/state/cache";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { updateMisc, useMisc } from "@/video/state/logic/misc"; import { updateMisc, useMisc } from "@/video/state/logic/misc";
import { createCastingStateProvider } from "@/video/state/providers/castingStateProvider"; import { createCastingStateProvider } from "@/video/state/providers/castingStateProvider";
import { setProvider, unsetStateProvider } from "@/video/state/providers/utils"; import { setProvider, unsetStateProvider } from "@/video/state/providers/utils";
import { useEffect, useMemo, useRef } from "react";
export function CastingInternal() { export function CastingInternal() {
const descriptor = useVideoPlayerDescriptor(); const descriptor = useVideoPlayerDescriptor();

View File

@ -1,9 +1,10 @@
import { useEffect, useMemo, useRef } from "react";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useMisc } from "@/video/state/logic/misc"; import { useMisc } from "@/video/state/logic/misc";
import { setProvider, unsetStateProvider } from "@/video/state/providers/utils"; import { setProvider, unsetStateProvider } from "@/video/state/providers/utils";
import { createVideoStateProvider } from "@/video/state/providers/videoStateProvider"; import { createVideoStateProvider } from "@/video/state/providers/videoStateProvider";
import { useEffect, useMemo, useRef } from "react";
interface Props { interface Props {
autoPlay?: boolean; autoPlay?: boolean;

View File

@ -1,7 +1,8 @@
import { useEffect } from "react";
import { getPlayerState } from "@/video/state/cache"; import { getPlayerState } from "@/video/state/cache";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { updateMisc } from "@/video/state/logic/misc"; import { updateMisc } from "@/video/state/logic/misc";
import { useEffect } from "react";
export function WrapperRegisterInternal(props: { export function WrapperRegisterInternal(props: {
wrapper: HTMLDivElement | null; 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 { MWMediaMeta } from "@/backend/metadata/types";
import { ErrorMessage } from "@/components/layout/ErrorBoundary"; import { ErrorMessage } from "@/components/layout/ErrorBoundary";
import { Link } from "@/components/text/Link"; import { Link } from "@/components/text/Link";
import { conf } from "@/setup/config"; 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"; import { VideoPlayerHeader } from "./VideoPlayerHeader";
interface ErrorBoundaryState { interface ErrorBoundaryState {

View File

@ -1,10 +1,12 @@
import { ReactNode } from "react";
import { IconPatch } from "@/components/buttons/IconPatch"; import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon"; import { Icons } from "@/components/Icon";
import { Title } from "@/components/text/Title"; import { Title } from "@/components/text/Title";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useError } from "@/video/state/logic/error"; import { useError } from "@/video/state/logic/error";
import { useMeta } from "@/video/state/logic/meta"; import { useMeta } from "@/video/state/logic/meta";
import { ReactNode } from "react";
import { VideoPlayerHeader } from "./VideoPlayerHeader"; import { VideoPlayerHeader } from "./VideoPlayerHeader";
interface VideoPlayerErrorProps { interface VideoPlayerErrorProps {

View File

@ -1,16 +1,17 @@
import { useTranslation } from "react-i18next";
import { MWMediaMeta } from "@/backend/metadata/types"; import { MWMediaMeta } from "@/backend/metadata/types";
import { IconPatch } from "@/components/buttons/IconPatch"; import { IconPatch } from "@/components/buttons/IconPatch";
import { Icon, Icons } from "@/components/Icon"; import { Icon, Icons } from "@/components/Icon";
import { BrandPill } from "@/components/layout/BrandPill"; import { BrandPill } from "@/components/layout/BrandPill";
import { useBannerSize } from "@/hooks/useBanner";
import { useIsMobile } from "@/hooks/useIsMobile";
import { import {
getIfBookmarkedFromPortable, getIfBookmarkedFromPortable,
useBookmarkContext, useBookmarkContext,
} from "@/state/bookmark"; } from "@/state/bookmark";
import { AirplayAction } from "@/video/components/actions/AirplayAction"; import { AirplayAction } from "@/video/components/actions/AirplayAction";
import { ChromecastAction } from "@/video/components/actions/ChromecastAction"; import { ChromecastAction } from "@/video/components/actions/ChromecastAction";
import { useTranslation } from "react-i18next";
import { useIsMobile } from "@/hooks/useIsMobile";
import { useBannerSize } from "@/hooks/useBanner";
interface VideoPlayerHeaderProps { interface VideoPlayerHeaderProps {
media?: MWMediaMeta; media?: MWMediaMeta;

View File

@ -1,6 +1,7 @@
import { Icon, Icons } from "@/components/Icon";
import React, { forwardRef } from "react"; import React, { forwardRef } from "react";
import { Icon, Icons } from "@/components/Icon";
export interface VideoPlayerIconButtonProps { export interface VideoPlayerIconButtonProps {
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void; onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
icon: Icons; icon: Icons;

View File

@ -1,7 +1,8 @@
import { useEffect, useRef } from "react";
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useInterface } from "@/video/state/logic/interface"; import { useInterface } from "@/video/state/logic/interface";
import { useEffect, useRef } from "react";
interface Props { interface Props {
children?: React.ReactNode; children?: React.ReactNode;

View File

@ -1,3 +1,6 @@
import { useMemo, useRef } from "react";
import { useTranslation } from "react-i18next";
import { import {
customCaption, customCaption,
getCaptionUrl, getCaptionUrl,
@ -15,8 +18,7 @@ import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useControls } from "@/video/state/logic/controls"; import { useControls } from "@/video/state/logic/controls";
import { useMeta } from "@/video/state/logic/meta"; import { useMeta } from "@/video/state/logic/meta";
import { useSource } from "@/video/state/logic/source"; import { useSource } from "@/video/state/logic/source";
import { useMemo, useRef } from "react";
import { useTranslation } from "react-i18next";
import { PopoutListEntry, PopoutSection } from "./PopoutUtils"; import { PopoutListEntry, PopoutSection } from "./PopoutUtils";
export function CaptionSelectionPopout(props: { 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 { useTranslation } from "react-i18next";
import { Slider } from "@/components/Slider";
import CaptionColorSelector, { import CaptionColorSelector, {
colors, colors,
} from "@/components/CaptionColorSelector"; } 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: { export function CaptionSettingsPopout(props: {
router: ReturnType<typeof useFloatingRouter>; router: ReturnType<typeof useFloatingRouter>;

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