A local music player for Android with mood tagging, BPM analysis, and offline recommendations.
---
Coming soon
---
- Playback — Media3/ExoPlayer, notification controls, sleep timer, speed control
- Library — Scans device audio; browse by album, artist, folder, or genre
- Smart playlists — Auto-generated from BPM and mood tags (Workout, Chill, Focus, etc.)
- Recommendations — Made For You, Because You Played, Good Right Now (all offline)
- Tag affinity — Learns from likes, skips, and listen duration
- Equaliser — Mood-adaptive EQ via Android's Equalizer API
- Lyrics — Reads embedded lyrics from file metadata
- Themes — Spotify-style, Apple Music-style, Classic dark
---
| Layer | Library |
|---|---|
| Language | Kotlin |
| UI | Jetpack Compose + Material 3 |
| Architecture | MVVM — ViewModel → Repository → Room |
| Playback | Media3 (ExoPlayer + MediaSessionService) |
| Background sync | WorkManager (6-hour periodic rescan) |
| Real-time updates | ContentObserver (3 s debounce) |
| Database | Room with 7 migrations |
| Image loading | Coil 2 |
| Preferences | DataStore |
---
Prerequisites
- Android Studio Ladybug or newer
- Min SDK 26 (Android 8.0)
- A device or emulator with audio files
Build
git clone https://github.com/<propitiousX>/lune.git
cd lune
./gradlew assembleDebugRun tests
./gradlew test # JVM unit tests
./gradlew connectedAndroidTest # Instrumented tests (device/emulator required)Install
./gradlew installDebug---
LuneApp
└── MainActivity
└── MusicViewModel
└── MusicRepository
├── MediaStoreScanner — cursor + metadata
├── BpmAnalyzer — MediaCodec audio analysis
├── MoodClassifier — genre + BPM → mood/tags
└── RecommendationEngine — similarity scoring
PlaybackService (MediaSessionService, foreground)
└── EqManager
LibrarySyncWorker — WorkManager, every 6 h, battery-aware
MediaStoreObserver — ContentObserver, real-time file changes
---
| Permission | Reason |
|---|---|
READ\\\_MEDIA\\\_AUDIO (API 33+) |
Read music files |
READ\\\_EXTERNAL\\\_STORAGE (API ≤ 32) |
Read music files (legacy) |
POST\\\_NOTIFICATIONS |
Playback notification |
FOREGROUND\\\_SERVICE / FOREGROUND\\\_SERVICE\\\_MEDIA\\\_PLAYBACK |
Background playback |
WAKE\\\_LOCK |
Prevent CPU sleep during playback |
---
Room schema files are exported to app/schemas/. If you add a column or table, add a migration in MusicDatabase.kt — do not use fallbackToDestructiveMigration.
---
- BPM analysis is CPU-intensive; large libraries may take several minutes on first scan
- Genre classification depends on file tags — untagged files fall back to BPM-only mood
- Lyrics require embedded tags (ID3 USLT or equivalent); no online lookup
---
Open an issue before large changes. Run ./gradlew test before submitting a PR.
---
MIT License — Copyright (c) 2025