Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | 5x 5x 5x 2126x 2126x 2126x 2126x 2126x 577x 327x 327x 494x 327x 319x 319x 176x 171x 4x 327x 327x 2126x 1786x 591x 1195x 5x 210x 210x 210x 210x 210x 210x | // SPDX-License-Identifier: GPL-3.0-only
// Copyright (C) 2026 Max Boksem. See NOTICE for additional terms under GPLv3 section 7.
import { useEffect, useState } from "react";
import { fetchOmdbData, fetchWhatsonData } from "@/lib/tauri";
import type { OmdbData, WhatsonData } from "@/lib/types";
import { useOmdbInfoState } from "@/hooks/useHasOmdbKey";
/** The movie or show to look up. */
export interface MediaDetailsRequest {
/** The channel OMDb's answer is saved for. */
id: string;
/** The name OMDb searches for. */
title: string;
kind: "movie" | "series";
}
export interface MediaDetails {
omdbData: OmdbData | null;
whatsonData: WhatsonData | null;
/** True until OMDb answers, or fails to. */
loading: boolean;
}
type Loaded = MediaDetailsRequest & Omit<MediaDetails, "loading">;
const NOTHING: MediaDetails = { omdbData: null, whatsonData: null, loading: false };
const LOADING: MediaDetails = { ...NOTHING, loading: true };
/**
* Loads OMDb's details for a movie or show, then Whatson's once OMDb gives an
* IMDb id. Pass null to load nothing.
*
* What it returns always belongs to the request it was given. A new request
* starts out loading and empty, never with the last one's details.
*/
export const useMediaDetails = (request: MediaDetailsRequest | null): MediaDetails => {
const id = request?.id;
const title = request?.title;
const kind = request?.kind;
const [loaded, setLoaded] = useState<Loaded | null>(null);
useEffect(() => {
if (id === undefined || title === undefined || kind === undefined) return;
let current = true;
const settle = (omdbData: OmdbData | null, whatsonData: WhatsonData | null) => {
if (current) setLoaded({ id, title, kind, omdbData, whatsonData });
};
fetchOmdbData(id, title, kind)
.then((omdbData) => {
settle(omdbData, null);
if (!current || !omdbData?.imdbId) return;
fetchWhatsonData(omdbData.imdbId, kind === "series" ? "show" : "movie")
.then((whatsonData) => settle(omdbData, whatsonData))
.catch(() => {});
})
.catch(() => settle(null, null));
return () => {
current = false;
};
}, [id, title, kind]);
if (!request) return NOTHING;
if (!loaded || loaded.id !== id || loaded.title !== title || loaded.kind !== kind)
return LOADING;
return { omdbData: loaded.omdbData, whatsonData: loaded.whatsonData, loading: false };
};
/**
* The details a movie or series sheet shows. The player hands over what it
* already loaded, with `prefetchedOmdbData` left undefined until OMDb has
* answered. Until then, or when opened from the channel list, the sheet
* loads its own.
*/
export const useSheetDetails = (
request: MediaDetailsRequest | null,
prefetchedOmdbData: OmdbData | null | undefined,
prefetchedWhatsonData: WhatsonData | null | undefined
) => {
const prefetched = prefetchedOmdbData !== undefined;
const own = useMediaDetails(prefetched ? null : request);
const omdbData = prefetched ? prefetchedOmdbData : own.omdbData;
const whatsonData = prefetched ? (prefetchedWhatsonData ?? null) : own.whatsonData;
const { hasOmdbKey, infoLoading } = useOmdbInfoState(omdbData, own.loading);
return { omdbData, whatsonData, omdbLoading: own.loading, hasOmdbKey, infoLoading };
};
|