mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-23 11:38:03 +00:00
refactor(casting): remove AirPlay references, keep extensible architecture
- Remove AirPlay from CastProtocol type union (Chromecast only for now) - Replace AirPlay TODOs with generic 'Future: Add X for other protocols' comments - Remove PROTOCOL_COLORS export, use hardcoded Chromecast color (#F9AB00) - Update all component headers to be protocol-agnostic - Keep switch statements extensible for future protocol additions - Maintain clean architecture for easy integration of new casting protocols Architecture remains flexible for future protocols (AirPlay, DLNA, etc.)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Unified Casting Player Modal
|
||||
* Full-screen player for both Chromecast and AirPlay
|
||||
* Protocol-agnostic full-screen player for all supported casting protocols
|
||||
*/
|
||||
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
@@ -35,7 +35,6 @@ import {
|
||||
shouldShowNextEpisodeCountdown,
|
||||
truncateTitle,
|
||||
} from "@/utils/casting/helpers";
|
||||
import { PROTOCOL_COLORS } from "@/utils/casting/types";
|
||||
|
||||
export default function CastingPlayerScreen() {
|
||||
const insets = useSafeAreaInsets();
|
||||
@@ -178,7 +177,7 @@ export default function CastingPlayerScreen() {
|
||||
);
|
||||
|
||||
const protocolColor = useMemo(
|
||||
() => (protocol ? PROTOCOL_COLORS[protocol] : "#666"),
|
||||
() => (protocol === "chromecast" ? "#F9AB00" : "#666"), // Google yellow
|
||||
[protocol],
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Unified Casting Mini Player
|
||||
* Works with both Chromecast and AirPlay
|
||||
* Works with all supported casting protocols
|
||||
*/
|
||||
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
getProtocolIcon,
|
||||
getProtocolName,
|
||||
} from "@/utils/casting/helpers";
|
||||
import { CASTING_CONSTANTS, PROTOCOL_COLORS } from "@/utils/casting/types";
|
||||
import { CASTING_CONSTANTS } from "@/utils/casting/types";
|
||||
|
||||
export const CastingMiniPlayer: React.FC = () => {
|
||||
const api = useAtomValue(apiAtom);
|
||||
@@ -47,7 +47,7 @@ export const CastingMiniPlayer: React.FC = () => {
|
||||
);
|
||||
|
||||
const progressPercent = duration > 0 ? (progress / duration) * 100 : 0;
|
||||
const protocolColor = PROTOCOL_COLORS[protocol];
|
||||
const protocolColor = protocol === "chromecast" ? "#F9AB00" : "#666"; // Google yellow
|
||||
|
||||
const handlePress = () => {
|
||||
router.push("/casting-player");
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
* Unified Casting Hook
|
||||
* Manages both Chromecast and AirPlay through a common interface
|
||||
* Protocol-agnostic casting interface - currently supports Chromecast
|
||||
* Architecture allows for future protocol integrations
|
||||
*/
|
||||
|
||||
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
|
||||
import { getPlaystateApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Platform } from "react-native";
|
||||
import {
|
||||
useCastDevice,
|
||||
useMediaStatus,
|
||||
@@ -18,7 +18,8 @@ import type { CastPlayerState, CastProtocol } from "@/utils/casting/types";
|
||||
import { DEFAULT_CAST_STATE } from "@/utils/casting/types";
|
||||
|
||||
/**
|
||||
* Unified hook for managing casting (Chromecast + AirPlay)
|
||||
* Unified hook for managing casting
|
||||
* Extensible architecture supporting multiple protocols
|
||||
*/
|
||||
export const useCasting = (item: BaseItemDto | null) => {
|
||||
const api = useAtomValue(apiAtom);
|
||||
@@ -39,21 +40,13 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
|
||||
// Detect which protocol is active
|
||||
const chromecastConnected = castDevice !== null;
|
||||
// TODO: AirPlay detection requires integration with video player's AVRoutePickerView
|
||||
// The @douglowder/expo-av-route-picker-view package doesn't expose route state
|
||||
// Options:
|
||||
// 1. Create native module to detect AVAudioSession.sharedInstance().currentRoute
|
||||
// 2. Use AVPlayer's isExternalPlaybackActive property
|
||||
// 3. Listen to AVPlayerItemDidPlayToEndTimeNotification for AirPlay events
|
||||
const airplayConnected = false;
|
||||
// Future: Add detection for other protocols here
|
||||
|
||||
const activeProtocol: CastProtocol | null = chromecastConnected
|
||||
? "chromecast"
|
||||
: airplayConnected
|
||||
? "airplay"
|
||||
: null;
|
||||
: null;
|
||||
|
||||
const isConnected = chromecastConnected || airplayConnected;
|
||||
const isConnected = chromecastConnected;
|
||||
|
||||
// Update current device
|
||||
useEffect(() => {
|
||||
@@ -68,17 +61,6 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
protocol: "chromecast",
|
||||
},
|
||||
}));
|
||||
} else if (airplayConnected) {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isConnected: true,
|
||||
protocol: "airplay",
|
||||
currentDevice: {
|
||||
id: "airplay-device",
|
||||
name: "AirPlay Device", // TODO: Get real device name
|
||||
protocol: "airplay",
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
@@ -87,7 +69,8 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
currentDevice: null,
|
||||
}));
|
||||
}
|
||||
}, [chromecastConnected, airplayConnected, castDevice]);
|
||||
// Future: Add device detection for other protocols
|
||||
}, [chromecastConnected, castDevice]);
|
||||
|
||||
// Chromecast: Update playback state
|
||||
useEffect(() => {
|
||||
@@ -146,14 +129,14 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
if (activeProtocol === "chromecast") {
|
||||
await client?.play();
|
||||
}
|
||||
// TODO: AirPlay play control
|
||||
// Future: Add play control for other protocols
|
||||
}, [client, activeProtocol]);
|
||||
|
||||
const pause = useCallback(async () => {
|
||||
if (activeProtocol === "chromecast") {
|
||||
await client?.pause();
|
||||
}
|
||||
// TODO: AirPlay pause control
|
||||
// Future: Add pause control for other protocols
|
||||
}, [client, activeProtocol]);
|
||||
|
||||
const togglePlayPause = useCallback(async () => {
|
||||
@@ -170,7 +153,7 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
if (activeProtocol === "chromecast") {
|
||||
await client?.seek({ position: positionMs / 1000 });
|
||||
}
|
||||
// TODO: AirPlay seek control
|
||||
// Future: Add seek control for other protocols
|
||||
},
|
||||
[client, activeProtocol],
|
||||
);
|
||||
@@ -196,7 +179,7 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
if (activeProtocol === "chromecast") {
|
||||
await client?.stop();
|
||||
}
|
||||
// TODO: AirPlay stop control
|
||||
// Future: Add stop control for other protocols
|
||||
|
||||
// Report stop to Jellyfin
|
||||
if (api && item?.Id && user?.Id) {
|
||||
@@ -229,7 +212,7 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
if (activeProtocol === "chromecast") {
|
||||
await client?.setStreamVolume(clampedVolume).catch(console.error);
|
||||
}
|
||||
// TODO: AirPlay volume control
|
||||
// Future: Add volume control for other protocols
|
||||
}, 300);
|
||||
},
|
||||
[client, activeProtocol],
|
||||
@@ -285,7 +268,7 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
|
||||
// Availability
|
||||
isChromecastAvailable: true, // Always available via react-native-google-cast
|
||||
isAirPlayAvailable: Platform.OS === "ios",
|
||||
// Future: Add availability checks for other protocols
|
||||
|
||||
// Raw clients (for advanced operations)
|
||||
remoteMediaClient: client,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Unified Casting Helper Functions
|
||||
* Common utilities for both Chromecast and AirPlay
|
||||
* Common utilities for casting protocols
|
||||
*/
|
||||
|
||||
import type { CastProtocol, ConnectionQuality } from "./types";
|
||||
@@ -110,8 +110,7 @@ export const getProtocolName = (protocol: CastProtocol): string => {
|
||||
switch (protocol) {
|
||||
case "chromecast":
|
||||
return "Chromecast";
|
||||
case "airplay":
|
||||
return "AirPlay";
|
||||
// Future: Add cases for other protocols
|
||||
}
|
||||
};
|
||||
|
||||
@@ -124,8 +123,7 @@ export const getProtocolIcon = (
|
||||
switch (protocol) {
|
||||
case "chromecast":
|
||||
return "tv";
|
||||
case "airplay":
|
||||
return "logo-apple";
|
||||
// Future: Add icons for other protocols
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/**
|
||||
* Unified Casting Types and Options
|
||||
* Abstracts Chromecast and AirPlay into a common interface
|
||||
* Protocol-agnostic casting interface - currently supports Chromecast
|
||||
* Architecture allows for future protocols (AirPlay, DLNA, etc.)
|
||||
*/
|
||||
|
||||
export type CastProtocol = "chromecast" | "airplay";
|
||||
export type CastProtocol = "chromecast";
|
||||
|
||||
export interface CastDevice {
|
||||
id: string;
|
||||
@@ -79,9 +80,3 @@ export const DEFAULT_CAST_STATE: CastPlayerState = {
|
||||
};
|
||||
|
||||
export type ConnectionQuality = "excellent" | "good" | "fair" | "poor";
|
||||
|
||||
// Protocol-specific colors for UI differentiation
|
||||
export const PROTOCOL_COLORS = {
|
||||
chromecast: "#e50914", // Red (Google Cast)
|
||||
airplay: "#007AFF", // Blue (Apple)
|
||||
} as const;
|
||||
|
||||
Reference in New Issue
Block a user