+
{props.content.map((item, index) => (
{index !== 0 ? (
diff --git a/src/components/text/Link.tsx b/src/components/text/Link.tsx
index 7505f41c..1451114e 100644
--- a/src/components/text/Link.tsx
+++ b/src/components/text/Link.tsx
@@ -16,22 +16,27 @@ interface ILinkPropsInternal extends ILinkPropsBase {
to: string;
}
-type LinkProps =
- | ILinkPropsExternal
- | ILinkPropsInternal
- | ILinkPropsBase;
+type LinkProps = ILinkPropsExternal | ILinkPropsInternal | ILinkPropsBase;
export function Link(props: LinkProps) {
const isExternal = !!(props as ILinkPropsExternal).url;
const isInternal = !!(props as ILinkPropsInternal).to;
const content = (
-
+
{props.children}
);
if (isExternal)
- return {content};
+ return (
+
+ {content}
+
+ );
if (isInternal)
return (
{content}
diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts
index 509337b6..fdc9b6db 100644
--- a/src/hooks/useDebounce.ts
+++ b/src/hooks/useDebounce.ts
@@ -4,17 +4,14 @@ export function useDebounce(value: T, delay: number): T {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState(value);
- useEffect(
- () => {
- const handler = setTimeout(() => {
- setDebouncedValue(value);
- }, delay);
- return () => {
- clearTimeout(handler);
- };
- },
- [value, delay]
- );
+ useEffect(() => {
+ const handler = setTimeout(() => {
+ setDebouncedValue(value);
+ }, delay);
+ return () => {
+ clearTimeout(handler);
+ };
+ }, [value, delay]);
return debouncedValue;
}
diff --git a/src/hooks/useFade.ts b/src/hooks/useFade.ts
index e03413fd..58438acf 100644
--- a/src/hooks/useFade.ts
+++ b/src/hooks/useFade.ts
@@ -1,7 +1,9 @@
import React, { useEffect, useState } from "react";
-import './useFade.css'
+import "./useFade.css";
-export const useFade = (initial = false): [boolean, React.Dispatch>, any] => {
+export const useFade = (
+ initial = false
+): [boolean, React.Dispatch>, any] => {
const [show, setShow] = useState(initial);
const [isVisible, setVisible] = useState(show);
@@ -20,7 +22,7 @@ export const useFade = (initial = false): [boolean, React.Dispatch;
-
-export interface MWQuery {
- searchQuery: string;
- type: MWMediaType;
-}
-
-export interface MWMediaProviderBase {
- id: string; // id of provider, must be unique
- enabled: boolean;
- type: MWMediaType[];
- displayName: string;
-
- getMediaFromPortable(media: MWPortableMedia): Promise;
- searchForMedia(query: MWQuery): Promise;
- getStream(media: MWPortableMedia): Promise;
- getSeasonDataFromMedia?: (media: MWPortableMedia) => Promise;
-}
-
-export type MWMediaProviderSeries = MWMediaProviderBase & {
- getSeasonDataFromMedia: (media: MWPortableMedia) => Promise;
-};
-
-export type MWMediaProvider = MWMediaProviderBase;
-
-export interface MWMediaProviderMetadata {
- exists: boolean;
- id?: string;
- enabled: boolean;
- type: MWMediaType[];
- provider?: MWMediaProvider;
-}
-
-export interface MWMassProviderOutput {
- providers: {
- id: string;
- success: boolean;
- }[];
- results: MWMedia[];
- stats: {
- total: number;
- failed: number;
- succeeded: number;
- };
-}
+export enum MWMediaType {
+ MOVIE = "movie",
+ SERIES = "series",
+ ANIME = "anime",
+}
+
+export interface MWPortableMedia {
+ mediaId: string;
+ mediaType: MWMediaType;
+ providerId: string;
+ seasonId?: string;
+ episodeId?: string;
+}
+
+export type MWMediaStreamType = "m3u8" | "mp4";
+export interface MWMediaCaption {
+ id: string;
+ url: string;
+ label: string;
+}
+export interface MWMediaStream {
+ url: string;
+ type: MWMediaStreamType;
+ captions: MWMediaCaption[];
+}
+
+export interface MWMediaMeta extends MWPortableMedia {
+ title: string;
+ year: string;
+ seasonCount?: number;
+}
+
+export interface MWMediaEpisode {
+ sort: number;
+ id: string;
+ title: string;
+}
+export interface MWMediaSeason {
+ sort: number;
+ id: string;
+ title?: string;
+ type: "season" | "special";
+ episodes: MWMediaEpisode[];
+}
+export interface MWMediaSeasons {
+ seasons: MWMediaSeason[];
+}
+
+export interface MWMedia extends MWMediaMeta {
+ seriesData?: MWMediaSeasons;
+}
+
+export type MWProviderMediaResult = Omit;
+
+export interface MWQuery {
+ searchQuery: string;
+ type: MWMediaType;
+}
+
+export interface MWMediaProviderBase {
+ id: string; // id of provider, must be unique
+ enabled: boolean;
+ type: MWMediaType[];
+ displayName: string;
+
+ getMediaFromPortable(media: MWPortableMedia): Promise;
+ searchForMedia(query: MWQuery): Promise;
+ getStream(media: MWPortableMedia): Promise;
+ getSeasonDataFromMedia?: (media: MWPortableMedia) => Promise;
+}
+
+export type MWMediaProviderSeries = MWMediaProviderBase & {
+ getSeasonDataFromMedia: (media: MWPortableMedia) => Promise;
+};
+
+export type MWMediaProvider = MWMediaProviderBase;
+
+export interface MWMediaProviderMetadata {
+ exists: boolean;
+ id?: string;
+ enabled: boolean;
+ type: MWMediaType[];
+ provider?: MWMediaProvider;
+}
+
+export interface MWMassProviderOutput {
+ providers: {
+ id: string;
+ success: boolean;
+ }[];
+ results: MWMedia[];
+ stats: {
+ total: number;
+ failed: number;
+ succeeded: number;
+ };
+}
diff --git a/src/setup/i18n.ts b/src/setup/i18n.ts
index 8ab960b1..312380b1 100644
--- a/src/setup/i18n.ts
+++ b/src/setup/i18n.ts
@@ -1,8 +1,8 @@
-import i18n from 'i18next';
-import { initReactI18next } from 'react-i18next';
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
-import Backend from 'i18next-http-backend';
-import LanguageDetector from 'i18next-browser-languagedetector';
+import Backend from "i18next-http-backend";
+import LanguageDetector from "i18next-browser-languagedetector";
i18n
// load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
@@ -17,12 +17,11 @@ i18n
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
- fallbackLng: 'en-GB',
+ fallbackLng: "en-GB",
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
- }
+ },
});
-
-export default i18n;
\ No newline at end of file
+export default i18n;
diff --git a/src/state/bookmark/index.ts b/src/state/bookmark/index.ts
index 1b3fa9eb..2edd280c 100644
--- a/src/state/bookmark/index.ts
+++ b/src/state/bookmark/index.ts
@@ -1 +1 @@
-export * from "./context";
\ No newline at end of file
+export * from "./context";
diff --git a/src/views/MediaView.tsx b/src/views/MediaView.tsx
index 02ea86e0..88fe66df 100644
--- a/src/views/MediaView.tsx
+++ b/src/views/MediaView.tsx
@@ -1,5 +1,6 @@
import { ReactElement, useEffect, useState } from "react";
import { useHistory } from "react-router-dom";
+import { useTranslation } from "react-i18next";
import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon";
import { Navigation } from "@/components/layout/Navigation";
@@ -29,7 +30,6 @@ import {
useBookmarkContext,
} from "@/state/bookmark";
import { getWatchedFromPortable, useWatchedContext } from "@/state/watched";
-import { useTranslation } from "react-i18next";
import { NotFoundChecks } from "./notfound/NotFoundChecks";
interface StyledMediaViewProps {
diff --git a/src/views/notfound/NotFoundView.tsx b/src/views/notfound/NotFoundView.tsx
index 6ba492ac..14cb7829 100644
--- a/src/views/notfound/NotFoundView.tsx
+++ b/src/views/notfound/NotFoundView.tsx
@@ -1,10 +1,10 @@
import { ReactNode } from "react";
+import { useTranslation } from "react-i18next";
import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon";
import { Navigation } from "@/components/layout/Navigation";
import { ArrowLink } from "@/components/text/ArrowLink";
import { Title } from "@/components/text/Title";
-import { useTranslation } from "react-i18next";
function NotFoundWrapper(props: { children?: ReactNode }) {
return (
diff --git a/src/views/search/HomeView.tsx b/src/views/search/HomeView.tsx
index 180d456e..16f68e7c 100644
--- a/src/views/search/HomeView.tsx
+++ b/src/views/search/HomeView.tsx
@@ -1,3 +1,4 @@
+import { useTranslation } from "react-i18next";
import { Icons } from "@/components/Icon";
import { SectionHeading } from "@/components/layout/SectionHeading";
import { MediaGrid } from "@/components/media/MediaGrid";
@@ -7,7 +8,6 @@ import {
useBookmarkContext,
} from "@/state/bookmark";
import { useWatchedContext } from "@/state/watched";
-import { useTranslation } from "react-i18next";
function Bookmarks() {
const { t } = useTranslation();
diff --git a/src/views/search/SearchLoadingView.tsx b/src/views/search/SearchLoadingView.tsx
index 6d02ff51..54cbeef9 100644
--- a/src/views/search/SearchLoadingView.tsx
+++ b/src/views/search/SearchLoadingView.tsx
@@ -1,5 +1,5 @@
-import { Loading } from "@/components/layout/Loading";
import { useTranslation } from "react-i18next";
+import { Loading } from "@/components/layout/Loading";
export function SearchLoadingView() {
const { t } = useTranslation();
diff --git a/src/views/search/SearchResultsPartial.tsx b/src/views/search/SearchResultsPartial.tsx
index 96934fa8..59281093 100644
--- a/src/views/search/SearchResultsPartial.tsx
+++ b/src/views/search/SearchResultsPartial.tsx
@@ -1,6 +1,6 @@
+import { useEffect, useMemo, useState } from "react";
import { useDebounce } from "@/hooks/useDebounce";
import { MWQuery } from "@/providers";
-import { useEffect, useMemo, useState } from "react";
import { HomeView } from "./HomeView";
import { SearchLoadingView } from "./SearchLoadingView";
import { SearchResultsView } from "./SearchResultsView";
diff --git a/src/views/search/SearchResultsView.tsx b/src/views/search/SearchResultsView.tsx
index 5f602988..6a775a23 100644
--- a/src/views/search/SearchResultsView.tsx
+++ b/src/views/search/SearchResultsView.tsx
@@ -1,3 +1,5 @@
+import { useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon";
import { SectionHeading } from "@/components/layout/SectionHeading";
@@ -5,8 +7,6 @@ import { MediaGrid } from "@/components/media/MediaGrid";
import { WatchedMediaCard } from "@/components/media/WatchedMediaCard";
import { useLoading } from "@/hooks/useLoading";
import { MWMassProviderOutput, MWQuery, SearchProviders } from "@/providers";
-import { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
import { SearchLoadingView } from "./SearchLoadingView";
function SearchSuffix(props: {
diff --git a/src/views/search/SearchView.tsx b/src/views/search/SearchView.tsx
index c786cbe1..ad61b696 100644
--- a/src/views/search/SearchView.tsx
+++ b/src/views/search/SearchView.tsx
@@ -1,12 +1,12 @@
import { useCallback, useState } from "react";
+import Sticky from "react-stickynode";
+import { useTranslation } from "react-i18next";
import { Navigation } from "@/components/layout/Navigation";
import { ThinContainer } from "@/components/layout/ThinContainer";
import { SearchBarInput } from "@/components/SearchBar";
-import Sticky from "react-stickynode";
import { Title } from "@/components/text/Title";
import { useSearchQuery } from "@/hooks/useSearchQuery";
import { WideContainer } from "@/components/layout/WideContainer";
-import { useTranslation } from "react-i18next";
import { SearchResultsPartial } from "./SearchResultsPartial";
export function SearchView() {