airplay button

Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
mrjvs 2023-10-19 14:16:10 +02:00
parent acd6541ba7
commit f6bbec8907
7 changed files with 42 additions and 0 deletions

View File

@ -0,0 +1,17 @@
import { Icons } from "@/components/Icon";
import { VideoPlayerButton } from "@/components/player/internals/Button";
import { usePlayerStore } from "@/stores/player/store";
export function Airplay() {
const canAirplay = usePlayerStore((s) => s.interface.canAirplay);
const display = usePlayerStore((s) => s.display);
if (!canAirplay) return null;
return (
<VideoPlayerButton
onClick={() => display?.startAirplay()}
icon={Icons.AIRPLAY}
/>
);
}

View File

@ -10,3 +10,4 @@ export * from "./Title";
export * from "./EpisodeTitle"; export * from "./EpisodeTitle";
export * from "./Settings"; export * from "./Settings";
export * from "./Episodes"; export * from "./Episodes";
export * from "./Airplay";

View File

@ -85,6 +85,14 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
emit("fullscreen", isFullscreen); emit("fullscreen", isFullscreen);
if (!isFullscreen) emit("needstrack", false); if (!isFullscreen) emit("needstrack", false);
}); });
videoElement.addEventListener(
"webkitplaybacktargetavailabilitychanged",
(e: any) => {
if (e.availability === "available") {
emit("canairplay", true);
}
}
);
} }
function unloadSource() { function unloadSource() {
@ -206,5 +214,11 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
} }
} }
}, },
startAirplay() {
const videoPlayer = videoElement as any;
if (videoPlayer && videoPlayer.webkitShowPlaybackTargetPicker) {
videoPlayer.webkitShowPlaybackTargetPicker();
}
},
}; };
} }

View File

@ -13,6 +13,7 @@ export type DisplayInterfaceEvents = {
qualities: SourceQuality[]; qualities: SourceQuality[];
changedquality: SourceQuality | null; changedquality: SourceQuality | null;
needstrack: boolean; needstrack: boolean;
canairplay: boolean;
}; };
export interface DisplayInterface extends Listener<DisplayInterfaceEvents> { export interface DisplayInterface extends Listener<DisplayInterfaceEvents> {
@ -26,4 +27,5 @@ export interface DisplayInterface extends Listener<DisplayInterfaceEvents> {
setVolume(vol: number): void; setVolume(vol: number): void;
setTime(t: number): void; setTime(t: number): void;
destroy(): void; destroy(): void;
startAirplay(): void;
} }

View File

@ -72,6 +72,7 @@ export function PlayerPart(props: PlayerPartProps) {
</Player.LeftSideControls> </Player.LeftSideControls>
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<Player.Episodes onChange={props.onMetaChange} /> <Player.Episodes onChange={props.onMetaChange} />
<Player.Airplay />
<Player.Settings /> <Player.Settings />
<Player.Fullscreen /> <Player.Fullscreen />
</div> </div>

View File

@ -80,6 +80,11 @@ export const createDisplaySlice: MakeSlice<DisplaySlice> = (set, get) => ({
s.caption.asTrack = needsTrack; s.caption.asTrack = needsTrack;
}); });
}); });
newDisplay.on("canairplay", (canAirplay) => {
set((s) => {
s.interface.canAirplay = canAirplay;
});
});
set((s) => { set((s) => {
s.display = newDisplay; s.display = newDisplay;

View File

@ -19,6 +19,7 @@ export interface InterfaceSlice {
hasOpenOverlay: boolean; hasOpenOverlay: boolean;
hovering: PlayerHoverState; hovering: PlayerHoverState;
lastHoveringState: PlayerHoverState; lastHoveringState: PlayerHoverState;
canAirplay: boolean;
volumeChangedWithKeybind: boolean; // has the volume recently been adjusted with the up/down arrows recently? volumeChangedWithKeybind: boolean; // has the volume recently been adjusted with the up/down arrows recently?
volumeChangedWithKeybindDebounce: NodeJS.Timeout | null; // debounce for the duration of the "volume changed thingamajig" volumeChangedWithKeybindDebounce: NodeJS.Timeout | null; // debounce for the duration of the "volume changed thingamajig"
@ -46,6 +47,7 @@ export const createInterfaceSlice: MakeSlice<InterfaceSlice> = (set, get) => ({
volumeChangedWithKeybind: false, volumeChangedWithKeybind: false,
volumeChangedWithKeybindDebounce: null, volumeChangedWithKeybindDebounce: null,
timeFormat: VideoPlayerTimeFormat.REGULAR, timeFormat: VideoPlayerTimeFormat.REGULAR,
canAirplay: false,
}, },
setLastVolume(state) { setLastVolume(state) {