oriaflow-labs/jellytunes

Take your Jellyfin music offline on MP3 players and storage devices

TypeScript

35

734 commits

updated Sep 29, 2026

See the code

README

JellyTunes

JellyTunes

Take your Jellyfin music offline on MP3 players and storage devices.

Latest Release   License: GPL v3

Support on Ko-fi


JellyTunes is a desktop app for Jellyfin users who want their music offline. Browse the artists, album artists, albums, playlists and genres on your server, pick a destination such as an MP3 player, a USB drive, an SD card or any local folder, and hit sync. JellyTunes downloads the tracks, converts formats when needed, embeds lyrics and cover art, and mirrors your server's folder structure at the destination.

Key Features

  • Browse your full library — artists, album artists, albums, playlists, and genres pulled directly from your Jellyfin server
  • Sync anywhere — USB drives, SD cards, and local folders all work as destinations
  • Selective sync — only downloads what's new or changed; skips tracks already at the destination
  • Out-of-sync detection — tracks that changed on the server since the last sync are automatically flagged for update
  • Sync preview — a three-column breakdown of exactly what will be added, updated, or removed — with per-category track count, size, and duration — before you commit to a sync
  • FLAC to MP3 conversion — built-in FFmpeg support with configurable bitrate (128k / 192k / 320k); settings saved per device
  • Lyrics sync — download .lrc sidecar files or embed lyrics directly into tracks (supports Jellyfin 10.9+ JSON lyrics); mode is configurable per device
  • Cover art modes — embed cover art into each track or write companion cover.jpg files; chosen per device and persisted
  • ReplayGain tags — ReplayGain metadata from Jellyfin is embedded into synced tracks for consistent playback volume
  • Smart storage bar — visual capacity indicator with live size estimates; warns when your selection exceeds free space
  • Smart filesystem handling — auto-detects FAT32, exFAT, and NTFS; sanitizes filenames accordingly
  • Per-destination history — remembers what was synced to each device or folder so you can pick up where you left off
  • Cancel anytime — stop a sync mid-progress without corrupting what's already been written

Screenshots

Browse your Jellyfin library    Pick a destination device or folder

Browse your library  ·  Pick a destination device or folder

Review the sync preview before syncing    Sync in progress with phase-aware progress

Review what will change  ·  Sync with live, phase-aware progress

Installation

Get it from the Snap Store

Linux  ·  installs in one command, updates arrive on their own


Prefer a direct download? Every platform is built on each release — grab yours from the latest release:

PlatformFileNotes
macOS.dmgApple silicon and Intel
Windows.exeInstaller
Linux.debDebian and Ubuntu
Linux.AppImageAppImage (legacy) — see Linux installation and migration

Open the installer and follow the prompts. FFmpeg is bundled with every package, so there is nothing else to install.

Linux: install from the Snap Store

sudo snap install jellytunes

The .snap is not attached to the release on purpose: a file downloaded from GitHub carries no store signature and snap install will reject it. Use the Snap Store button above, or the command.

Syncing to USB drives and SD cards needs the removable-media interface. Most systems connect it on install; if yours doesn't, JellyTunes says so at startup and gives you the command.

The .deb is equally supported and runs unconfined, which matters if your desktop has no working Secret portal and JellyTunes keeps asking you to log in. AppImage still runs but is deprecated. Both cases, and the migration path off AppImage, are covered in Linux installation and migration.

macOS: "App is damaged" or Gatekeeper warning

macOS blocks JellyTunes the first time you open it. What it says depends on your Mac:

Your MacWhat you see
Apple silicon (M1 and later)"JellyTunes is damaged and can't be opened. You should move it to the Bin."
Intel"JellyTunes can't be opened because it is from an unidentified developer."

On Apple silicon, "damaged" does not mean the download is broken. It is the wording macOS uses for any quarantined app it cannot verify, and JellyTunes cannot be verified because it is not signed with an Apple Developer certificate. Mac OS builds have been confirmed to install and run on Apple silicon after the steps below.

Click Cancel, not Move to Bin, and then:

  1. Open the .dmg and drag JellyTunes into your Applications folder.
  2. Open Terminal and run:
    xattr -cr /Applications/JellyTunes.app
    
  3. Open JellyTunes normally.

That command clears the com.apple.quarantine flag your browser attaches to anything it downloads. You need it once per install, and again after each update.

On Intel Macs you can avoid Terminal: try to open the app, then go to System Settings → Privacy & Security and click "Open Anyway" next to the JellyTunes entry. Apple silicon usually offers no such button for the "damaged" error, so use the command above.

