Skip to content

misc-de/emilia

Repository files navigation

Emilia

Adaptive music, podcast, streaming and audio-drama player for Linux Phosh smartphones (Librem 5, PinePhone & co.) – runs equally well on the desktop. Written in Rust

⚠️ AI-assisted project

App ID: de.cais.Emilia · License: GPL-3.0-or-later


Screenshots


Library by artist and albums

Internet radio & recordings

Podcasts

YouTube as a music source

10-band equalizer with cascade

Listening statistics

Preferences

Adaptive phone layout (portrait)

What Emilia can do

  • Adaptive interface – works in narrow portrait (phone) and on the desktop; the navigation collapses automatically on mobile.

  • Scan a music folder – recursive background scan, tags & covers via lofty. Audio files are only ever read, never modified.

  • Several views of the library:

    • File system – reliable navigation even with patchy tags (important for audio dramas). Additional music sources (a second local folder or a Nextcloud/WebDAV remote) appear here as their own tabs.
    • Artists – a single tap opens a subpage with the artist's albums (with covers) and, below them, the single tracks (guest/feature tracks and tracks without an album). An album opens its track list.
    • Albums – all albums with covers.
    • Concerts – mark and collect live/unplugged recordings; an import suggests likely candidates.
    • Favorites, Audiobooks, Statistics.
  • Cover & photo galleries – open an album's or artist's detail view to pick among several cover/photo candidates (swipe the carousel or tap the dots to jump straight to one), or upload your own image. Choosing an artist photo never changes the album covers.

  • Playback – play/pause, next/previous, shuffle, a whole-queue repeat toggle (at the end of the queue it starts over), a queue, and a bottom mini-player with a seek bar (scrub through long tracks).

  • Gapless & crossfade – seamless transitions for sequential local queues (albums, concerts, audiobooks); an optional, configurable crossfade overlaps the end of one track with the start of the next. Streams, podcasts, YouTube, Nextcloud and shuffle keep the normal end-of-track path.

  • Sleep timer – the header "zzz" button starts a countdown from a preset; the volume gently fades out over the final two minutes before playback stops.

  • Quick filter – a funnel button reveals an inline search bar that filters the list you're looking at (Files / Artists / Albums) live, separate from the global search dialog.

  • Lock screen & media keys – control via MPRIS (play/pause, next/previous, seek) including title/album display.

  • Playlists – create your own playlists, add tracks/albums/folders via the options, play, rename and remove individual tracks.

  • Lyrics & karaoke – lyrics are read from the file's tags, then the local cache, then looked up online at LRCLIB. A pulldown on the file-info page shows them; for time-synced lyrics a karaoke view highlights and scrolls the active line. Fetched lyrics are only cached in the database, never written back into the audio files.

  • Podcasts – subscribe to feeds by RSS address or search the iTunes directory; episodes are streamed directly, with show notes, chapter marks and resume.

  • Streaming / Internet radio – add a stream URL or search stations worldwide (Radio-Browser API). Live now-playing title from the ICY metadata, plus a timeshift recorder:

    • a rolling ring buffer (configurable up to 60 minutes) lets you record a song even after it has played – press record at the end of a song and the whole song is saved;
    • automatic split at song boundaries, online cover/metadata embedded into the saved file;
    • saved songs live in a dedicated Recordings section. From there you can edit a recording in a built-in waveform editor – mark a region, cut it out with the scissors, zoom (+/− or scroll) and pan, scrub a timeline and play from the playhead (Save re-encodes and overwrites the file) – or add a recording to your music library as a regular track.
  • Voice memos – record from the microphone with the player-bar record button; memos collect in their own Memo section with Recent and Category tabs (organise them into freely named categories). A memo can be trimmed in the same waveform editor as a recording (saved as Ogg/Opus).

  • YouTube – search for tracks and play them in-app, or add a track to your library. The section can be hidden in the navigation if you don't need it.

  • Nextcloud – connect a Nextcloud (login QR code or manual), then index its music into the library so the tracks behave 1:1 like local songs (Artists, Albums, queue, resume). Audio streams on demand; duration, covers and photos are cached locally for performance.

  • Device sync – share library/resume data between devices over the LAN with a QR-code pairing handshake.

  • Equalizer with cascade – 10-band EQ (equalizer-10bands), live during playback. Settings apply in the order Global → Artist → Album → Track (the most specific level wins), additionally per output device/headphones (PipeWire sink).

  • Fetch online metadata (optional) – from open sources:

    • album covers via MusicBrainz + Cover Art Archive
    • artist photos via Deezer (no key required)
    • track recognition via AcoustID/Chromaprint (needs fpcalc + a free AcoustID key) for files with patchy tags
    • extra image galleries via fanart.tv (optional key)

    Everything is stored only in the local database and the XDG cache – never in the audio files.


