The songs module provides hymn/worship song browsing, searching, and audio playback. Songs are organized into downloadable song books, each containing multiple songs with lyrics, metadata, and optional audio.
Alkitab/src/main/java/yuku/alkitab/songs/SongListActivity.java— Main song list with search and filteringAlkitab/src/main/java/yuku/alkitab/songs/SongViewActivity.kt— Individual song viewerAlkitab/src/main/java/yuku/alkitab/songs/SongFragment.kt— WebView-based song rendering with JavaScriptAlkitab/src/main/java/yuku/alkitab/songs/SongBookUtil.kt— Song book download, installation, metadataAlkitab/src/main/java/yuku/alkitab/songs/SongFilter.java— Search/filter with regex and tokenized queriesAlkitab/src/main/java/yuku/alkitab/songs/SongInfo.kt— Lightweight song record (bookName, code, title, title_original)KpriModel/— Song data model (Song,Verse,Lyric,VerseKind)
KpriModel.Song is the core song entity with fields: title, title_original, authors_lyric, authors_music, tune, and a list of Verse objects. Each verse has a VerseKind (verse, chorus, bridge, etc.) and Lyric lines.
Important caveat: Song uses Parcelable serialization for persistent database storage. This is noted in the code as a bad design decision — changes to the Song class can break deserialization of stored data.
Songs are stored in SongRoomDatabase (separate Room database from the main AppDatabase — see Storage & Database for the rationale). Two tables: song_info (one row per song, with the Parcelable-marshalled Song BLOB in the data column) and song_book_info (one row per installed song book). The SongDb.java facade preserves the legacy public surface, routing through SongRoomDao. Song books are downloaded as serialized List<Song> objects via ObjectInputStream, optionally gzip-compressed. Data format version is currently 3.
The legacy SongDb SQLite file (managed by SongDbHelper) is kept around as a rollback safety net; a one-time SongDbDataMigration copies its rows into Room on first launch with the migrated code. See REM-32 for the full migration writeup.
SongBookUtil uses a SafeObjectInputStream with a class whitelist (java.util.*, java.lang.*, Song model classes only) and an instanceof check before casting to guard against deserialization gadgets; the response body is capped at 50MB; and the Response plus all derived streams are wrapped in try-with-resources.
SongFilter implements a sophisticated search with:
- Query tokenization (multi-term, quoted phrases via
QueryTokenizer) - Word-boundary and substring matching
- Regex pattern generation for highlighting
- Searches across title, title_original, and full lyric text
Songs can have audio attachments played via two controller implementations:
ExoplayerController.kt— ExoPlayer (media3) for MP3 with OkHttp streamingMidiController.kt— Android MediaPlayer for MIDI with local caching
Both extend MediaController.kt with a shared state machine (reset → preparing → playing/paused → complete/error). See Audio Playback for details.
SongBookUtil handles:
- Listing available song books from the server
- Downloading and installing new song books
- Managing user's default song book preference
- Song book metadata (name, title, copyright info)