Signing the app so macOS stops asking requires a paid Apple Developer account, which JellyTunes does not have yet. Until then this step is unavoidable — it is not a bug. See issue #12 for the background.

Windows: "Windows protected your PC" (SmartScreen)

JellyTunes is not signed with a code-signing certificate, so Windows SmartScreen may show a blue "Windows protected your PC" warning the first time you run the installer. To proceed:

  1. Click "More info" on the warning dialog
  2. Click the "Run anyway" button that appears
  3. Continue through the installer as normal

This only happens on first run.

Prerequisites

  • A Jellyfin server reachable on your network
  • A USB drive, SD card, local folder, or any mounted storage device as destination

Development

Everything below is for contributors and developers who want to build JellyTunes from source.

Setup

git clone https://github.com/orainlabs/jellytunes.git
cd jellytunes
pnpm install
pnpm dev

This starts the Vite dev server and launches the Electron window.

Requirements: Node.js 18+ and pnpm

Commands

# Development
pnpm dev              # Start dev server + Electron
pnpm build            # Compile with electron-vite
pnpm typecheck        # TypeScript type checking

# Testing
pnpm test             # Unit tests (Vitest)
pnpm test:unit:watch  # Unit tests in watch mode
pnpm test:e2e         # E2E tests with Playwright (see docs/E2E_TESTING.md)

# Packaging
pnpm package          # Build + create installers

Architecture

Three Electron processes plus a standalone sync engine:

  • Main process (src/main/) — IPC handlers, USB/filesystem detection, sync orchestration
  • Preload (src/preload/) — typed IPC bridge between main and renderer
  • Renderer (src/renderer/) — React UI for library navigation, device selection, and sync progress
  • Sync module (src/sync/) — dependency-injected sync engine (API client, file ops, FFmpeg converter); fully unit-testable without hitting the network or filesystem

Contributing

See CONTRIBUTING.md for guidelines on reporting bugs, submitting changes, and code style.

License

This project is licensed under the GNU General Public License v3.0 — see the LICENSE file for details.

desktop-app
electron
flac-to-mp3
jellyfin
music
offline-music
open-source
sync
usb

oriaflow-labs/jellytunes

Take your Jellyfin music offline on MP3 players and storage devices

TypeScript

35

734 commits

updated Sep 29, 2026

See the code

README

JellyTunes

JellyTunes

Take your Jellyfin music offline on MP3 players and storage devices.

Latest Release   License: GPL v3

Support on Ko-fi


JellyTunes is a desktop app for Jellyfin users who want their music offline. Browse the artists, album artists, albums, playlists and genres on your server, pick a destination such as an MP3 player, a USB drive, an SD card or any local folder, and hit sync. JellyTunes downloads the tracks, converts formats when needed, embeds lyrics and cover art, and mirrors your server's folder structure at the destination.

Key Features

  • Browse your full library — artists, album artists, albums, playlists, and genres pulled directly from your Jellyfin server
  • Sync anywhere — USB drives, SD cards, and local folders all work as destinations
  • Selective sync — only downloads what's new or changed; skips tracks already at the destination
  • Out-of-sync detection — tracks that changed on the server since the last sync are automatically flagged for update
  • Sync preview — a three-column breakdown of exactly what will be added, updated, or removed — with per-category track count, size, and duration — before you commit to a sync
  • FLAC to MP3 conversion — built-in FFmpeg support with configurable bitrate (128k / 192k / 320k); settings saved per device
  • Lyrics sync — download .lrc sidecar files or embed lyrics directly into tracks (supports Jellyfin 10.9+ JSON lyrics); mode is configurable per device
  • Cover art modes — embed cover art into each track or write companion cover.jpg files; chosen per device and persisted
  • ReplayGain tags — ReplayGain metadata from Jellyfin is embedded into synced tracks for consistent playback volume
  • Smart storage bar — visual capacity indicator with live size estimates; warns when your selection exceeds free space
  • Smart filesystem handling — auto-detects FAT32, exFAT, and NTFS; sanitizes filenames accordingly
  • Per-destination history — remembers what was synced to each device or folder so you can pick up where you left off
  • Cancel anytime — stop a sync mid-progress without corrupting what's already been written

Screenshots

Browse your Jellyfin library    Pick a destination device or folder

Browse your library  ·  Pick a destination device or folder

Review the sync preview before syncing    Sync in progress with phase-aware progress

