⬆️ version to v0.3.41 — async queue sync refactoring

- Add `SyncCancelled` error variant for non-fatal cancellations
- Refactor queue sync to async via `MusicQueue::schedule_sync()`
  - Extract browse+conversion into internal helper
- Update all `QueueBackend::sync_queue()` signatures to accept cancel token and on_ready callback  
- Implement early-start logic (on pivot preservation or first insert)
 - Add `QueueReadyToPlay` and  ‘ QueueSyncCancelled➔ SSE events
- Replace blocking `refresh_attached_queue_for()` with non-blocking async dispatch in control_point.rs  
- Bump version to v0.3.41
This commit is contained in:
2026-04-09 11:19:54 +02:00
parent c128120697
commit 9dee193947
21 changed files with 1455 additions and 241 deletions

View File

@@ -28,7 +28,8 @@
//! - This identity is used by the sync helpers to preserve the current
//! track across queue rebuilds when the MediaServer content changes.
use crate::{PlaybackItem, QueueSnapshot, errors::ControlPointError};
use crate::{errors::ControlPointError, PlaybackItem, QueueSnapshot};
use std::sync::{atomic::AtomicBool, Arc};
/// High-level enqueue mode.
///
@@ -107,7 +108,12 @@ pub trait QueueBackend {
/// corresponds to the old current index track.
/// If the old current index track is absent from the new queue,
/// it is kept as the first item and the new items are appended after it.
fn sync_queue(&mut self, items: Vec<PlaybackItem>) -> Result<(), ControlPointError>;
fn sync_queue(
&mut self,
items: Vec<PlaybackItem>,
cancel_token: &Arc<AtomicBool>,
on_ready: Option<Box<dyn FnOnce() + Send>>,
) -> Result<(), ControlPointError>;
/// Returns the item at `index`, if it exists.
fn get_item(&self, index: usize) -> Result<Option<PlaybackItem>, ControlPointError>;