Repository: aome510/spotify-player (language: rust)

Issue:
Allow creation of streaming device in daemon mode + don't register another device when spawning TUI
**Is your feature request related to a problem? Please describe.**
Currently if I spawn spotify_player in daemon and then launch another instance in TUI mode - two streaming devices in total are being registered - both with the same name but different IDs

If I set `enable_streaming` to `false` TUI doesn't register new streaming device but then same happens to daemon mode.

**Describe the solution you'd like**
I would like to use spotify_player in daemon mode akin to spotifyd and let it register as streaming device.
Then I would like to use spotify_player in TUI mode from time to time in order to control what is being played.

I tend to control spotify device with Raycast plugin and thus I don't need TUI to be opened 100% of the time. 
I use spotify_player in --daemon mode so it registers itself as streaming device.
But from time to time when I want to change playlist I use TUI mode - I would expect TUI to NOT register another streaming device


I wonder if I miss some option to allow such setup or it isn't possible right now.



Discussion / hints:
I don't think it's possible now to run TUI with streaming disabled beside setting `enable_streaming=false`.  Should be easy to add a new cli option to disable streaming when running the TUI. Maybe we can remove `enable_streaming` as a config option in favours of cli option as it's more flexible.

Fix patch:
diff --git a/docs/config.md b/docs/config.md
index e91b16cc..13d404c7 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -36,7 +36,7 @@ All configuration files should be placed inside the application's configuration
 | `page_size_in_rows`                  | a page's size expressed as a number of rows (for page-navigation commands)    | `20`                                                       |
 | `track_table_item_max_len`           | the maximum length of a column in a track table                               | `32`                                                       |
 | `enable_media_control`               | enable application media control support (`media-control` feature only)       | `true` (Linux), `false` (Windows and MacOS)                |
-| `enable_streaming`                   | create a device for streaming (streaming feature only)                        | `true`                                                     |
+| `enable_streaming`                   | create a device for streaming (streaming feature only)                        | `Always`                                                     |
 | `enable_cover_image_cache`           | store album's cover images in the cache folder                                | `true`                                                     |
 | `default_device`                     | the default device to connect to on startup if no playing device found        | `spotify-player`                                           |
 | `play_icon`                          | the icon to indicate playing state of a Spotify item                          | `▶`                                                        |
@@ -72,8 +72,9 @@ All configuration files should be placed inside the application's configuration
 
 - An example of event that triggers a playback update is the one happening when the current track ends.
 - `copy_command` is represented by a struct with two fields `command` and `args`. For example, `copy_command = { command = "xclip", args = ["-sel", "c"] }`. The copy command should read input from **standard input**.
+- `enable_streaming` can be either `Always`, `Never` or `DaemonOnly`. For backwards compatibility, `true` and `false` are still accepted as aliases for `Always` and `Never`.
 - `playback_window_position` can only be either `Top` or `Bottom`.
-- `border_type` can be either `Hidden`, `Plain`, `Rounded`, `Double`, `Thick`.
+- `border_type` can be either `Hidden`, `Plain`, `Rounded`, `Double` or `Thick`.
 - `progress_bar_type` can be either `Rectangle` or `Line`.
 
 #### Media control
diff --git a/examples/app.toml b/examples/app.toml
index 143ab1d8..2d4115f3 100644
--- a/examples/app.toml
+++ b/examples/app.toml
@@ -14,7 +14,7 @@ cover_image_refresh_duration_in_ms = 2000
 page_size_in_rows = 20
 track_table_item_max_len = 32
 enable_media_control = false
-enable_streaming = true
+enable_streaming = "Always"
 enable_cover_image_cache = true
 default_device = "spotify-player"
 play_icon = "▶"
diff --git a/spotify_player/src/config/mod.rs b/spotify_player/src/config/mod.rs
index 782b192b..9f9c432d 100644
--- a/spotify_player/src/config/mod.rs
+++ b/spotify_player/src/config/mod.rs
@@ -71,7 +71,7 @@ pub struct AppConfig {
     pub enable_media_control: bool,
 
     #[cfg(feature = "streaming")]
-    pub enable_streaming: bool,
+    pub enable_streaming: StreamingType,
 
     pub enable_cover_image_cache: bool,
 
@@ -127,6 +127,42 @@ pub struct NotifyFormat {
     pub body: String,
 }
 
+#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
+#[serde(from = "StreamingTypeOrBool")]
+pub enum StreamingType {
+    Always,
+    DaemonOnly,
+    Never,
+}
+config_parser_impl!(StreamingType);
+
+// For backward compatibility, to accept booleans for enable_streaming
+#[derive(Deserialize)]
+enum RawStreamingType {
+    Always,
+    DaemonOnly,
+    Never,
+}
+
+#[derive(Deserialize)]
+#[serde(untagged)]
+enum StreamingTypeOrBool {
+    Bool(bool),
+    Type(RawStreamingType),
+}
+
+impl From<StreamingTypeOrBool> for StreamingType {
+    fn from(v: StreamingTypeOrBool) -> Self {
+        match v {
+            StreamingTypeOrBool::Bool(true) => StreamingType::Always,
+            StreamingTypeOrBool::Bool(false) => StreamingType::Never,
+            StreamingTypeOrBool::Type(RawStreamingType::Always) => StreamingType::Always,
+            StreamingTypeOrBool::Type(RawStreamingType::DaemonOnly) => StreamingType::DaemonOnly,
+            StreamingTypeOrBool::Type(RawStreamingType::Never) => StreamingType::Never,
+        }
+    }
+}
+
 impl Default for AppConfig {
     fn default() -> Self {
         Self {
@@ -203,7 +239,7 @@ impl Default for AppConfig {
             enable_media_control: true,
 
             #[cfg(feature = "streaming")]
-            enable_streaming: true,
+            enable_streaming: StreamingType::Always,
 
             enable_cover_image_cache: true,
 
diff --git a/spotify_player/src/main.rs b/spotify_player/src/main.rs
index 878f3e34..7be88b74 100644
--- a/spotify_player/src/main.rs
+++ b/spotify_player/src/main.rs
@@ -78,7 +78,9 @@ async fn init_spotify(
 ) -> Result<()> {
     // if `streaming` feature is enabled, create a new streaming connection
     #[cfg(feature = "streaming")]
-    if state.app_config.enable_streaming {
+    if state.app_config.enable_streaming == config::StreamingType::Always
+        || (state.app_config.enable_streaming == config::StreamingType::DaemonOnly && is_daemon)
+    {
         client.new_streaming_connection(state).await;
     }
 


Test patch: