feat(device-sync): USB/SD card sync page (WIP)

Adds a new Device Sync page for transferring music from Navidrome to
USB drives or SD cards. Sidebar entry is hidden by default.

- Four new Tauri commands: sync_track_to_device, compute_sync_paths,
  list_device_dir_files, delete_device_file
- Filename template engine with cross-platform path sanitization
- 4-concurrent-worker download, live progress via device:sync:progress event
- Persistent source list (albums/playlists/artists) with checkbox deletion
- Expandable artist tree in browser panel (per-album selection)
- i18n: DE + EN complete; other locales have stub keys

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-04-14 00:02:13 +02:00
parent 58f99ae846
commit 17a5c92174
15 changed files with 1341 additions and 2 deletions
+32
View File
@@ -25,6 +25,7 @@ export const enTranslation = {
mostPlayed: 'Most Played',
radio: 'Internet Radio',
folderBrowser: 'Folder Browser',
deviceSync: 'Device Sync',
libraryScope: 'Library scope',
allLibraries: 'All libraries',
expandPlaylists: 'Expand playlists',
@@ -1023,4 +1024,35 @@ export const enTranslation = {
empty: 'Empty folder',
error: 'Failed to load',
},
deviceSync: {
title: 'Device Sync',
targetFolder: 'Target Folder',
noFolderChosen: 'No folder chosen',
chooseFolder: 'Choose…',
filenameTemplate: 'Filename Template',
templateHint: 'Variables: {artist}, {album}, {title}, {track_number}, {disc_number}, {year}',
onDevice: 'On Device',
addSources: 'Add…',
colName: 'Name',
colType: 'Type',
syncResult: '{{done}} transferred, {{skipped}} already up to date ({{total}} total)',
deleteFromDevice: 'Delete from device ({{count}})',
confirmDelete: 'Delete {{count}} item(s) from the device: {{names}}?',
deleteComplete: '{{count}} item(s) removed from device.',
selectedSources: 'Selected Sources',
noSourcesSelected: 'No sources selected. Click items in the browser to add them.',
clearAll: 'Clear all',
tabPlaylists: 'Playlists',
tabAlbums: 'Albums',
tabArtists: 'Artists',
searchPlaceholder: 'Search…',
syncButton: 'Sync to Device',
cancel: 'Cancel',
noTargetDir: 'Please choose a target folder first.',
noSources: 'Please select at least one source.',
noTracks: 'No tracks found in the selected sources.',
fetchError: 'Failed to fetch tracks from server.',
syncComplete: 'Sync complete.',
dismiss: 'Dismiss',
},
};