Review what will change  ·  Sync with live, phase-aware progress

Installation

Get it from the Snap Store

Linux  ·  installs in one command, updates arrive on their own


Prefer a direct download? Every platform is built on each release — grab yours from the latest release:

PlatformFileNotes
macOS.dmgApple silicon and Intel
Windows.exeInstaller
Linux.debDebian and Ubuntu
Linux.AppImageAppImage (legacy) — see Linux installation and migration

Open the installer and follow the prompts. FFmpeg is bundled with every package, so there is nothing else to install.

Linux: install from the Snap Store

sudo snap install jellytunes

The .snap is not attached to the release on purpose: a file downloaded from GitHub carries no store signature and snap install will reject it. Use the Snap Store button above, or the command.

Syncing to USB drives and SD cards needs the removable-media interface. Most systems connect it on install; if yours doesn't, JellyTunes says so at startup and gives you the command.

The .deb is equally supported and runs unconfined, which matters if your desktop has no working Secret portal and JellyTunes keeps asking you to log in. AppImage still runs but is deprecated. Both cases, and the migration path off AppImage, are covered in Linux installation and migration.

macOS: "App is damaged" or Gatekeeper warning

macOS blocks JellyTunes the first time you open it. What it says depends on your Mac:

Your MacWhat you see
Apple silicon (M1 and later)"JellyTunes is damaged and can't be opened. You should move it to the Bin."
Intel"JellyTunes can't be opened because it is from an unidentified developer."

On Apple silicon, "damaged" does not mean the download is broken. It is the wording macOS uses for any quarantined app it cannot verify, and JellyTunes cannot be verified because it is not signed with an Apple Developer certificate. Mac OS builds have been confirmed to install and run on Apple silicon after the steps below.

Click Cancel, not Move to Bin, and then:

  1. Open the .dmg and drag JellyTunes into your Applications folder.
  2. Open Terminal and run:
    xattr -cr /Applications/JellyTunes.app
    
  3. Open JellyTunes normally.

That command clears the com.apple.quarantine flag your browser attaches to anything it downloads. You need it once per install, and again after each update.

On Intel Macs you can avoid Terminal: try to open the app, then go to System Settings → Privacy & Security and click "Open Anyway" next to the JellyTunes entry. Apple silicon usually offers no such button for the "damaged" error, so use the command above.

Signing the app so macOS stops asking requires a paid Apple Developer account, which JellyTunes does not have yet. Until then this step is unavoidable — it is not a bug. See issue #12 for the background.

Windows: "Windows protected your PC" (SmartScreen)

JellyTunes is not signed with a code-signing certificate, so Windows SmartScreen may show a blue "Windows protected your PC" warning the first time you run the installer. To proceed:

  1. Click "More info" on the warning dialog
  2. Click the "Run anyway" button that appears
  3. Continue through the installer as normal

This only happens on first run.

Prerequisites

  • A Jellyfin server reachable on your network
  • A USB drive, SD card, local folder, or any mounted storage device as destination

Development

Everything below is for contributors and developers who want to build JellyTunes from source.

Setup

git clone https://github.com/orainlabs/jellytunes.git
cd jellytunes
pnpm install
pnpm dev

This starts the Vite dev server and launches the Electron window.

Requirements: Node.js 18+ and pnpm

Commands

# Development
pnpm dev              # Start dev server + Electron
pnpm build            # Compile with electron-vite
pnpm typecheck        # TypeScript type checking

# Testing
pnpm test             # Unit tests (Vitest)
pnpm test:unit:watch  # Unit tests in watch mode
pnpm test:e2e         # E2E tests with Playwright (see docs/E2E_TESTING.md)

# Packaging
pnpm package          # Build + create installers

Architecture

Three Electron processes plus a standalone sync engine:

  • Main process (src/main/) — IPC handlers, USB/filesystem detection, sync orchestration
  • Preload (src/preload/) — typed IPC bridge between main and renderer
  • Renderer (src/renderer/) — React UI for library navigation, device selection, and sync progress
  • Sync module (src/sync/) — dependency-injected sync engine (API client, file ops, FFmpeg converter); fully unit-testable without hitting the network or filesystem

Contributing

See CONTRIBUTING.md for guidelines on reporting bugs, submitting changes, and code style.

License

This project is licensed under the GNU General Public License v3.0 — see the LICENSE file for details.

desktop-app
electron
flac-to-mp3
jellyfin
music
offline-music
open-source
sync
usb

Languages

TypeScript

97.4%

JavaScript

2.1%