mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-05-23 15:26:42 +01:00
fix: resolve 13 review issues across casting components
- casting-player: remove redundant self-navigation useEffect - casting-player: derive Type from metadata instead of hardcoding 'Movie' - casting-player: pass null to useTrickplay instead of empty BaseItemDto - casting-player: use != null for skip time labels (allow 0 to render) - Chromecast: case-insensitive m3u8 detection via regex - Chromecast: fix UUID hyphen indices to 4,6,8,10 for proper v4 format - CastingMiniPlayer: use SeriesPrimaryImageTag for series poster URL - ChromecastConnectionMenu: send rounded volume to castSession.setVolume - ChromecastConnectionMenu: use isMutedRef in onValueChange to avoid stale closure - ChromecastDeviceSheet: skip volume sync during active sliding - ChromecastDeviceSheet: move unmute logic from onValueChange to onSlidingStart - useCasting: detect playback start via isPlaying/playerState, not just progress>0 - useCasting: derive isChromecastAvailable from castState instead of hardcoding true - useTrickplay: accept BaseItemDto|null with null guards on Id access
This commit is contained in:
@@ -120,8 +120,13 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
const playStateApi = getPlaystateApi(api);
|
||||
|
||||
// Report playback start when media begins (only once per item)
|
||||
// Don't require progress > 0 — playback can legitimately start at position 0
|
||||
const currentState = stateRef.current;
|
||||
if (hasReportedStartRef.current !== item.Id && currentState.progress > 0) {
|
||||
const isPlaybackActive =
|
||||
currentState.isPlaying ||
|
||||
mediaStatus?.playerState === "playing" ||
|
||||
currentState.progress > 0;
|
||||
if (hasReportedStartRef.current !== item.Id && isPlaybackActive) {
|
||||
// Set synchronously before async call to prevent race condition duplicates
|
||||
hasReportedStartRef.current = item.Id || null;
|
||||
|
||||
@@ -366,8 +371,11 @@ export const useCasting = (item: BaseItemDto | null) => {
|
||||
duration: state.duration,
|
||||
volume: state.volume,
|
||||
|
||||
// Availability
|
||||
isChromecastAvailable: true, // Always available via react-native-google-cast
|
||||
// Availability - derived from actual cast state
|
||||
isChromecastAvailable:
|
||||
castState === CastState.CONNECTED ||
|
||||
castState === CastState.CONNECTING ||
|
||||
castState === CastState.NOT_CONNECTED,
|
||||
|
||||
// Raw clients (for advanced operations)
|
||||
remoteMediaClient: client,
|
||||
|
||||
@@ -17,20 +17,24 @@ interface TrickplayUrl {
|
||||
}
|
||||
|
||||
/** Hook to handle trickplay logic for a given item. */
|
||||
export const useTrickplay = (item: BaseItemDto) => {
|
||||
export const useTrickplay = (item: BaseItemDto | null) => {
|
||||
const { getDownloadedItemById } = useDownload();
|
||||
const [trickPlayUrl, setTrickPlayUrl] = useState<TrickplayUrl | null>(null);
|
||||
const lastCalculationTime = useRef(0);
|
||||
const throttleDelay = 200;
|
||||
const isOffline = useGlobalSearchParams().offline === "true";
|
||||
const trickplayInfo = useMemo(() => getTrickplayInfo(item), [item]);
|
||||
const trickplayInfo = useMemo(
|
||||
() => (item ? getTrickplayInfo(item) : null),
|
||||
[item],
|
||||
);
|
||||
|
||||
/** Generates the trickplay URL for the given item and sheet index.
|
||||
* We change between offline and online trickplay URLs depending on the state of the app. */
|
||||
const getTrickplayUrl = useCallback(
|
||||
(item: BaseItemDto, sheetIndex: number) => {
|
||||
if (!item.Id) return null;
|
||||
// If we are offline, we can use the downloaded item's trickplay data path
|
||||
const downloadedItem = getDownloadedItemById(item.Id!);
|
||||
const downloadedItem = getDownloadedItemById(item.Id);
|
||||
if (isOffline && downloadedItem?.trickPlayData?.path) {
|
||||
return `${downloadedItem.trickPlayData.path}${sheetIndex}.jpg`;
|
||||
}
|
||||
@@ -45,7 +49,7 @@ export const useTrickplay = (item: BaseItemDto) => {
|
||||
const now = Date.now();
|
||||
if (
|
||||
!trickplayInfo ||
|
||||
!item.Id ||
|
||||
!item?.Id ||
|
||||
now - lastCalculationTime.current < throttleDelay
|
||||
)
|
||||
return;
|
||||
@@ -62,7 +66,7 @@ export const useTrickplay = (item: BaseItemDto) => {
|
||||
|
||||
/** Prefetches all the trickplay images for the item, limiting concurrency to avoid I/O spikes. */
|
||||
const prefetchAllTrickplayImages = useCallback(async () => {
|
||||
if (!trickplayInfo || !item.Id) return;
|
||||
if (!trickplayInfo || !item?.Id) return;
|
||||
const maxConcurrent = 4;
|
||||
const total = trickplayInfo.totalImageSheets;
|
||||
const urls: string[] = [];
|
||||
|
||||
Reference in New Issue
Block a user