mirror of
https://github.com/movie-web/movie-web.git
synced 2025-01-12 12:09:10 +01:00
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:
parent
d6d318006b
commit
b886443ea7
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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"
|
||||||
>
|
>
|
||||||
|
@ -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..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
22
src/video/components/actions/CastingTextAction.tsx
Normal file
22
src/video/components/actions/CastingTextAction.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
@ -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]);
|
||||||
|
@ -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]);
|
||||||
|
@ -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);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user