Files
streamyfin/CLAUDE.md
Uruk 12047cbe12 fix: correct dependency arrays and add null checks
Fixes missing dependencies in useMemo and useCallback hooks to prevent stale closures and potential bugs.

Adds null/undefined guards before navigation in music components to prevent crashes when attempting to navigate with missing IDs.

Corrects query key from "company" to "genre" in genre page to ensure proper cache invalidation.

Updates Jellyseerr references to Seerr throughout documentation and error messages for consistency.

Improves type safety by adding error rejection handling in SeerrApi and memoizing components to optimize re-renders.
2026-01-14 10:24:57 +01:00

4.6 KiB

CLAUDE.md

@.claude/learned-facts.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Streamyfin is a cross-platform Jellyfin video streaming client built with Expo (React Native). It supports mobile (iOS/Android) and TV platforms, with features including offline downloads, Chromecast support, and Seerr integration.

Development Commands

CRITICAL: Always use bun for package management. Never use npm, yarn, or npx.

# Setup
bun i && bun run submodule-reload

# Development builds
bun run prebuild              # Mobile prebuild
bun run ios                   # Run iOS
bun run android               # Run Android

# TV builds (suffix with :tv)
bun run prebuild:tv
bun run ios:tv
bun run android:tv

# Code quality
bun run typecheck             # TypeScript check
bun run check                 # BiomeJS check
bun run lint                  # BiomeJS lint + fix
bun run format                # BiomeJS format
bun run test                  # Run all checks (typecheck, lint, format, doctor)

# iOS-specific
bun run ios:install-metal-toolchain  # Fix "missing Metal Toolchain" build errors

Tech Stack

  • Runtime: Bun
  • Framework: React Native (Expo SDK 54)
  • Language: TypeScript (strict mode)
  • State Management: Jotai (global state atoms) + React Query (server state)
  • API: Jellyfin SDK (@jellyfin/sdk)
  • Navigation: Expo Router (file-based)
  • Linting/Formatting: BiomeJS
  • Storage: react-native-mmkv

Architecture

File Structure

  • app/ - Expo Router screens with file-based routing
  • components/ - Reusable UI components
  • providers/ - React Context providers
  • hooks/ - Custom React hooks
  • utils/ - Utilities including Jotai atoms
  • modules/ - Native modules (vlc-player, mpv-player, background-downloader)
  • translations/ - i18n translation files

Key Patterns

State Management:

  • Global state uses Jotai atoms in utils/atoms/
  • settingsAtom in utils/atoms/settings.ts for app settings
  • apiAtom and userAtom in providers/JellyfinProvider.tsx for auth state
  • Server state uses React Query with @tanstack/react-query

Jellyfin API Access:

  • Use apiAtom from JellyfinProvider for authenticated API calls
  • Access user via userAtom
  • Use Jellyfin SDK utilities from @jellyfin/sdk/lib/utils/api

Navigation:

  • File-based routing in app/ directory
  • Tab navigation: (home), (search), (favorites), (libraries), (watchlists)
  • Shared routes use parenthesized groups like (home,libraries,search,favorites,watchlists)
  • IMPORTANT: Always use useAppRouter from @/hooks/useAppRouter instead of useRouter from expo-router. This custom hook automatically handles offline mode state preservation across navigation:
    // ✅ Correct
    import useRouter from "@/hooks/useAppRouter";
    const router = useRouter();
    
    // ❌ Never use this
    import { useRouter } from "expo-router";
    import { router } from "expo-router";
    

Offline Mode:

  • Use OfflineModeProvider from @/providers/OfflineModeProvider to wrap pages that support offline content
  • Use useOfflineMode() hook to check if current context is offline
  • The useAppRouter hook automatically injects offline=true param when navigating within an offline context

Providers (wrapping order in app/_layout.tsx):

  1. JotaiProvider
  2. QueryClientProvider
  3. JellyfinProvider (auth, API)
  4. NetworkStatusProvider
  5. PlaySettingsProvider
  6. WebSocketProvider
  7. DownloadProvider
  8. MusicPlayerProvider

Native Modules

Located in modules/:

  • vlc-player - VLC video player integration
  • mpv-player - MPV video player integration (iOS)
  • background-downloader - Background download functionality
  • sf-player - Swift player module

Path Aliases

Use @/ prefix for imports (configured in tsconfig.json):

import { useSettings } from "@/utils/atoms/settings";
import { apiAtom } from "@/providers/JellyfinProvider";

Coding Standards

  • Use TypeScript for all files (no .js)
  • Use functional React components with hooks
  • Use Jotai atoms for global state, React Query for server state
  • Follow BiomeJS formatting rules (2-space indent, semicolons, LF line endings)
  • Handle both mobile and TV navigation patterns
  • Use existing atoms, hooks, and utilities before creating new ones
  • Use Conventional Commits: feat(scope):, fix(scope):, chore(scope):

Platform Considerations

  • TV version uses :tv suffix for scripts
  • Platform checks: Platform.isTV, Platform.OS === "android" or "ios"
  • Some features disabled on TV (e.g., notifications, Chromecast)