Installation

Flatpak (recommended)

Pre-built, GPG-signed bundle for x86_64 and aarch64 – ideal for the phone, no build tools needed. From the project repo (GitHub Pages):

flatpak remote-add --if-not-exists emilia https://misc-de.github.io/emilia/de.cais.Emilia.flatpakrepo
flatpak install emilia de.cais.Emilia
flatpak run de.cais.Emilia

Update later with flatpak update de.cais.Emilia. The signing key is already embedded in the .flatpakrepo file – nothing needs to be imported separately.

Prefer to compile it yourself? See Building from source at the bottom.


Getting started

  1. Start Emilia and open Settings (the gear) at the top.
  2. Pick the music folder – Emilia scans the library in the background.
  3. Browse and play via Artists / Albums / File system.
  4. Optional: under Search, enable "Fetch automatically" to fill in covers, artist photos and (with fpcalc + an AcoustID key) missing tracks.
  5. Equalizer: long-press a track/album/artist → Equalizer, or the global EQ in the settings.

Streaming & recordings

  • Open the Streaming section, tap + to add a stream URL or search for a station worldwide.
  • Tap a station to play; the player bar shows a red record button next to play/pause. Set the recording buffer under Settings → Cache & recordings (0 turns it off). Recorded songs appear under Recordings.
  • Long-press a recording for its detail page: Play, Add to library, Edit (open the waveform editor to trim it) or delete it.

Nextcloud

  • Settings → Library → Connect to Nextcloud: scan the login QR code (the camera starts immediately) or expand the manual entry, then set the music folder. On connect the cloud library is indexed in the background and shows up under Artists/Albums.

Online metadata (optional)

  • An AcoustID key (free, for fingerprint track recognition) and a fanart.tv key (for extra images) can be stored under Settings → Search. Without keys those phases are simply skipped.
  • Covers (MusicBrainz/Cover Art Archive) and artist photos (Deezer) work without a key.

Where data is stored

Content Path
Library & settings ~/.local/share/emilia/library.db
Cover cache ~/.cache/emilia/covers/
Artist photo cache ~/.cache/emilia/artists/
Remote (Nextcloud) cache ~/.local/share/emilia/cache/<source-id>/

All settings (music folder, API keys, window state …) live in the SQLite database.


Building from source (for developers)

Not needed for normal use – that's what the Flatpak is for. This section is for developers and anyone who wants to compile it themselves.

Requirements

  • Rust toolchain (edition 2021), easiest via rustup
  • GTK ≥ 4.14 and libadwaita ≥ 1.5 (incl. dev headers)
  • GStreamer 1.x (core + dev headers) plus the plugin packages base, good, bad, ugly and libav (for playbin3, the equalizer and common codecs)
  • PipeWire for audio output (present on Phosh / recent distros)
  • a C compiler + pkg-config (SQLite is bundled and built from source)
  • optional: fpcalc (Chromaprint) for fingerprint track recognition, and yt-dlp for the YouTube source

1. Install dependencies

Arch / Manjaro

sudo pacman -S --needed rustup base-devel pkgconf \
  gtk4 libadwaita \
  gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav \
  chromaprint yt-dlp        # optional: fpcalc + the YouTube source
rustup default stable

Debian / Ubuntu / Mobian

sudo apt install build-essential pkg-config curl \
  libgtk-4-dev libadwaita-1-dev \
  libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
  gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
  gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav \
  gstreamer1.0-pipewire \
  libchromaprint-tools yt-dlp   # optional: fpcalc + the YouTube source
# Rust via rustup if not already present:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Fedora

sudo dnf install cargo rust gcc pkgconf-pkg-config \
  gtk4-devel libadwaita-devel \
  gstreamer1-devel gstreamer1-plugins-base-devel \
  gstreamer1-plugins-good gstreamer1-plugins-bad-free gstreamer1-libav \
  chromaprint-tools yt-dlp     # optional: fpcalc + the YouTube source
# gstreamer1-plugins-ugly is in RPM Fusion

2. Build & run

git clone <repo-url> Emilia
cd Emilia

# During development:
cargo run

# Optimized release binary:
cargo build --release
./target/release/emilia

Note: when started from the project folder (cargo run) the icons in data/icons are found. For permanent use, install it instead (below).

3. Install (optional)

So Emilia shows up in the app grid and displays its icon on the lock screen, the Makefile installs the binary, .desktop file, app icon and AppStream metainfo to the right XDG locations:

# system-wide (needs root):
sudo make install

# or just for your user (good for the phone, no root):
make install PREFIX=$HOME/.local

Remove again with make uninstall (same PREFIX). make check validates the .desktop and metainfo with desktop-file-validate / appstreamcli.

Build the Flatpak yourself

