Merge pull request 'push-zplyprxpvxxm' (#51) from push-zplyprxpvxxm into main
All checks were successful
Build and Push Docker Image / build (push) Successful in 28m7s
All checks were successful
Build and Push Docker Image / build (push) Successful in 28m7s
Reviewed-on: https://gargoton.petite-maison-orange.fr/eric/pmomusic/pulls/51
This commit was merged in pull request #51.
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -3713,7 +3713,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pmocontrol"
|
name = "pmocontrol"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-std",
|
"async-std",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pmocontrol"
|
name = "pmocontrol"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -542,6 +542,9 @@ impl ControlPoint {
|
|||||||
"Sleep timer expired, stopping playback"
|
"Sleep timer expired, stopping playback"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Mark this as a user-requested stop to prevent auto-advance
|
||||||
|
renderer.mark_user_stop_requested();
|
||||||
|
|
||||||
// Stop playback
|
// Stop playback
|
||||||
if let Err(err) = renderer.stop() {
|
if let Err(err) = renderer.stop() {
|
||||||
warn!(
|
warn!(
|
||||||
@@ -1516,10 +1519,22 @@ impl ControlPoint {
|
|||||||
#[cfg(feature = "pmoserver")]
|
#[cfg(feature = "pmoserver")]
|
||||||
fn convert_runtime_position(position: Option<&PlaybackPositionInfo>) -> (Option<u64>, Option<u64>) {
|
fn convert_runtime_position(position: Option<&PlaybackPositionInfo>) -> (Option<u64>, Option<u64>) {
|
||||||
match position {
|
match position {
|
||||||
Some(info) => (
|
Some(info) => {
|
||||||
parse_hms_to_ms(info.rel_time.as_deref()),
|
let position_ms = parse_hms_to_ms(info.rel_time.as_deref());
|
||||||
parse_hms_to_ms(info.track_duration.as_deref()),
|
let duration_ms = parse_hms_to_ms(info.track_duration.as_deref());
|
||||||
),
|
|
||||||
|
// Validate that position doesn't exceed duration
|
||||||
|
// If position > duration, the renderer is reporting invalid data
|
||||||
|
// (common during track initialization on some UPNP renderers)
|
||||||
|
match (position_ms, duration_ms) {
|
||||||
|
(Some(pos), Some(dur)) if pos > dur => {
|
||||||
|
// Position exceeds duration - invalid state during initialization
|
||||||
|
// Return None for position to avoid showing bogus timestamps
|
||||||
|
(None, duration_ms)
|
||||||
|
}
|
||||||
|
_ => (position_ms, duration_ms),
|
||||||
|
}
|
||||||
|
}
|
||||||
None => (None, None),
|
None => (None, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -672,47 +672,37 @@ async fn seek_queue_index(
|
|||||||
let control_point = Arc::clone(&state.control_point);
|
let control_point = Arc::clone(&state.control_point);
|
||||||
let rid_for_task = rid.clone();
|
let rid_for_task = rid.clone();
|
||||||
let index = payload.index;
|
let index = payload.index;
|
||||||
let seek_task =
|
|
||||||
tokio::task::spawn_blocking(move || control_point.play_queue_index(&rid_for_task, index));
|
|
||||||
|
|
||||||
time::timeout(TRANSPORT_COMMAND_TIMEOUT, seek_task)
|
// Launch the command in background and return immediately
|
||||||
.await
|
// The UI will be updated via SSE events when the state changes
|
||||||
.map_err(|_| {
|
tokio::task::spawn(async move {
|
||||||
warn!(
|
let rid_for_log = rid_for_task.clone();
|
||||||
"Seek queue command for renderer {} exceeded {:?}",
|
let result = tokio::task::spawn_blocking(move || {
|
||||||
renderer_id, TRANSPORT_COMMAND_TIMEOUT
|
control_point.play_queue_index(&rid_for_task, index)
|
||||||
);
|
})
|
||||||
(
|
.await;
|
||||||
StatusCode::GATEWAY_TIMEOUT,
|
|
||||||
Json(ErrorResponse {
|
match result {
|
||||||
error: format!(
|
Ok(Ok(())) => {
|
||||||
"Seek command timed out after {}s",
|
debug!(
|
||||||
TRANSPORT_COMMAND_TIMEOUT.as_secs()
|
"Successfully started playback at index {} for renderer {}",
|
||||||
),
|
index, rid_for_log.0
|
||||||
}),
|
);
|
||||||
)
|
}
|
||||||
})?
|
Ok(Err(e)) => {
|
||||||
.map_err(|e| {
|
warn!(
|
||||||
warn!("Task join error during queue seek: {}", e);
|
"Failed to seek to index {} for renderer {}: {}",
|
||||||
(
|
index, rid_for_log.0, e
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
);
|
||||||
Json(ErrorResponse {
|
}
|
||||||
error: format!("Internal task error: {}", e),
|
Err(e) => {
|
||||||
}),
|
warn!(
|
||||||
)
|
"Task join error during queue seek for renderer {}: {}",
|
||||||
})?
|
rid_for_log.0, e
|
||||||
.map_err(|e| {
|
);
|
||||||
warn!(
|
}
|
||||||
"Failed to seek to index {} for renderer {}: {}",
|
}
|
||||||
index, renderer_id, e
|
});
|
||||||
);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json(ErrorResponse {
|
|
||||||
error: format!("Failed to seek to index {}: {}", index, e),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Json(SuccessResponse {
|
Ok(Json(SuccessResponse {
|
||||||
message: format!("Playing item at index {}", index),
|
message: format!("Playing item at index {}", index),
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.20
|
0.3.0
|
||||||
|
|||||||
Reference in New Issue
Block a user