Skip to content

RobertDaleSmith/Untune

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

94 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Untune icon

Untune

A native music player for macOS, iOS, and Apple TV.
Imports your Apple Music library into a fast local SQLite database,
with AI-powered tagging, a voice assistant, and cross-device streaming.

Untune screenshot

Overview

Untune is a three-platform music player built around your local Apple Music library:

  • macOS Desktop β€” Full-featured player with 62k+ track support, AI tagging, visualizer, smart playlists, and a Claude-powered voice assistant
  • iOS Companion β€” Offline playback with synced playlists, CarPlay, and Siri integration
  • tvOS Streaming β€” Stream your library to Apple TV over your local network

All three apps share a common sync protocol: the desktop runs an HTTP server that mobile and TV clients discover via Bonjour and connect to with a 4-digit pairing code.

Tech Stack

Layer Technology
Desktop backend Tauri v2 + Rust (rodio, rusqlite, lofty, axum, symphonia)
Desktop frontend React 19 + TypeScript + Vite 6 + Tailwind CSS v4
Table rendering TanStack Table + Virtual (62k rows, virtualized)
State management Zustand (7 stores)
Database SQLite with WAL mode + FTS5 full-text search
iOS / tvOS SwiftUI + GRDB.swift 7 + AVQueuePlayer
AI Claude API (Haiku for tagging, assistant for chat)
Sync axum HTTP server + Bonjour/mDNS discovery

Features

Library Management

  • Full Apple Music import via JXA scripts (62k+ tracks, 47 metadata fields)
  • Filesystem scanning with parallel audio file parsing (lofty + rayon)
  • FTS5 full-text search across all metadata
  • iTunes-style column browser (genre / artist / album filtering)
  • Smart playlists with rule-based editors (field/operator/value)
  • Playlist folder hierarchy with drag-and-drop
  • Star ratings, play counts, last played tracking
  • MusicBrainz artwork search and replacement
  • M3U/M3U8 playlist import and export

Playback

  • Gapless playback with pre-buffering
  • Crossfade (0–12s configurable overlap with fade curves)
  • Shuffle with back-navigation history
  • Repeat modes: off, all, one
  • Sleep timer with gradual fade-out
  • Radio mode (auto-queue similar tracks)
  • AirPlay device switching
  • Real-time FFT visualizer (5 modes: bars, waveform, particles, geometry, digital)
  • Mini player mode (always-on-top, 350Γ—48px)

AI Features

  • AI Tagging β€” Batch-tag tracks with mood, energy, BPM, danceability, acousticness, and vibe tags via Claude Haiku
  • Voice Assistant β€” Claude-powered chat with 13 music tools (search, play, queue, create playlists, get stats)
  • Speech Input β€” Native macOS speech recognition for voice commands
  • Artist Bios β€” AI-generated biographies in artist detail views
  • Smart Radio β€” Auto-queue tracks similar to what's playing

macOS Integration

  • Now Playing widget with artwork
  • Media key support (play/pause, next, previous)
  • Dock menu (play/pause, next, previous)
  • Keyboard shortcuts (volume, seek, navigation, search)
  • Background artwork as app backdrop
  • Synced lyrics display (LRCLIB integration)
  • Deep link support (untune://add?url=...)

Sync & Streaming

  • Built-in HTTP sync server (port 8485)
  • Bonjour/mDNS service discovery on LAN
  • 4-digit pairing code authentication
  • Per-device playlist selection
  • Metadata, artwork, and audio file transfer
  • Bidirectional play stat syncing

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   macOS Desktop                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    IPC     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ React 19 +   │◄─────────►│ Rust Backend      β”‚  β”‚
β”‚  β”‚ TanStack     β”‚  invoke() β”‚ β”œβ”€ playback.rs     β”‚  β”‚
β”‚  β”‚ Virtual      β”‚  events   β”‚ β”œβ”€ db/             β”‚  β”‚
β”‚  β”‚ Zustand      β”‚           β”‚ β”œβ”€ import/         β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚ β”œβ”€ assistant/      β”‚  β”‚
β”‚                             β”‚ β”œβ”€ sync/ ──────┐   β”‚  β”‚
β”‚                             β”‚ └─ commands/   β”‚   β”‚  β”‚
β”‚                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”˜
                                               β”‚ HTTP :8485
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β”‚                β”‚                β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
                    β”‚   iOS App      β”‚  β”‚  tvOS App       β”‚     β”‚
                    β”‚ Download+Play  β”‚  β”‚  Stream Only    β”‚     β”‚
                    β”‚ Offline Cache  β”‚  β”‚  Metadata Cache β”‚     β”‚
                    β”‚ CarPlay, Siri  β”‚  β”‚  10-foot UI     β”‚     β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
                                                                β”‚
                                        Bonjour (_untune._tcp) β”€β”˜

Desktop Backend (Rust)

Directory Purpose
src-tauri/src/lib.rs Tauri setup, native menu, menu event dispatch
src-tauri/src/commands/ 16 IPC command modules (import, tracks, playback, playlists, artwork, ai_tags, assistant, sync, lyrics, speech, airplay, preferences, browse, bios, url_download)
src-tauri/src/db/ SQLite: schema + migrations, queries, inserts
src-tauri/src/import/ Multi-phase import pipeline (JXA β†’ scan β†’ match β†’ merge β†’ artwork β†’ AI tags)
src-tauri/src/playback.rs Audio engine: rodio + symphonia, crossfade, FFT, sleep timer
src-tauri/src/assistant/ Claude API client with streaming + 13 music tools
src-tauri/src/sync/ axum HTTP server, Bonjour advertisement, pairing, file serving
src-tauri/src/models/ Track (47 fields), Playlist, MergedTrack, JxaTrack

Desktop Frontend (React + TypeScript)

Directory Purpose
src/components/ 31 React components (TrackTable, PlaybackBar, Sidebar, Visualizer, AssistantPanel, etc.)
src/stores/ 7 Zustand stores (library, playback, navigation, theme, columnBrowser, activity, assistant)
src/lib/commands.ts Typed wrappers for all invoke() calls
src/lib/types.ts TypeScript interfaces matching Rust models

Database

SQLite with WAL mode at ~/Library/Application Support/com.untune.app/library.db.

  • tracks β€” ~50 columns including AI tag fields (mood, energy, vibe_tags, bpm, danceability, acousticness)
  • tracks_fts β€” FTS5 virtual table for full-text search
  • playlists β€” Hierarchical with parent_id for folder trees
  • playlist_tracks β€” Junction table with sort order
  • preferences β€” Key-value store for app settings
  • smart_playlists β€” Rule-based playlist definitions (JSON rules)
  • sync_devices β€” Paired mobile devices with tokens
  • sync_playlist_selections β€” Per-device playlist sync choices
  • sync_track_state β€” Per-device per-track sync progress

iOS Companion App

Native SwiftUI app (untune-ios/) for iOS 17+ with offline playback.

Bundle ID: com.untune.ios Build: xcodegen (project.yml) β†’ Xcode project Database: GRDB.swift 7 (mirrors desktop schema)

Features

  • Syncs selected playlists + tracks from desktop over LAN
  • Offline playback via AVQueuePlayer
  • Background audio with lock screen controls
  • CarPlay support (tabbed browsing)
  • Siri media intents ("Play [artist] in Untune")
  • Bonjour discovery + 4-digit pairing
  • Play stat upload back to desktop

Structure

untune-ios/Untune/
β”œβ”€β”€ App/            # UntuneApp, ContentView, SplashView
β”œβ”€β”€ Models/         # Track (39 fields), Playlist
β”œβ”€β”€ Database/       # GRDB schema, manager, records
β”œβ”€β”€ Playback/       # AVQueuePlayer, NowPlayingManager
β”œβ”€β”€ Networking/     # DesktopDiscovery, PairingManager, SyncClient
β”œβ”€β”€ Sync/           # SyncEngine (state machine)
β”œβ”€β”€ Siri/           # PlayMediaIntentHandler
β”œβ”€β”€ CarPlay/        # CarPlaySceneDelegate, CarPlayBrowser
β”œβ”€β”€ Views/          # Library, Playback, Settings, Common
└── Utilities/      # TimeFormatting, MockData, AccentColor

tvOS Streaming App

Native SwiftUI app (untune-tvos/) for tvOS 18+ with streaming playback.

Bundle ID: com.untune.tvos Build: xcodegen (project.yml) β†’ Xcode project Database: GRDB.swift 7 (metadata cache only)

Key Differences from iOS

  • Streaming-first β€” Audio streams via HTTP from desktop (no file downloads)
  • Metadata cache β€” Only syncs track/playlist metadata and artwork thumbnails
  • 10-foot UI β€” Grid layouts, large text, focus engine for Siri Remote
  • Minimal storage β€” Artwork in Caches directory, no audio files stored

Structure

untune-tvos/Untune/
β”œβ”€β”€ App/            # UntuneApp, ContentView
β”œβ”€β”€ Models/         # Track (fileExtension instead of localFilePath)
β”œβ”€β”€ Database/       # GRDB (cachesDirectory for tvOS sandbox)
β”œβ”€β”€ Playback/       # AVURLAsset + HTTP auth headers for streaming
β”œβ”€β”€ Networking/     # Discovery, Pairing, SyncClient, ArtworkLoader (actor)
β”œβ”€β”€ Sync/           # SyncEngine (metadata-only, no file downloads)
β”œβ”€β”€ Views/          # Library grids, NowPlaying, Pairing
└── Utilities/      # TimeFormatting, MockData, ArtworkCache

Prerequisites

  • Node.js 20+
  • pnpm 10+
  • Rust 1.77+
  • macOS (required for Tauri, Apple Music integration, and building iOS/tvOS)
  • xcodegen (for iOS/tvOS project generation)
  • Xcode 16+ (for iOS/tvOS builds)

Development

Desktop (macOS)

make install   # Install frontend dependencies
make dev       # Run app in development (Tauri + Vite HMR)
make build     # Build production app bundle
make check     # Type-check frontend (tsc) and backend (cargo check)
make clean     # Remove build artifacts

Or without Make:

pnpm install
pnpm tauri dev

Optional: PSF / PSF2 playback (custom builds only)

PlayStation Sound Format playback uses the Highly Experimental emulator core, which has no upstream license. Official releases ship without it β€” Untune is MIT-licensed and can't redistribute unlicensed code. You can opt in for a personal local build at your own discretion:

git submodule update --init src-tauri/vendor
pnpm tauri build --features psf       # or: cargo check --features psf

PS2 PSF additionally needs a Sony PS2 BIOS image at src-tauri/vendor/Highly_Experimental/Core/hebios.bin (generated by mkhebios from your own PS2 BIOS dump). Sony BIOS files cannot be distributed.

iOS

cd untune-ios
xcodegen generate
open Untune.xcodeproj
# Build and run from Xcode (iOS 17+ device or simulator)

tvOS

cd untune-tvos
xcodegen generate
open Untune.xcodeproj
# Build and run from Xcode (tvOS 18+ device or simulator)

Sync Setup

  1. Start the sync server from the desktop app (Settings β†’ Sync β†’ Start Server)
  2. On iOS/tvOS, go to Settings β†’ Pair with Desktop
  3. Select your desktop from the Bonjour discovery list
  4. Enter the 4-digit pairing code shown on the desktop
  5. Select playlists to sync (iOS) or start streaming (tvOS)

CI/CD

GitHub Actions workflow in .github/workflows/:

  • build.yml β€” One workflow handles everything:
    • Push to main / PRs: type-check, cargo check, full Tauri build for aarch64-apple-darwin + x86_64-apple-darwin, uploads DMG artifacts
    • Manual dispatch (Actions β†’ Build & Release β†’ Run workflow) with bump_version = patch/minor/major: bumps version across package.json, Cargo.toml, tauri.conf.json, publishes a tagged GitHub Release with both architectures and a checksums.txt
    • Signs with the Developer ID cert when APPLE_CERTIFICATE / APPLE_CERTIFICATE_PASSWORD / APPLE_SIGNING_IDENTITY secrets are present; otherwise produces an unsigned DMG that still works via right-click β†’ Open

Project Documentation

Document Description
docs/ROADMAP.md Feature roadmap with completion status
docs/IOS-SYNC-PLAN.md iOS companion app design and sync protocol
docs/TVOS-PLAN.md tvOS streaming app design
docs/SERVER-ARCHITECTURE.md Long-term vision for self-hosted server mode
docs/ITUNES_DATA.md Apple Music/iTunes metadata schema reference
CHANGELOG.md Development history by phase

License

MIT

About

Personal music player app to librate decades old libraries from iTunes.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Contributors