Most of this README was written by Claude Code. It may contain errors or inaccuracies.
Guess who's back in the motherfuckin' house with a JellyFin app for your motherfuckin' phone? Yep, I'm back again with another entirely AI-generated app. There's a number of JellyFin music players out there, not least of which is FinAmp, which is great, but none of them really worked like I want them to so I had Claude write one for me. Very simple navigation, with Playlists or Artist -> Album -> Song and the ability to shuffle entire artists or albums (or playlists) which will loop forever. I mostly use this on the rare occasion I want to listen to music in the car or, my primary usage, listening to the audio from TV shows ripped to MP3 while I sleep. As such, it's not very feature-full.
This is designed to be used on a LineageOS phone. I don't have one yet as I'm currently (2025-09-30) waiting out the 7-day OEM unlock waiting period on my Moto G 5G (2024), but I'm dogfooding it on a Moto G Power (2025) in the meantime running full fat Tom Google Android.
- Jellyfin Integration: Connect to your Jellyfin server to stream your music library
- Offline Mode: Download albums, playlists, and entire artist catalogs for offline playback
- Smart Transcoding: Automatic audio transcoding support for optimal streaming quality
- Multi-Disc Album Support: Proper handling of multi-disc albums with correct track ordering
- Library Selection: Choose which music libraries to display from your Jellyfin server
- Playlist Support: Browse and play your Jellyfin playlists
- Material Design 3: Modern UI following Material Design 3 guidelines
- Persistent Mini Player: Always-visible mini player for quick playback controls
- Infinite Looping: Queues automatically loop back to the beginning when finished
- Server Unreachable Detection: Automatically switches to offline mode when server is unavailable
- Android Auto Support: Media controls and notifications for Android Auto integration
- Library-Organized Downloads: Downloads are organized into library-specific folders
- Framework: Flutter 3.35.4
- Language: Dart
- Audio Playback: just_audio package with support for streaming and local files
- Local Storage: SQLite database for tracking downloads, SharedPreferences for settings
- State Management: Provider pattern with ChangeNotifier
- HTTP Client: http package for Jellyfin API communication
- File Management: file_picker and permission_handler for Android storage access
- Platform: Android (with HTTP cleartext traffic support for local servers)
lib/
├── main.dart # App entry point with Provider setup
├── models/ # Data models
│ ├── jellyfin_album.dart
│ ├── jellyfin_artist.dart
│ ├── jellyfin_auth.dart
│ ├── jellyfin_library.dart
│ ├── jellyfin_playlist.dart
│ ├── jellyfin_server.dart
│ └── jellyfin_song.dart
├── pages/ # UI screens
│ ├── album_detail_page.dart
│ ├── artist_detail_page.dart
│ ├── download_settings_page.dart
│ ├── first_run_page.dart
│ ├── home_page.dart
│ ├── library_selection_page.dart
│ ├── playlist_detail_page.dart
│ ├── playlist_list_page.dart
│ └── server_config_page.dart
├── providers/ # State management
│ └── player_provider.dart
├── services/ # Business logic
│ ├── audio_player_service.dart # Audio playback management
│ ├── download_database.dart # SQLite database for downloads
│ ├── download_service.dart # File download management
│ ├── jellyfin_service.dart # Jellyfin API client
│ ├── offline_service.dart # Offline content access
│ └── settings_service.dart # App settings persistence
├── utils/ # Utilities
│ └── shuffle_helper.dart # Fisher-Yates shuffle algorithm
└── widgets/ # Reusable UI components
└── mini_player.dart # Persistent mini player widget
- Flutter SDK 3.35.4 or higher
- Android SDK with API level 33+ support
- A Jellyfin server (local or remote)
-
Clone the repository:
git clone <repository-url> cd yucheegung
-
Install dependencies:
flutter pub get
-
Run the app:
flutter run
The app requires the following Android permissions:
INTERNET- For streaming from Jellyfin serverREAD_EXTERNAL_STORAGE- For reading downloaded filesWRITE_EXTERNAL_STORAGE- For saving downloadsREAD_MEDIA_AUDIO- For Android 13+ media accessMANAGE_EXTERNAL_STORAGE- For managing download directoriesFOREGROUND_SERVICE- For background audio playbackFOREGROUND_SERVICE_MEDIA_PLAYBACK- For media playback serviceWAKE_LOCK- For keeping audio playing when screen is off
The app supports HTTP (cleartext) traffic to allow connections to local Jellyfin servers. This is configured in android/app/src/main/AndroidManifest.xml with:
<application android:usesCleartextTraffic="true">- Launch the app and enter your Jellyfin server URL (e.g.,
http://192.168.1.100:8096) - Log in with your Jellyfin credentials
- Select which music libraries you want to display
- Choose a download location for offline content
- The home page shows all artists from your selected libraries
- Tap an artist to view their albums
- Tap an album to view its tracks
- Access playlists from the "-- Playlists --" entry at the top of the artist list
- Tap any song to start playback immediately
- Use the shuffle button on album/playlist pages to shuffle and play
- The mini player appears at the bottom when music is playing
- Mini player shows: song info, progress bar, play/pause, and skip controls
- Navigate to an album, playlist, or artist
- Tap the download icon in the app bar
- Wait for the download to complete (progress shown in dialog)
- Downloaded content shows a green checkmark icon
- When server is unreachable, app automatically uses downloaded content
- When the Jellyfin server is unreachable, the app enters offline mode
- The app bar shows "YuCheeGung (Offline)"
- An offline indicator appears in the bottom bar
- Only downloaded artists, albums, and playlists are visible
- All playback uses local files instead of streaming
- Open the drawer menu (hamburger icon)
- Your selected libraries are listed under "LIBRARIES"
- Tap a library to switch to it
- The app remembers your selection across restarts
The app uses the just_audio package with audio_service for background playback:
- Streaming: Uses Jellyfin's universal endpoint with automatic transcoding to AAC
- Offline: Plays from local files stored in the download directory
- Queue Management: Maintains a playback queue with next/previous navigation
- Infinite Looping: Automatically loops back to the first song when the queue finishes
- Background Playback: Continues playing when app is in background or screen is off
- Media Controls: System media notifications and Android Auto integration
- Downloads are organized:
DownloadLocation/LibraryName/ArtistName/AlbumName/DiscNumber-TrackNumber - SongName.ext - Library-specific folders keep downloads from different libraries organized
- SQLite database tracks downloaded items and their file paths
- Supports downloading individual albums, entire playlists, or all albums by an artist
- Filenames are sanitized to remove invalid characters
- Multi-disc albums preserve disc numbers in filenames
The app communicates with Jellyfin using:
- Authentication: X-Emby-Authorization header with access token
- Libraries: Fetches music libraries and filters by user selection
- Artists: Retrieves artists with album counts
- Albums: Fetches albums with year, track count, and multi-disc info
- Songs: Gets track listings with disc/track numbers and runtime
- Playlists: Retrieves user playlists and their contents
- Streaming: Uses the universal endpoint for adaptive streaming with transcoding
- Artist lists are cached for 1 hour to reduce server requests
- Cache can be manually refreshed using the refresh button
- Offline mode bypasses cache and uses local database
Built with:
- Flutter - UI framework
- just_audio - Audio playback
- audio_service - Background playback and Android Auto
- sqflite - Local database
- provider - State management
- shared_preferences - Settings storage
- http & dio - HTTP clients
- file_picker - Directory selection
- permission_handler - Android permissions
Designed for use with Jellyfin media server.
This app is fully compatible with LineageOS and does not require Google Play Services. All dependencies use AOSP (Android Open Source Project) APIs and will work on de-Googled Android systems.