mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-27 10:31:48 +01:00
Merge branch 'dev' into time-format
This commit is contained in:
commit
6eb25fb49c
53
.eslintrc.js
53
.eslintrc.js
@ -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,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -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>
|
||||||
|
@ -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",
|
||||||
|
@ -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();
|
||||||
|
@ -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}`;
|
||||||
|
@ -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 { mwFetch, proxiedFetch } from "@/backend/helpers/fetch";
|
||||||
import { MWCaption } from "@/backend/helpers/streams";
|
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 const customCaption = "external-custom";
|
||||||
export function makeCaptionId(caption: MWCaption, isLinked: boolean): string {
|
export function makeCaptionId(caption: MWCaption, isLinked: boolean): string {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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"
|
||||||
|
@ -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) => {
|
||||||
|
@ -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 {
|
import {
|
||||||
|
@ -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 = {
|
||||||
|
@ -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";
|
||||||
|
@ -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";
|
||||||
|
|
||||||
const nanoid = customAlphabet("0123456789abcdef", 32);
|
const nanoid = customAlphabet("0123456789abcdef", 32);
|
||||||
|
@ -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;
|
||||||
|
@ -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"];
|
||||||
|
@ -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 {
|
||||||
|
@ -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 (
|
||||||
<>
|
<>
|
||||||
|
@ -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";
|
||||||
|
@ -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"
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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: {
|
||||||
|
@ -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: {
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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";
|
||||||
|
@ -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) ||
|
||||||
|
@ -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);
|
||||||
|
@ -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";
|
||||||
|
@ -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"
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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([
|
||||||
|
@ -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: {
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"seasons": {
|
"seasons": {
|
||||||
"seasonAndEpisode": "S{{saison}} E{{épisode}}"
|
"seasonAndEpisode": "S{{season}} E{{episode}}"
|
||||||
},
|
},
|
||||||
"notFound": {
|
"notFound": {
|
||||||
"genericTitle": "Introuvable",
|
"genericTitle": "Introuvable",
|
||||||
|
@ -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,
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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")
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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>()
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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>()
|
||||||
|
@ -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;
|
||||||
|
@ -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?:
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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 { useRef } from "react";
|
||||||
import { useAsync } from "react-use";
|
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 { 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";
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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() {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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() {
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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() {
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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]);
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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: {
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user