feat(TagEditor): show real-time progress when writing tags
Backend: - Emit 'library:tag_write_progress' events with current/total count - Progress updates as each file is written Frontend: - Listen for progress events during direct write mode - Save button shows "Writing X of Y..." dynamically - Cleanup listener on completion or error
This commit is contained in:
1 parent
f1ff7d4698
commit
65adf352b6
2 files changed
+29
-2
No files matched your search
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tauri::State;
|
use tauri::{Emitter, State};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::discogs::DiscogsClient;
|
use crate::discogs::DiscogsClient;
|
||||||
@@ -1616,6 +1616,7 @@ pub async fn library_update_album_metadata(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn library_write_album_metadata_to_files(
|
pub async fn library_write_album_metadata_to_files(
|
||||||
|
app: tauri::AppHandle,
|
||||||
request: LibraryAlbumMetadataUpdateRequest,
|
request: LibraryAlbumMetadataUpdateRequest,
|
||||||
state: State<'_, LibraryState>,
|
state: State<'_, LibraryState>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@@ -1663,7 +1664,16 @@ pub async fn library_write_album_metadata_to_files(
|
|||||||
by_file.entry(track.file_path.clone()).or_insert(track);
|
by_file.entry(track.file_path.clone()).or_insert(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let total = by_file.len();
|
||||||
|
let mut current = 0usize;
|
||||||
|
|
||||||
for (file_path, track) in by_file {
|
for (file_path, track) in by_file {
|
||||||
|
current += 1;
|
||||||
|
// Emit progress event
|
||||||
|
let _ = app.emit("library:tag_write_progress", serde_json::json!({
|
||||||
|
"current": current,
|
||||||
|
"total": total
|
||||||
|
}));
|
||||||
let path = Path::new(&file_path);
|
let path = Path::new(&file_path);
|
||||||
if !path.is_file() {
|
if !path.is_file() {
|
||||||
return Err("One or more audio files were not found on disk.".to_string());
|
return Err("One or more audio files were not found on disk.".to_string());
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Modal from './Modal.svelte';
|
import Modal from './Modal.svelte';
|
||||||
import { invoke } from '@tauri-apps/api/core';
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
|
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
|
||||||
import { ask } from '@tauri-apps/plugin-dialog';
|
import { ask } from '@tauri-apps/plugin-dialog';
|
||||||
import { openUrl } from '@tauri-apps/plugin-opener';
|
import { openUrl } from '@tauri-apps/plugin-opener';
|
||||||
import { showToast } from '$lib/stores/toastStore';
|
import { showToast } from '$lib/stores/toastStore';
|
||||||
@@ -90,6 +91,7 @@
|
|||||||
let albumTotalDiscs = $state(1);
|
let albumTotalDiscs = $state(1);
|
||||||
let persistence: PersistenceMode = $state('sidecar');
|
let persistence: PersistenceMode = $state('sidecar');
|
||||||
let saving = $state(false);
|
let saving = $state(false);
|
||||||
|
let writeProgress = $state<{ current: number; total: number } | null>(null);
|
||||||
|
|
||||||
// Remote metadata search state
|
// Remote metadata search state
|
||||||
let remoteProvider: RemoteProvider = $state('musicbrainz');
|
let remoteProvider: RemoteProvider = $state('musicbrainz');
|
||||||
@@ -345,10 +347,17 @@
|
|||||||
if (!payload) return;
|
if (!payload) return;
|
||||||
|
|
||||||
saving = true;
|
saving = true;
|
||||||
|
writeProgress = null;
|
||||||
|
let unlisten: UnlistenFn | null = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (persistence === 'sidecar') {
|
if (persistence === 'sidecar') {
|
||||||
await invoke('library_update_album_metadata', { request: payload });
|
await invoke('library_update_album_metadata', { request: payload });
|
||||||
} else {
|
} else {
|
||||||
|
// Listen for progress events
|
||||||
|
unlisten = await listen<{ current: number; total: number }>('library:tag_write_progress', (event) => {
|
||||||
|
writeProgress = event.payload;
|
||||||
|
});
|
||||||
await invoke('library_write_album_metadata_to_files', { request: payload });
|
await invoke('library_write_album_metadata_to_files', { request: payload });
|
||||||
}
|
}
|
||||||
showToast('Album metadata saved', 'success');
|
showToast('Album metadata saved', 'success');
|
||||||
@@ -357,6 +366,8 @@
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(`Failed to save metadata: ${err}`);
|
alert(`Failed to save metadata: ${err}`);
|
||||||
} finally {
|
} finally {
|
||||||
|
if (unlisten) unlisten();
|
||||||
|
writeProgress = null;
|
||||||
saving = false;
|
saving = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -571,7 +582,13 @@
|
|||||||
<button class="btn btn-primary" onclick={handleSave} disabled={saving}>
|
<button class="btn btn-primary" onclick={handleSave} disabled={saving}>
|
||||||
{#if saving}
|
{#if saving}
|
||||||
<span class="spinner-inline"></span>
|
<span class="spinner-inline"></span>
|
||||||
{persistence === 'direct' ? 'Writing tags...' : 'Saving...'}
|
{#if writeProgress}
|
||||||
|
Writing {writeProgress.current} of {writeProgress.total}...
|
||||||
|
{:else if persistence === 'direct'}
|
||||||
|
Writing tags...
|
||||||
|
{:else}
|
||||||
|
Saving...
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
Save
|
Save
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in new issue
Block a user