If you prefer to build a bundle yourself (instead of the pre-built one above): a manifest is in de.cais.Emilia.yaml (GNOME runtime + rust-stable SDK). Build with flatpak-builder – the exact commands are in the header of the manifest.


Project layout

src/
  main.rs            App start (Adw::Application, app ID de.cais.Emilia)
  model.rs           Data models (Track, AlbumMeta, ArtistMeta, MemoItem, …)
  i18n.rs            Internationalization (gettext)
  ui/
    app.rs           Root component (init/update/view!), navigation, player bar
    app_init.rs      Post-view_output!() wiring split out of init()
    setup.rs         First-run setup assistant (standalone component)
    app_views.rs     Load/group folder/album/artist, subpages, ctx/cover helpers
    app_sort.rs      Per-category sorting of the library overviews
    app_filter.rs    Inline list filter (funnel button + live search bar)
    app_favorites.rs Favorites / audiobooks / concerts unified lists
    app_concert.rs   Concerts (detect & collect live recordings)
    app_gallery.rs   Cover/photo gallery carousel (dot navigation, upload)
    app_playback.rs  Playback, queue, resume (local & remote), running EQ
    app_queue.rs     Explicit user-queue dialog ("Add to queue")
    app_gapless.rs   Gapless + crossfade integration (sequential local queues)
    app_sleep.rs     Sleep timer (header "zzz" button, countdown, fade-out)
    app_lyrics.rs    Lyrics & karaoke (embedded → DB → LRCLIB, live highlight)
    app_playlist.rs  Playlists (list, subpage, dialogs)
    podcasts_page.rs Podcasts page component (feeds, episodes, detail dialogs)
    app_episode_playback.rs  Podcast-episode playback on the shared transport
    stream_page.rs   Internet-radio page component (stations, recordings)
    app_streaming.rs Streaming/timeshift transport (ICY, ring buffer, replay)
    app_rec_edit.rs  Recording/memo waveform editor (mark/cut, zoom/pan, overwrite)
    yt_page.rs       YouTube page component (search, lists, dialogs)
    app_yt_glue.rs   YouTube transport + yt-dlp/settings glue on App
    app_memo.rs      Voice-memo page (Recent/Category tabs, mic record button)
    cloud_page.rs    Nextcloud connect dialog (QR camera + manual)
    sync_page.rs     Device sync UI (QR pairing, optional webcam)
    sync_share_ui.rs Sync share flow (size confirm + receiver review)
    stats_page.rs    Listening statistics component
    app_eq.rs        Equalizer editor + property dialogs
    app_dialogs.rs   Action menu (long press), share, settings
    enrich.rs        Online enrichment worker (background)
    artist_row.rs    Artist card (with photo)
    album_row.rs     Album card (with cover)
    track_row.rs     Track row (relm4 factory)
    fs_row.rs        File-system row
    app_helpers.rs   Small shared App helpers
    widgets.rs       Shared UI helpers (cover frames, thumbnails)
  core/
    scanner.rs       Directory scan + lofty metadata → DB (background worker)
    db/              SQLite (rusqlite, bundled) + queries (split into submodules)
    player.rs        GStreamer wrapper (playbin3, equalizer-10bands, gapless/crossfade)
    waveform.rs      Recording/memo waveform decode + region cut/re-encode
    online.rs        Online enrichment (MusicBrainz/CAA/Deezer/AcoustID/fanart)
    lyrics.rs        LRC parsing + lyrics model (LRCLIB lookup)
    podcast.rs       Read podcast feeds (RSS), provide episodes
    streaming.rs     Station search (Radio-Browser API)
    recorder.rs      Timeshift ring buffer + ICY reader for recording
    mic.rs           Microphone capture for voice memos (Ogg/Opus)
    webdav.rs        Nextcloud/WebDAV: list, read tags, index, stream
    source.rs        Add local/WebDAV sources and secret-backed credentials
    secrets.rs       Secret Service bridge for app passwords
    sync/            LAN device sync (server, client, QR scanner)
    mpris.rs         MPRIS lock-screen / media-key control
    fingerprint.rs   Chromaprint (fpcalc) for track recognition
    cover.rs         Embedded & folder covers
    category.rs      EQ/property keys and cascade resolution
    output.rs        Audio outputs (PipeWire sinks) for EQ profiles
    concert.rs       Detect concert candidates
    artist.rs        "feat." splitting of artist credits
    youtube.rs       YouTube resolve/download/transcode (yt-dlp)
    net.rs           Shared download helpers (size-capped streaming)

License

GPL-3.0-or-later. Online metadata comes from open sources (MusicBrainz/Cover Art Archive: CC0; Deezer search API; AcoustID/Chromaprint; fanart.tv; Radio-Browser).

About

Emilia – Adaptive music, podcast, streaming and audio-drama player for Linux

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors