Psychotoxical a2f880da0d feat(device-sync): fixed cross-OS naming scheme + playlist folders
Replace the user-configurable filename template with a fixed scheme so
syncing the same library across Linux/Windows/macOS no longer re-downloads
files just because the template string differs by OS.

Track layout on the device:
  {AlbumArtist}/{Album}/{TrackNum:02d} - {Title}.{ext}
  Playlists/{PlaylistName}/{Index:02d} - {Artist} - {Title}.{ext}
  Playlists/{PlaylistName}/{PlaylistName}.m3u8

Playlist tracks go into a self-contained folder with a sibling-referencing
Extended M3U, instead of being scattered across the album tree with an
external .m3u8 — the stick stays tidy even for 50-artist playlists.

Rust (lib.rs):
- TrackSyncInfo: drop disc_number/year (not used in fixed schema), add
  album_artist, duration, playlist_name, playlist_index
- sanitize_path_component strengthens empty-result handling via new
  sanitize_or() which falls back to "Unknown Artist/Album/Title"
- build_track_path() dispatches on playlist context — playlist tracks
  get the "Playlists/{Name}/…" shape, album tracks the traditional tree
- albumArtist resolution: the server's albumArtist tag, falling back to
  the track artist (empty-string treated as missing)
- calculate_sync_payload: dedup key is now (source_id, track_id) instead
  of track_id alone, so a track appearing in both an album and a playlist
  ends up on the device in both locations; playlist context is embedded
  into the response JSON as _playlistName / _playlistIndex so the follow-
  up sync_batch_to_device call can route each track correctly
- write_playlist_m3u8: rewritten — writes into the playlist folder with
  sibling filenames instead of a top-level .m3u8 with ../relative paths
- New rename_device_files command: atomic renames (per-entry result,
  skip-if-exists, skip-if-source-missing) plus empty-dir cleanup. Used
  by the migration flow
- write_device_manifest: v2 format, drops filenameTemplate field
- Drop the `template` parameter from sync_track_to_device,
  compute_sync_paths, calculate_sync_payload, sync_batch_to_device

Frontend:
- DeviceSyncStore: drop filenameTemplate from state and persist
- DeviceSync.tsx: strip template editor UI (presets, token buttons, live
  preview); replace with a compact read-only schema info card
- trackToSyncInfo(track, url, playlistCtx?): optional playlist context
  parameter. Tracks coming back from calculate_sync_payload with embedded
  _playlistName/_playlistIndex fall through via the same parameter
- compute_sync_paths / write_playlist_m3u8 / delete paths now pass the
  playlist context per-source so status checks + deletions hit the right
  files (album tree vs playlist folder)
- Album-Artist fallback: frontend falls back to track artist when the
  server has no albumArtist tag (empty strings treated as missing) —
  "Unknown Artist" is only used as a last-resort placeholder
- New migration flow: "Reorganize existing files…" button opens a modal
  that reads the legacy filenameTemplate from the v1 manifest, computes
  per-track (old, new) rename pairs, detects collisions (two old files
  mapping onto one new path), and executes via rename_device_files.
  Playlist-only tracks are left for the next sync to re-download into
  the new playlist folder
- Small JS-side applyLegacyTemplate() helper: only used by the migration
  preview so we can diff old paths against the current files on disk
- CSS: device-sync-schema-section / -code / -hint, migrate-modal +
  summary + warning + result layout

i18n (en + de):
- Remove dead keys: filenameTemplate, templatePreview, templateHint,
  templatePresetStandard/MultiDisc/AltFolder, tokenSlashHint
- Add schemaLabel, schemaHint, migrateButton/Title/Tooltip/Loading/
  NothingToDo/NoTemplate/FilesToRename/Unchanged/Collisions/
  PreviewNote/Executing/Success/Failed/ShowErrors/Start

Other locales (fr/nl/zh/nb/ru/es) fall through to the English defaultValue
until translated in a follow-up pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 19:30:25 +02:00
2026-04-18 12:31:16 +02:00

Psysonic Logo

A modern, gorgeous, and blazing fast desktop client for Subsonic API compatible music servers (Navidrome, Gonic, etc.).

Latest Release License: GPL v3 Built with Tauri AUR AUR (bin) Discord

Warning

Psysonic is under heavy active development. Bugs and rough edges are to be expected. We reserve the right to change, remove, or rework existing features at any time without prior notice.


Join Discord

Have questions, ideas, or just want to hang out? Come chat in our Discord server!


Psysonic is a beautiful desktop music player built completely from the ground up for the modern era. Utilizing Tauri v2 and React, it offers a native-feeling, lightweight, and incredibly fast experience with a stunning UI inspired by the Catppuccin and Nord aesthetics.

Designed specifically for users hosting their own music via Navidrome or other Subsonic API servers, Psysonic aims to be the best way to interact with your personal library.

Psysonic Screenshot

