From d72e98eb1eb0bc4e8363b6557b8d1e9aa0b22078 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Mon, 28 Feb 2022 22:00:32 +0100 Subject: [PATCH] add hover state to brand pill - use replace instead of push for search url - video loading and error state - extra elaboration of providers in readme --- README.md | 4 +- src/components/layout/BrandPill.tsx | 15 +++++--- src/components/layout/Navigation.tsx | 30 +++++++++++---- src/components/media/VideoPlayer.tsx | 57 ++++++++++++++++++++-------- src/hooks/useSearchQuery.ts | 24 ++++++++---- src/providers/README.md | 23 +++++++++++ 6 files changed, 114 insertions(+), 39 deletions(-) create mode 100644 src/providers/README.md diff --git a/README.md b/README.md index c7976ed9..9cf13051 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Check out [this project's issues](https://github.com/JamesHawkinss/movie-web/iss - [x] Global state for media objects - [x] Styling for pages - [x] loading stream player view + error - - [ ] video load error, video loading (from actual video player) + - [x] video load error, video loading (from actual video player) - [ ] Series episodes+seasons - [ ] implement source that are not mp4 - [ ] Subtitles @@ -61,7 +61,7 @@ Check out [this project's issues](https://github.com/JamesHawkinss/movie-web/iss - [ ] Get rid of react warnings - [ ] Implement more scrapers - [ ] Add 404 page for media (media not found, provider disabled, provider not found) & general (page not found) -- [ ] Brand tag hover state and cursor +- [x] Brand tag hover state and cursor - [ ] Handle disabled providers (continue watching, bookmarks & router) ## After all rewrite code has been written diff --git a/src/components/layout/BrandPill.tsx b/src/components/layout/BrandPill.tsx index d51e5104..b2b8eabd 100644 --- a/src/components/layout/BrandPill.tsx +++ b/src/components/layout/BrandPill.tsx @@ -1,11 +1,16 @@ -import { Icon, Icons } from 'components/Icon' - -export function BrandPill() { +import { Icon, Icons } from "components/Icon"; +export function BrandPill(props: { clickable?: boolean }) { return ( -
+
movie-web
- ) + ); } diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx index 375878e6..3e40ff6d 100644 --- a/src/components/layout/Navigation.tsx +++ b/src/components/layout/Navigation.tsx @@ -2,7 +2,7 @@ import { IconPatch } from "components/buttons/IconPatch"; import { Icons } from "components/Icon"; import { DISCORD_LINK, GITHUB_LINK } from "mw_constants"; import { ReactNode } from "react"; -import { Link } from "react-router-dom" +import { Link } from "react-router-dom"; import { BrandPill } from "./BrandPill"; export interface NavigationProps { @@ -11,19 +11,33 @@ export interface NavigationProps { export function Navigation(props: NavigationProps) { return ( -
-
+
+
- - + +
{props.children}
- - + + + + + +
- ) + ); } diff --git a/src/components/media/VideoPlayer.tsx b/src/components/media/VideoPlayer.tsx index 8784f3ed..f9e04e5a 100644 --- a/src/components/media/VideoPlayer.tsx +++ b/src/components/media/VideoPlayer.tsx @@ -2,7 +2,7 @@ import { IconPatch } from "components/buttons/IconPatch"; import { Icons } from "components/Icon"; import { Loading } from "components/layout/Loading"; import { MWMediaStream } from "providers"; -import { useRef } from "react"; +import { useEffect, useRef, useState } from "react"; export interface VideoPlayerProps { source: MWMediaStream; @@ -30,23 +30,48 @@ export function SkeletonVideoPlayer(props: { error?: boolean }) { export function VideoPlayer(props: VideoPlayerProps) { const videoRef = useRef(null); + const [hasErrored, setErrored] = useState(false); + const [isLoading, setLoading] = useState(true); + const showVideo = !isLoading && !hasErrored; const mustUseHls = props.source.type === "m3u8"; + // reset if stream url changes + useEffect(() => { + setLoading(true); + setErrored(false); + }, [props.source.url]); + return ( - + <> + {hasErrored ? ( + + ) : isLoading ? ( + + ) : null} + + ); } diff --git a/src/hooks/useSearchQuery.ts b/src/hooks/useSearchQuery.ts index cf938358..942dee91 100644 --- a/src/hooks/useSearchQuery.ts +++ b/src/hooks/useSearchQuery.ts @@ -3,24 +3,32 @@ import React, { useState } from "react"; import { generatePath, useHistory, useRouteMatch } from "react-router-dom"; export function useSearchQuery(): [MWQuery, (inp: Partial) => void] { - const history = useHistory() - const { path, params } = useRouteMatch<{ type: string, query: string}>() + const history = useHistory(); + const { path, params } = useRouteMatch<{ type: string; query: string }>(); const [search, setSearch] = useState({ searchQuery: "", type: MWMediaType.MOVIE, }); const updateParams = (inp: Partial) => { - const copySearch: MWQuery = {...search}; + const copySearch: MWQuery = { ...search }; Object.assign(copySearch, inp); - history.push(generatePath(path, { query: copySearch.searchQuery.length === 0 ? undefined : inp.searchQuery, type: copySearch.type })) - } + history.replace( + generatePath(path, { + query: + copySearch.searchQuery.length === 0 ? undefined : inp.searchQuery, + type: copySearch.type, + }) + ); + }; React.useEffect(() => { - const type = Object.values(MWMediaType).find(v=>params.type === v) || MWMediaType.MOVIE; + const type = + Object.values(MWMediaType).find((v) => params.type === v) || + MWMediaType.MOVIE; const searchQuery = params.query || ""; setSearch({ type, searchQuery }); - }, [params, setSearch]) + }, [params, setSearch]); - return [search, updateParams] + return [search, updateParams]; } diff --git a/src/providers/README.md b/src/providers/README.md new file mode 100644 index 00000000..19f3dc6d --- /dev/null +++ b/src/providers/README.md @@ -0,0 +1,23 @@ +# the providers + +to make this as clear as possible, here is some extra information on how the interal system works regarding providers. + +| Term | explanation | +| ------------- | ------------------------------------------------------------------------------------- | +| Media | Object containing information about a piece of media. like title and its id's | +| PortableMedia | Object with just the identifiers of a piece of media. used for transport and saving | +| MediaStream | Object with a stream url in it. use it to view a piece of media. | +| Provider | group of methods to generate media and mediastreams from a source. aliased as scraper | + +All types are prefixed with MW (MovieWeb) to prevent clashing names. + +## Some rules + +1. **Never** remove a provider completely if it's been in use before. just disable it. +2. **Never** change the ID of a provider if it's been in use before. +3. **Never** change system of the media ID of a provider without making it backwards compatible + +All these rules are because `PortableMedia` objects need to stay functional. because: + +- It's used for routing, links would stop working +- It's used for storage, continue watching and bookmarks would stop working