diff --git a/src/components/player/atoms/Airplay.tsx b/src/components/player/atoms/Airplay.tsx index a81e57cf..54a22919 100644 --- a/src/components/player/atoms/Airplay.tsx +++ b/src/components/player/atoms/Airplay.tsx @@ -6,10 +6,26 @@ import { isSafari } from "@/utils/detectFeatures"; export function Airplay() { const canAirplay = usePlayerStore((s) => s.interface.canAirplay); const display = usePlayerStore((s) => s.display); + const source = usePlayerStore((s) => s.source); + + // Check if source is supported for casting + // HLS is always supported (proxied if needed) + // MP4/File is only supported if it doesn't need headers (no proxy available) + const isCastable = (() => { + if (!source) return false; + if (source.type === "hls") return true; + if (source.type === "file") { + const hasHeaders = + Object.keys(source.headers || {}).length > 0 || + Object.keys(source.preferredHeaders || {}).length > 0; + return !hasHeaders; + } + return true; // Unknown types assumed castable + })(); // Show Airplay button on Safari browsers (which support AirPlay natively) // or when the webkit event has confirmed availability - if (!canAirplay && !isSafari) return null; + if ((!canAirplay && !isSafari) || !isCastable) return null; return ( s.interface.isCasting); + const source = usePlayerStore((s) => s.source); const launcherRef = useRef(null); + // Check if source is supported for casting + // HLS is always supported (proxied if needed) + // MP4/File is only supported if it doesn't need headers (no proxy available) + const isCastable = (() => { + if (!source) return false; + if (source.type === "hls") return true; + if (source.type === "file") { + const hasHeaders = + Object.keys(source.headers || {}).length > 0 || + Object.keys(source.preferredHeaders || {}).length > 0; + return !hasHeaders; + } + return true; // Unknown types assumed castable + })(); + useEffect(() => { const w = window as unknown as { cast?: typeof cast }; const castFramework = w.cast?.framework; @@ -72,7 +88,7 @@ export function Chromecast({ className }: ChromecastProps) { "google-cast-button", "cast-button-container", isCasting ? "casting" : "", - castHidden ? "hidden" : "", + castHidden || !isCastable ? "hidden" : "", ].join(" ")} >
diff --git a/src/components/player/display/base.ts b/src/components/player/display/base.ts index 88b75656..3593f22b 100644 --- a/src/components/player/display/base.ts +++ b/src/components/player/display/base.ts @@ -834,6 +834,8 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { if (source?.type === "hls") { if (hls) { hls.loadSource(proxiedUrl); + } else { + videoPlayer.src = proxiedUrl; } } else { videoPlayer.src = proxiedUrl;