Features

  • 🎨 Wide Theme Selection: Dozens of themes across 8 groups — Open Source Classics (Catppuccin, Nord, Gruvbox, Nightfox, Dracula), Operating Systems, Games, Movies, Series, Social Media, and Psysonic originals. Glassmorphism effects, micro-animations, and a time-based Theme Scheduler for automatic day/night switching.
  • Native Performance: Built with Rust & Tauri — native audio engine (rodio), minimal RAM usage, no Electron overhead.
  • 🎵 Last.fm Integration: Scrobbling, Now Playing, love/unlove, Similar Artists, and top stats — no Navidrome config needed.
  • 🎤 Synchronized Lyrics: Auto-scrolling synced lyrics with click-to-seek in the sidebar and fullscreen player, powered by LRCLIB and your Navidrome server.
  • 📻 Radio & Infinite Queue: Smart Radio sessions from any song or artist, built-in Internet Radio (ICY/HLS), and an Infinite Queue that silently refills when the queue runs out.
  • 🎛️ Advanced Audio: 10-band graphic EQ with custom presets, AutoEQ headphone correction, Replay Gain, gapless playback, and crossfade.
  • 〰️ 10 Seekbar Styles: Waveform, Bar, Thick Bar, Segmented, Line+Dot, Neon, Pulse Wave, Particle Trail, Liquid Fill, and Retro Tape.
  • 🖥️ Fullscreen Player: Album art, animated synced lyrics overlay, and artist image in a dedicated fullscreen view.
  • 📋 Playlists & Library: Full playlist management with drag-and-drop reorder and smart suggestions. Genre browsing, Random Mix, Advanced Search, ratings (15 stars), and multi-select actions.
  • 💾 Device Sync: Export your library to a USB drive or portable device using a configurable filename template.
  • 🖥️ CLI Control: Control playback, switch servers, manage the queue, and more directly from the command line.
  • ⌨️ Customization: Configurable keybindings, UI fonts, global zoom slider, system tray, backup & restore, and in-app auto-update.
  • 🌍 8 Languages: English, German, French, Dutch, Spanish, Chinese, Norwegian, Russian.
  • 🖥️ Cross-Platform: Windows, macOS, and Linux (Arch AUR, .deb, .rpm).

🗺️ Roadmap

📋 Planned

  • Theme contrast & legibility audit — systematic review of text/background contrast ratios across all themes
  • Accessibility (a11y) — keyboard navigation, screen reader support, ARIA labels
  • More languages

📥 Installation

Navigate to the Releases page and download the installer for your operating system.

🐧 Linux

Quick Install (Recommended):

curl -fsSL https://raw.githubusercontent.com/Psychotoxical/psysonic/main/scripts/install.sh | sudo bash

Manual Installation:

  • Ubuntu / Debian: .deb from GitHub Releases
  • Fedora / RHEL: .rpm from GitHub Releases

🍎 macOS

  • macOS: .dmg (Universal or Apple Silicon)

Warning

Gatekeeper Note: Since the app is released without an Apple Developer certificate, macOS will block it by default. To bypass this, run the following command in the Terminal after moving the app to the Applications folder:

xattr -cr /Applications/Psysonic.app

🪟 Windows

  • Windows: .exe (NSIS installer)

Warning

SmartScreen Note: Windows SmartScreen might show a warning because the installer isn't signed with an expensive developer certificate. Click on "More info" and then "Run anyway".

📦 Installation (Arch Linux / AUR)

Psysonic is available in the AUR in two versions. Choose the one that best fits your needs:

Package Type Description
psysonic Source Builds from source using your system's native WebKitGTK (no bundled libs, no EGL/Mesa compatibility issues).
psysonic-bin Binary Pre-compiled version for faster installation.

Tip

The AUR binary package is kindly provided and maintained by kilyabin.

🚀 Getting Started

  1. Download and install Psysonic.
  2. Open the app and enter your Subsonic/Navidrome server details (URL, Username, Password).
  3. If applicable, you can provide both an external URL and a local LAN IP. Psysonic allows you to quickly toggle between them in the Settings.
  4. Enjoy your music!

🛠️ Development

If you want to build Psysonic from source or contribute to the project:

Prerequisites

  • Node.js (v18+)
  • Rust (v1.75+)
  • cmake — required to compile the bundled libopus (Opus audio support). Install it before running cargo build or npm run tauri:build:
    • Linux: sudo apt install cmake / sudo pacman -S cmake
    • macOS: brew install cmake
    • Windows: cmake.org/download or winget install cmake
  • OS-specific build dependencies for Tauri (see the Tauri prerequisites guide).

Setup

# Clone the repository
git clone https://github.com/Psychotoxical/psysonic.git
cd psysonic

# Install node dependencies
npm install

# Run in development mode
npm run tauri:dev

# Build for production
npm run tauri:build

🤝 Contributing

Contributions are completely welcome! Whether it is translating the app into a new language, fixing a bug, or proposing a new feature.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

📄 License

Distributed under the GNU General Public License v3.0. See LICENSE for more information.

This means: you are free to use, study, and modify Psysonic. If you distribute a modified version, you must release it under the same GPL v3 license and keep the original copyright notice intact. You may not incorporate this code into proprietary software.

🔒 Privacy

Psysonic contains no telemetry or analytics. All third-party integrations (Last.fm, LRCLIB, Discord) are opt-in. See PRIVACY.md for full details.

Languages
TypeScript 69.9%
Rust 24.9%
CSS 4.3%
JavaScript 0.5%
Shell 0.3%