feat(sync): auto-refresh on Jellyfin LibraryChanged events

Handle the server's LibraryChanged WebSocket message to invalidate
library-dependent React Query caches when items are added/updated/
removed, so newly added episodes/movies appear without a manual
refresh. Debounced to coalesce a scan's burst of events.

Add useRefreshLibraryOnFocus as a fallback that re-checks on screen
focus (throttled, online-only, skips first focus), wired into home
(mobile + TV) and the library pages.
This commit is contained in:
Fredrik Burmester
2026-05-30 13:05:43 +02:00
parent f9b71ef648
commit 2166bb3867
5 changed files with 122 additions and 1 deletions

View File

@@ -35,6 +35,7 @@ import { MediaListSection } from "@/components/medialists/MediaListSection";
import { Colors } from "@/constants/Colors";
import useRouter from "@/hooks/useAppRouter";
import { useNetworkStatus } from "@/hooks/useNetworkStatus";
import { useRefreshLibraryOnFocus } from "@/hooks/useRefreshLibraryOnFocus";
import { useInvalidatePlaybackProgressCache } from "@/hooks/useRevalidatePlaybackProgressCache";
import { useDownload } from "@/providers/DownloadProvider";
import { useIntroSheet } from "@/providers/IntroSheetProvider";
@@ -89,6 +90,10 @@ const HomeMobile = () => {
const [loadedSections, setLoadedSections] = useState<Set<string>>(new Set());
const { showIntro } = useIntroSheet();
// Fallback refresh for newly added content when returning to the home screen
// (primary path is the LibraryChanged WebSocket event).
useRefreshLibraryOnFocus();
// Show intro modal on first launch
useEffect(() => {
const hasShownIntro = storage.getBoolean("hasShownIntro");

View File

@@ -35,6 +35,7 @@ import { Loader } from "@/components/Loader";
import { useScaledTVTypography } from "@/constants/TVTypography";
import useRouter from "@/hooks/useAppRouter";
import { useNetworkStatus } from "@/hooks/useNetworkStatus";
import { useRefreshLibraryOnFocus } from "@/hooks/useRefreshLibraryOnFocus";
import { useInvalidatePlaybackProgressCache } from "@/hooks/useRevalidatePlaybackProgressCache";
import { useTVItemActionModal } from "@/hooks/useTVItemActionModal";
import {
@@ -86,6 +87,10 @@ export const Home = () => {
const _invalidateCache = useInvalidatePlaybackProgressCache();
const { showItemActions } = useTVItemActionModal();
// Fallback refresh for newly added content when returning to the home screen
// (primary path is the LibraryChanged WebSocket event).
useRefreshLibraryOnFocus();
// Dynamic backdrop state with debounce
const [focusedItem, setFocusedItem] = useState<BaseItemDto | null>(null);
const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);