feat: real progress bar and improved loading state for scene discovery

Backend emits 'scene-discovery-progress' events with phase, progress
percentage, and detail. Frontend listens and shows a real progress bar
(0-40% MB search, 40-95% Qobuz validation, 100% done).

Loading state: hides header, cycles icons (Music/Globe/Network) at
1.5s intervals in a 96px pulse circle, shows progress bar with
percentage text.
This commit is contained in:
vicrodh committed 2026-03-09 17:29:14 -06:00
1 parent 3050999d60
commit faa68d1079
2 files changed
+174 -106

No files matched your search

+33 -2
View File
@@ -8819,6 +8819,7 @@ pub async fn v2_discover_artists_by_location(
bridge: State<'_, CoreBridgeState>,
blacklist_state: State<'_, BlacklistState>,
runtime: State<'_, RuntimeManagerState>,
app: tauri::AppHandle,
) -> Result<crate::musicbrainz::LocationDiscoveryResponse, RuntimeError> {
use crate::musicbrainz::genre_normalization::{extract_affinity_seeds, genre_summary, is_broad_genre};
use crate::musicbrainz::location_discovery::{build_scene_cache_key, compute_affinity_score};
@@ -8969,7 +8970,15 @@ pub async fn v2_discover_artists_by_location(
let mut candidate_map: HashMap<String, (String, i32, usize, Vec<String>)> = HashMap::new();
let per_genre_limit = 200; // Get up to 200 per genre query for broader coverage
for genre in &search_genres {
let total_genres = search_genres.len();
for (genre_idx, genre) in search_genres.iter().enumerate() {
// Progress: MB search phase = 0-40%
let progress = ((genre_idx as f64 / total_genres as f64) * 40.0) as u8;
let _ = app.emit("scene-discovery-progress", serde_json::json!({
"phase": "searching",
"progress": progress,
"detail": genre
}));
let search_result = state
.client
.search_artists_by_tag_and_area(genre, &search_name, country.as_deref(), per_genre_limit, 0)
@@ -9096,9 +9105,25 @@ pub async fn v2_discover_artists_by_location(
// Step 4: Validate against Qobuz
let bridge_guard = bridge.try_get().await;
let mut validated: Vec<LocationCandidate> = Vec::new();
let total_to_validate = candidates_to_validate.len();
let _ = app.emit("scene-discovery-progress", serde_json::json!({
"phase": "validating",
"progress": 40,
"detail": format!("{} candidates", total_to_validate)
}));
if let Some(ref core_bridge) = bridge_guard {
for (mbid, mb_name, candidate_genres, score) in &candidates_to_validate {
for (validate_idx, (mbid, mb_name, candidate_genres, score)) in candidates_to_validate.iter().enumerate() {
// Progress: Qobuz validation phase = 40-95%
if validate_idx % 5 == 0 {
let progress = 40 + ((validate_idx as f64 / total_to_validate as f64) * 55.0) as u8;
let _ = app.emit("scene-discovery-progress", serde_json::json!({
"phase": "validating",
"progress": progress,
"detail": format!("{}/{}", validate_idx, total_to_validate)
}));
}
// Qobuz validation cache — TEMPORARILY DISABLED for tuning
let _name_normalized =
crate::musicbrainz::cache::MusicBrainzCache::normalize_name(mb_name);
@@ -9164,6 +9189,12 @@ pub async fn v2_discover_artists_by_location(
}
}
let _ = app.emit("scene-discovery-progress", serde_json::json!({
"phase": "done",
"progress": 100,
"detail": format!("{} artists", validated.len())
}));
log::info!(
"[V2] Scene discovery complete: {} validated artists from {}",
validated.len(),