Background-audio handoff for video + repository/player refactor
Hand video playback off to a native audio-only stream when the app is backgrounded or locked, with no on-device video decode (UR-040). Adds player_enter/exit_background_audio commands, an audio-only stream URL for video items across the repository layer, and the frontend handoff state machine wired into VideoPlayer. Includes accompanying repository/offline/player refactoring and regenerates the traceability matrix.
This commit is contained in:
@@ -149,7 +149,10 @@ impl QueueManager {
|
||||
}
|
||||
|
||||
let insert_index = match position {
|
||||
AddPosition::Next => self.current_index.map(|i| i + 1).unwrap_or(self.items.len()),
|
||||
AddPosition::Next => self
|
||||
.current_index
|
||||
.map(|i| i + 1)
|
||||
.unwrap_or(self.items.len()),
|
||||
AddPosition::End => self.items.len(),
|
||||
};
|
||||
|
||||
@@ -167,10 +170,7 @@ impl QueueManager {
|
||||
|
||||
// Regenerate shuffle order if shuffle is on
|
||||
if self.shuffle {
|
||||
self.shuffle_order = self.generate_shuffle_order(
|
||||
self.items.len(),
|
||||
self.current_index,
|
||||
);
|
||||
self.shuffle_order = self.generate_shuffle_order(self.items.len(), self.current_index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,8 @@ impl QueueManager {
|
||||
|
||||
// Update shuffle order
|
||||
if self.shuffle {
|
||||
self.shuffle_order = self.shuffle_order
|
||||
self.shuffle_order = self
|
||||
.shuffle_order
|
||||
.iter()
|
||||
.filter(|&&i| i != index)
|
||||
.map(|&i| if i > index { i - 1 } else { i })
|
||||
@@ -239,7 +240,10 @@ impl QueueManager {
|
||||
} else if self.repeat == RepeatMode::All {
|
||||
0
|
||||
} else {
|
||||
log::debug!("[Queue] next() at end of queue (index {}), no next track", current);
|
||||
log::debug!(
|
||||
"[Queue] next() at end of queue (index {}), no next track",
|
||||
current
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
@@ -269,8 +273,11 @@ impl QueueManager {
|
||||
if let Some(prev) = self.history.pop() {
|
||||
// Safety check: ensure the history entry is valid
|
||||
if prev >= self.items.len() {
|
||||
log::warn!("[Queue] Invalid history entry {} (queue has {} items), clearing history",
|
||||
prev, self.items.len());
|
||||
log::warn!(
|
||||
"[Queue] Invalid history entry {} (queue has {} items), clearing history",
|
||||
prev,
|
||||
self.items.len()
|
||||
);
|
||||
self.history.clear();
|
||||
return None;
|
||||
}
|
||||
@@ -334,10 +341,7 @@ impl QueueManager {
|
||||
self.shuffle = !self.shuffle;
|
||||
|
||||
if self.shuffle && !self.items.is_empty() {
|
||||
self.shuffle_order = self.generate_shuffle_order(
|
||||
self.items.len(),
|
||||
self.current_index,
|
||||
);
|
||||
self.shuffle_order = self.generate_shuffle_order(self.items.len(), self.current_index);
|
||||
} else {
|
||||
self.shuffle_order.clear();
|
||||
}
|
||||
@@ -371,7 +375,8 @@ impl QueueManager {
|
||||
true
|
||||
} else if self.shuffle {
|
||||
let pos = self.shuffle_order.iter().position(|&i| i == current);
|
||||
pos.map(|p| p + 1 < self.shuffle_order.len()).unwrap_or(false)
|
||||
pos.map(|p| p + 1 < self.shuffle_order.len())
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
current + 1 < self.items.len()
|
||||
}
|
||||
@@ -473,8 +478,7 @@ impl QueueManager {
|
||||
// Update shuffle order if shuffle is on
|
||||
if self.shuffle && !self.shuffle_order.is_empty() {
|
||||
// Regenerate shuffle order to maintain consistency
|
||||
self.shuffle_order =
|
||||
self.generate_shuffle_order(self.items.len(), self.current_index);
|
||||
self.shuffle_order = self.generate_shuffle_order(self.items.len(), self.current_index);
|
||||
}
|
||||
|
||||
true
|
||||
@@ -486,7 +490,10 @@ impl QueueManager {
|
||||
if let Some(current_index) = self.current_index {
|
||||
if let Some(item) = self.items.get_mut(current_index) {
|
||||
// Only update if it's a Remote source
|
||||
if let MediaSource::Remote { jellyfin_item_id, .. } = &item.source {
|
||||
if let MediaSource::Remote {
|
||||
jellyfin_item_id, ..
|
||||
} = &item.source
|
||||
{
|
||||
item.source = MediaSource::Remote {
|
||||
stream_url: new_url,
|
||||
jellyfin_item_id: jellyfin_item_id.clone(),
|
||||
|
||||
Reference in New Issue
Block a user