diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json
index 9e923ee0..71fb1d78 100644
--- a/src/assets/locales/en.json
+++ b/src/assets/locales/en.json
@@ -94,6 +94,9 @@
"failure": "Error occurred"
}
},
+ "casting": {
+ "enabled": "Casting to device..."
+ },
"playbackError": {
"badge": "Playback error",
"title": "Failed to play video!",
diff --git a/src/components/player/atoms/CastingNotification.tsx b/src/components/player/atoms/CastingNotification.tsx
new file mode 100644
index 00000000..9c4e423b
--- /dev/null
+++ b/src/components/player/atoms/CastingNotification.tsx
@@ -0,0 +1,22 @@
+import { useTranslation } from "react-i18next";
+
+import { Icon, Icons } from "@/components/Icon";
+import { usePlayerStore } from "@/stores/player/store";
+
+export function CastingNotification() {
+ const { t } = useTranslation();
+ const isLoading = usePlayerStore((s) => s.mediaPlaying.isLoading);
+ const display = usePlayerStore((s) => s.display);
+ const isCasting = display?.getType() === "casting";
+
+ if (isLoading || !isCasting) return null;
+
+ return (
+
+
+
+
+
{t("player.casting.enabled")}
+
+ );
+}
diff --git a/src/components/player/atoms/index.ts b/src/components/player/atoms/index.ts
index 111703d5..3caf8154 100644
--- a/src/components/player/atoms/index.ts
+++ b/src/components/player/atoms/index.ts
@@ -15,3 +15,4 @@ export * from "./Airplay";
export * from "./VolumeChangedPopout";
export * from "./NextEpisodeButton";
export * from "./Chromecast";
+export * from "./CastingNotification";
diff --git a/src/components/player/base/SubtitleView.tsx b/src/components/player/base/SubtitleView.tsx
index c3f16a78..38520cac 100644
--- a/src/components/player/base/SubtitleView.tsx
+++ b/src/components/player/base/SubtitleView.tsx
@@ -107,8 +107,10 @@ export function SubtitleRenderer() {
export function SubtitleView(props: { controlsShown: boolean }) {
const caption = usePlayerStore((s) => s.caption.selected);
const captionAsTrack = usePlayerStore((s) => s.caption.asTrack);
+ const display = usePlayerStore((s) => s.display);
+ const isCasting = display?.getType() === "casting";
- if (captionAsTrack || !caption) return null;
+ if (captionAsTrack || !caption || isCasting) return null;
return (
{
destroyVideoElement();
fscreen.removeEventListener("fullscreenchange", fullscreenChange);
diff --git a/src/components/player/display/chromecast.ts b/src/components/player/display/chromecast.ts
index c8bfc3c7..401fc6f8 100644
--- a/src/components/player/display/chromecast.ts
+++ b/src/components/player/display/chromecast.ts
@@ -158,6 +158,9 @@ export function makeChromecastDisplayInterface(
return {
on,
off,
+ getType() {
+ return "casting";
+ },
destroy: () => {
stopListening();
destroyVideoElement();
diff --git a/src/components/player/display/displayInterface.ts b/src/components/player/display/displayInterface.ts
index 0b76fd79..b7a3e09d 100644
--- a/src/components/player/display/displayInterface.ts
+++ b/src/components/player/display/displayInterface.ts
@@ -46,6 +46,8 @@ export interface DisplayCaption {
url?: string;
}
+export type DisplayType = "web" | "casting";
+
export interface DisplayInterface extends Listener {
play(): void;
pause(): void;
@@ -66,4 +68,5 @@ export interface DisplayInterface extends Listener {
setPlaybackRate(rate: number): void;
setMeta(meta: DisplayMeta): void;
setCaption(caption: DisplayCaption | null): void;
+ getType(): DisplayType;
}
diff --git a/src/pages/parts/player/PlayerPart.tsx b/src/pages/parts/player/PlayerPart.tsx
index 14df6f31..48a25094 100644
--- a/src/pages/parts/player/PlayerPart.tsx
+++ b/src/pages/parts/player/PlayerPart.tsx
@@ -31,10 +31,15 @@ export function PlayerPart(props: PlayerPartProps) {
{status === playerStatus.PLAYING ? (
-
-
-
-
+ <>
+
+
+
+
+
+
+
+ >
) : null}