PLAYER: Fixed connected device logic.
Build and Publish / Build and Publish Docker Image (push) Successful in 2m50s

This commit is contained in:
2026-05-28 15:17:59 +03:00
parent 34e25fac2c
commit 072c00a48e
7 changed files with 132 additions and 33 deletions
+4
View File
@@ -338,6 +338,10 @@ translations! {
player_lastfm_connected: "Connected as {user}" , "Подключён: {user}";
player_lastfm_reconnect: "Reconnect Last.fm" , "Переподключить Last.fm";
player_lastfm_not_configured: "Last.fm is not configured" , "Last.fm не настроен";
player_lastfm_status_connect: "connect account" , "подключить аккаунт";
player_lastfm_status_connected: "connected" , "подключён";
player_lastfm_status_reconnect: "reconnect account" , "переподключить аккаунт";
player_lastfm_status_not_configured: "not configured" , "не настроен";
player_lastfm_disconnect_confirm: "Disconnect Last.fm account {user}?" , "Отвязать аккаунт Last.fm {user}?";
player_lastfm_connect_failed: "Could not open Last.fm connection" , "Не удалось открыть подключение Last.fm";
player_lastfm_disconnect_failed: "Could not disconnect Last.fm" , "Не удалось отвязать Last.fm";
+54 -2
View File
@@ -146,9 +146,32 @@ impl PlayerDeviceHub {
if !devices.contains_key(target_device_id) {
return None;
}
let previous_active_id = state.active_device_by_user.get(&user_id).cloned();
let transfer_state = state
.playback_state_by_user
.get(&user_id)
.cloned()
.map(|playback_state| playback_state_at(playback_state, now));
state
.active_device_by_user
.insert(user_id, target_device_id.to_string());
if previous_active_id.as_deref() != Some(target_device_id) {
if let Some(transfer_state) = transfer_state {
state
.playback_state_by_user
.insert(user_id, transfer_state.clone());
if let Ok(payload) = serde_json::to_value(transfer_state) {
self.enqueue_command_locked(
&mut state,
user_id,
target_device_id,
"transfer_state",
payload,
now,
);
}
}
}
Some(self.snapshot_locked(&state, user_id, current_device_id, now))
}
@@ -180,9 +203,22 @@ impl PlayerDeviceHub {
return Err("target device is offline");
}
self.enqueue_command_locked(&mut state, user_id, &target_id, command, payload, now);
Ok(())
}
fn enqueue_command_locked(
&self,
state: &mut PlayerDeviceHubState,
user_id: i64,
target_device_id: &str,
command: &str,
payload: serde_json::Value,
now: i64,
) {
let queue = state
.commands_by_device
.entry((user_id, target_id))
.entry((user_id, target_device_id.to_string()))
.or_default();
while queue.len() >= PLAYER_DEVICE_MAX_COMMANDS {
queue.pop_front();
@@ -193,7 +229,6 @@ impl PlayerDeviceHub {
payload,
created_at_ms: now,
});
Ok(())
}
fn touch_locked(
@@ -332,6 +367,23 @@ fn current_millis() -> i64 {
chrono::Utc::now().timestamp_millis()
}
fn playback_state_at(
mut playback_state: PlayerDevicePlaybackStateDto,
now: i64,
) -> PlayerDevicePlaybackStateDto {
if !playback_state.paused && playback_state.updated_at_ms > 0 {
let elapsed_seconds = now.saturating_sub(playback_state.updated_at_ms) as f64 / 1000.0;
playback_state.position_seconds += elapsed_seconds;
if playback_state.duration_seconds > 0.0 {
playback_state.position_seconds = playback_state
.position_seconds
.min(playback_state.duration_seconds);
}
}
playback_state.updated_at_ms = now;
playback_state
}
fn normalize_device_id(raw: &str) -> Option<String> {
let trimmed = raw.trim();
if trimmed.is_empty() || trimmed.len() > 128 {