A simple and usable Jellyfin client for Apple TV with seamless multi-audio track switching and advanced subtitle support.
![]() Folder exploration |
![]() Multi-audio track switching |
![]() Subtitle support |
![]() Up next overlay |
![]() Native Search |
![]() Help page |
Built from the ground up for Apple TV with a focus on seamless playback. Switch audio tracks mid-video without restarting playback, thanks to custom HLS manifest generation. Codec compatibility is handled automatically so you can focus on watching, not troubleshooting.
- Multi-Audio Switching — Change audio tracks mid-playback without restarting. Uses a custom Swift module to generate multivariant HLS manifests.
- Subtitle Support — External (.srt) and embedded tracks with native tvOS picker.
- Smart Codec Handling — Direct plays H.264/HEVC; auto-transcodes everything else.
- Native tvOS Search — SwiftUI-powered with proper focus navigation.
- Demo Mode — Try instantly with Jellyfin's demo server.
- Playlist Support — Browse and play from your Jellyfin playlists.
- Secure Storage — device Keychain (secure local storage).
- Continue Watching — Resume videos from last position.
- Jellyfin Server 10.8+ with transcoding enabled
- Node.js 18+ and npm
- Xcode 15+
- Apple TV or tvOS simulator
- react-native-tvos configured project
# Clone the repository
git clone https://github.com/keiver/tomotv.git
cd tomotv
# Install dependencies
npm install
# Configure environment (development only)
cp .env.example .env.local
# Edit .env.local with your Jellyfin server details
# Prebuild for tvOS
npm run prebuild:tv
# Run on tvOS simulator
npm run ios
# Or build for Apple TV device
npx expo run:ios- Quick Connect support
- Username/password authentication
![]() Quick Connect |
![]() Username/Password |
Tomo TV supports 480p, 540p, 720p, 1080p, and 4K transcoding quality presets. Configure via Settings → Video Quality.
- All networks: HTTP and HTTPS connections allowed via
NSAllowsArbitraryLoads - Remote servers: HTTPS strongly recommended; HTTP exposes credentials in plaintext
npm start # Start dev server
npm run ios # Build and run
npm test # Run tests
npm run lint # Lint and auto-fix
npm run prebuild:tv # Rebuild native projects (deletes ios/ folder)Native code: Always edit files in the native/ folder — the ios/ folder is regenerated by prebuild and any direct edits will be lost.
Screens live in app/ using Expo Router's file-based routing with native tvOS tabs. Global state is managed through singleton managers wrapped in React Contexts. Video playback follows a state machine (IDLE → FETCHING → CREATING_STREAM → READY → PLAYING) that handles codec detection, automatic transcoding fallback, and multi-audio track switching via a custom Swift HLS manifest generator in native/ios/.
- React Native TVOS — TV-optimized fork of React Native
- Expo Router 6.0 — File-based routing with native tabs
- react-native-video 6.19 — Native video playback (AVPlayer)
- React Native Reanimated 4.1 — GPU-accelerated animations
- TypeScript 5.9 — Strict type checking
- Jest 29.7 — Unit and integration tests
- expo-tvos-search — Native tvOS search UI using SwiftUI
I use Claude as a development tool for drafting code and documentation. Architecture and decisions are mine, blame me for any shady code.
Contributions are welcome! This is a real, production app used by real users.
- Fork the repository
- Create a feature branch (
git checkout -b feature/cool-feature) - Make your changes following the existing code patterns
- Add tests for new functionality
- Run
npm testto ensure all tests pass - Run
npm run lintto fix any linting issues - Commit with clear, descriptive messages
- Push to your fork and submit a PR
- TypeScript: Strict mode, no
anytypes without justification - Testing: Add tests for new features, maintain >50% coverage
- Error handling: Try-catch around async operations with structured logging
- React patterns: Proper cleanup (useEffect, unsubscribe functions)
- Comments: Only where logic isn't self-evident
- Performance: No scale animations on grid items; use border-only focus feedback
- Codec support: Only H.264 and HEVC direct play; all others require transcoding
- Platform: tvOS only (Android not supported for now)
- Network: HTTP allowed on all networks; HTTPS recommended for remote servers (HTTP exposes credentials)
- Server: Jellyfin only (not compatible with Plex, Emby, etc.)
MIT License - see LICENSE file for details.
- Jellyfin Team for the excellent open-source media server
- Expo Team for React Native TVOS support
- Blender Foundation for open movie test files (Sintel, Elephants Dream...)
- IETF for Matroska test files used in development
- Documentation: https://tomotv.app/
- Support: contact@keiver.dev
- Demo Server: Uses Jellyfin's official demo at demo.jellyfin.org
- expo-tvos-search: github.com/keiver/expo-tvos-search
Built with ❤️ for the Jellyfin community.








