Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog

## [Unreleased]
## Unreleased

### Fixed

- **Native streaming startup device recovery**: Startup now trusts the local `spotatui` Connect device id, preserves saved external devices, activates the native device when Spotify reports no active playback, and renders an actionable idle playbar so paused native sessions restore without manually opening the device selector ([#301](https://github.com/LargeModGames/spotatui/issues/301)).

### Added

Expand Down
62 changes: 62 additions & 0 deletions src/core/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,16 @@ use std::{
};

use arboard::Clipboard;
#[cfg(feature = "streaming")]
use chrono::Utc;
use log::info;
#[cfg(feature = "streaming")]
use rspotify::model::{
context::Actions,
device::Device,
enums::{CurrentlyPlayingType, RepeatState},
DeviceType,
};

pub const LIBRARY_OPTIONS: [&str; 7] = [
"Discover",
Expand Down Expand Up @@ -2172,6 +2181,49 @@ impl App {
self.api_error = e.to_string();
}

#[cfg(feature = "streaming")]
pub fn mark_native_streaming_device_available(
&mut self,
device_id: String,
device_name: String,
volume_percent: u8,
) {
self.native_device_id = Some(device_id.clone());
self.is_streaming_active = true;
self.native_activation_pending = false;
self.native_is_playing = Some(false);

if self
.current_playback_context
.as_ref()
.and_then(|ctx| ctx.item.as_ref())
.is_some()
{
return;
}

self.current_playback_context = Some(CurrentPlaybackContext {
device: Device {
id: Some(device_id),
is_active: true,
is_private_session: false,
is_restricted: false,
name: device_name,
_type: DeviceType::Computer,
volume_percent: Some(u32::from(volume_percent)),
},
repeat_state: RepeatState::Off,
shuffle_state: self.user_config.behavior.shuffle_enabled,
context: None,
timestamp: Utc::now(),
progress: None,
is_playing: false,
item: None,
currently_playing_type: CurrentlyPlayingType::Unknown,
actions: Actions::default(),
});
}

#[cfg(feature = "streaming")]
pub fn has_fresh_native_activity(&self) -> bool {
self.native_track_info.is_some()
Expand Down Expand Up @@ -2235,6 +2287,16 @@ impl App {
// Use native streaming player for instant control (bypasses event channel latency)
#[cfg(feature = "streaming")]
if self.is_native_streaming_active_for_playback() {
if self
.current_playback_context
.as_ref()
.and_then(|ctx| ctx.item.as_ref())
.is_none()
{
self.dispatch(IoEvent::StartPlayback(None, None, None));
return;
}

if let Some(ref player) = self.streaming_player {
let is_playing = self
.native_is_playing
Expand Down
Loading
Loading