bunch of chromecast fixes

Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
Co-authored-by: James Hawkins <jhawki2005@gmail.com>
Co-authored-by: William Oldham <wegg7250@gmail.com>
This commit is contained in:
mrjvs 2023-02-19 22:22:01 +01:00
parent d6d318006b
commit b886443ea7
9 changed files with 61 additions and 34 deletions

View File

@ -12,7 +12,6 @@ interface Props {
animation: TransitionAnimations; animation: TransitionAnimations;
className?: string; className?: string;
children?: ReactNode; children?: ReactNode;
appearOnMount?: boolean;
isChild?: boolean; isChild?: boolean;
} }
@ -62,23 +61,14 @@ export function Transition(props: Props) {
if (props.isChild) { if (props.isChild) {
return ( return (
<HeadlessTransition.Child <HeadlessTransition.Child as={Fragment} {...classes}>
as={Fragment}
appear={props.appearOnMount}
{...classes}
>
<div className={props.className}>{props.children}</div> <div className={props.className}>{props.children}</div>
</HeadlessTransition.Child> </HeadlessTransition.Child>
); );
} }
return ( return (
<HeadlessTransition <HeadlessTransition show={props.show} as={Fragment} {...classes}>
show={props.show}
as={Fragment}
appear={props.appearOnMount}
{...classes}
>
<div className={props.className}>{props.children}</div> <div className={props.className}>{props.children}</div>
</HeadlessTransition> </HeadlessTransition>
); );

View File

@ -13,13 +13,11 @@ export function ModalFrame(props: Props) {
<Transition <Transition
className="fixed inset-0 z-[9999]" className="fixed inset-0 z-[9999]"
animation="none" animation="none"
appearOnMount
show={props.show} show={props.show}
> >
<Overlay> <Overlay>
<Transition <Transition
isChild isChild
appearOnMount
className="flex h-full w-full items-center justify-center" className="flex h-full w-full items-center justify-center"
animation="slide-up" animation="slide-up"
> >

View File

@ -79,9 +79,13 @@
} }
}, },
"v3": { "v3": {
"newSiteTitle": "Version 3 has released!", "newSiteTitle": "New version now released!",
"newDomain": "https://movie-web.app", "newDomain": "https://movie-web.app",
"newDomainText": "We have a new domain. You can now access our website on <0>https://movie-web.app</0>. Make sure to update all your bookmarks as <1>the old link will stop working on {{date}}.</1>", "newDomainText": "movie-web will soon be moving to a new domain: <0>https://movie-web.app</0>. Make sure to update all your bookmarks as <1>the old website will stop working on {{date}}.</1>",
"tireless": "We've worked tirelessly on this new update, we hope you will enjoy what we've been cooking up for the past months." "tireless": "We've worked tirelessly on this new update, we hope you will enjoy what we've been cooking up for the past months.",
"leaveAnnouncement": "Take me there!"
},
"casting": {
"casting": "Casting to device..."
} }
} }

View File

@ -29,6 +29,7 @@ import { useControls } from "@/video/state/logic/controls";
import { ReactNode, useCallback, useState } from "react"; import { ReactNode, useCallback, useState } from "react";
import { PopoutProviderAction } from "@/video/components/popouts/PopoutProviderAction"; import { PopoutProviderAction } from "@/video/components/popouts/PopoutProviderAction";
import { ChromecastAction } from "@/video/components/actions/ChromecastAction"; import { ChromecastAction } from "@/video/components/actions/ChromecastAction";
import { CastingTextAction } from "@/video/components/actions/CastingTextAction";
type Props = VideoPlayerBaseProps; type Props = VideoPlayerBaseProps;
@ -94,6 +95,9 @@ export function VideoPlayer(props: Props) {
<CenterPosition> <CenterPosition>
<LoadingAction /> <LoadingAction />
</CenterPosition> </CenterPosition>
<CenterPosition>
<CastingTextAction />
</CenterPosition>
<CenterPosition> <CenterPosition>
<MiddlePauseAction /> <MiddlePauseAction />
</CenterPosition> </CenterPosition>

View File

@ -0,0 +1,22 @@
import { Icon, Icons } from "@/components/Icon";
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { useMisc } from "@/video/state/logic/misc";
import { useTranslation } from "react-i18next";
export function CastingTextAction() {
const { t } = useTranslation();
const descriptor = useVideoPlayerDescriptor();
const misc = useMisc(descriptor);
if (!misc.isCasting) return null;
return (
<div className="flex flex-col items-center justify-center gap-4">
<div className="rounded-full bg-denim-200 p-3 brightness-100 grayscale">
<Icon icon={Icons.CASTING} />
</div>
<p className="text-center text-gray-300">{t("casting.casting")}</p>
</div>
);
}

View File

@ -16,13 +16,17 @@ export function CastingInternal() {
useEffect(() => { useEffect(() => {
if (lastValue.current === isCasting) return; if (lastValue.current === isCasting) return;
if (!isCasting) return;
lastValue.current = isCasting; lastValue.current = isCasting;
if (!isCasting) return;
const provider = createCastingStateProvider(descriptor); const provider = createCastingStateProvider(descriptor);
setProvider(descriptor, provider); setProvider(descriptor, provider);
const { destroy } = provider.providerStart(); const { destroy } = provider.providerStart();
return () => { return () => {
try {
unsetStateProvider(descriptor, provider.getId()); unsetStateProvider(descriptor, provider.getId());
} catch {
// ignore errors from missing player state, we need to run destroy()!
}
destroy(); destroy();
}; };
}, [descriptor, isCasting]); }, [descriptor, isCasting]);

View File

@ -27,7 +27,11 @@ function VideoElement(props: Props) {
setProvider(descriptor, provider); setProvider(descriptor, provider);
const { destroy } = provider.providerStart(); const { destroy } = provider.providerStart();
return () => { return () => {
try {
unsetStateProvider(descriptor, provider.getId()); unsetStateProvider(descriptor, provider.getId());
} catch {
// ignore errors from missing player state, we need to run destroy()!
}
destroy(); destroy();
}; };
}, [descriptor, initalized, stateProviderId]); }, [descriptor, initalized, stateProviderId]);

View File

@ -18,9 +18,7 @@ import { VideoPlayerStateProvider } from "./providerTypes";
import { updateProgress } from "../logic/progress"; import { updateProgress } from "../logic/progress";
// TODO startAt when switching state providers // TODO startAt when switching state providers
// TODO cast -> uncast -> cast will break // TODO test HLS
// TODO chromecast button has incorrect hitbox and badly styled
// TODO casting text middle of screen
export function createCastingStateProvider( export function createCastingStateProvider(
descriptor: string descriptor: string
): VideoPlayerStateProvider { ): VideoPlayerStateProvider {
@ -112,8 +110,10 @@ export function createCastingStateProvider(
const movieMeta = new chrome.cast.media.MovieMediaMetadata(); const movieMeta = new chrome.cast.media.MovieMediaMetadata();
movieMeta.title = state.meta?.meta.meta.title ?? ""; movieMeta.title = state.meta?.meta.meta.title ?? "";
// TODO contentId? const mediaInfo = new chrome.cast.media.MediaInfo(
const mediaInfo = new chrome.cast.media.MediaInfo("hello", "video/mp4"); state.meta?.meta.meta.id ?? "hello",
"video/mp4"
);
(mediaInfo as any).contentUrl = source?.source; (mediaInfo as any).contentUrl = source?.source;
mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED; mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED;
mediaInfo.metadata = movieMeta; mediaInfo.metadata = movieMeta;
@ -167,17 +167,16 @@ export function createCastingStateProvider(
updateProgress(descriptor, state); updateProgress(descriptor, state);
break; break;
case "mediaInfo": case "mediaInfo":
if (e.value) {
state.progress.duration = e.value.duration; state.progress.duration = e.value.duration;
updateProgress(descriptor, state); updateProgress(descriptor, state);
}
break; break;
case "playerState": case "playerState":
state.mediaPlaying.isLoading = e.value === "BUFFERING"; state.mediaPlaying.isLoading = e.value === "BUFFERING";
updateMediaPlaying(descriptor, state); state.mediaPlaying.isPaused = e.value !== "PLAYING";
break; state.mediaPlaying.isPlaying = e.value === "PLAYING";
case "isPaused": if (e.value === "PLAYING") state.mediaPlaying.hasPlayedOnce = true;
state.mediaPlaying.isPaused = e.value;
state.mediaPlaying.isPlaying = !e.value;
if (!e.value) state.mediaPlaying.hasPlayedOnce = true;
updateMediaPlaying(descriptor, state); updateMediaPlaying(descriptor, state);
break; break;
case "isMuted": case "isMuted":
@ -188,6 +187,7 @@ export function createCastingStateProvider(
case "displayStatus": case "displayStatus":
case "canSeek": case "canSeek":
case "title": case "title":
case "isPaused":
break; break;
default: default:
console.log(e.type, e.field, e.value); console.log(e.type, e.field, e.value);
@ -229,6 +229,7 @@ export function createCastingStateProvider(
state.wrapperElement?.removeEventListener("mouseenter", isFocused); state.wrapperElement?.removeEventListener("mouseenter", isFocused);
state.wrapperElement?.removeEventListener("mouseleave", isFocused); state.wrapperElement?.removeEventListener("mouseleave", isFocused);
fscreen.removeEventListener("fullscreenchange", fullscreenchange); fscreen.removeEventListener("fullscreenchange", fullscreenchange);
ins?.endCurrentSession(true);
}, },
}; };
}, },

View File

@ -161,7 +161,7 @@ function NewDomainModal() {
</div> </div>
<div className="mt-16 mb-6 flex items-center justify-center"> <div className="mt-16 mb-6 flex items-center justify-center">
<Button icon={Icons.PLAY} onClick={() => setShow(false)}> <Button icon={Icons.PLAY} onClick={() => setShow(false)}>
Take me to the app {t("v3.leaveAnnouncement")}
</Button> </Button>
</div> </div>
</ModalCard> </ModalCard>