librespot_core/dealer/protocol/
request.rs1use crate::{
2 deserialize_with::*,
3 protocol::{
4 context::Context,
5 context_player_options::ContextPlayerOptionOverrides,
6 player::{PlayOrigin, ProvidedTrack},
7 transfer_state::TransferState,
8 },
9};
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use std::fmt::{Display, Formatter};
13
14#[derive(Clone, Debug, Deserialize)]
15pub struct Request {
16 pub message_id: u32,
17 pub sent_by_device_id: String,
20 pub command: Command,
21}
22
23#[derive(Clone, Debug, Deserialize)]
24#[serde(tag = "endpoint", rename_all = "snake_case")]
25pub enum Command {
26 Transfer(TransferCommand),
27 #[serde(deserialize_with = "boxed")]
28 Play(Box<PlayCommand>),
29 Pause(PauseCommand),
30 SeekTo(SeekToCommand),
31 SetShufflingContext(SetValueCommand),
32 SetRepeatingTrack(SetValueCommand),
33 SetRepeatingContext(SetValueCommand),
34 AddToQueue(AddToQueueCommand),
35 SetQueue(SetQueueCommand),
36 SetOptions(SetOptionsCommand),
37 UpdateContext(UpdateContextCommand),
38 SkipNext(SkipNextCommand),
39 SkipPrev(GenericCommand),
41 Resume(GenericCommand),
42 #[serde(untagged)]
44 Unknown(Value),
45}
46
47impl Display for Command {
48 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
49 use Command::*;
50
51 write!(
52 f,
53 "endpoint: {}{}",
54 matches!(self, Unknown(_))
55 .then_some("unknown ")
56 .unwrap_or_default(),
57 match self {
58 Transfer(_) => "transfer",
59 Play(_) => "play",
60 Pause(_) => "pause",
61 SeekTo(_) => "seek_to",
62 SetShufflingContext(_) => "set_shuffling_context",
63 SetRepeatingContext(_) => "set_repeating_context",
64 SetRepeatingTrack(_) => "set_repeating_track",
65 AddToQueue(_) => "add_to_queue",
66 SetQueue(_) => "set_queue",
67 SetOptions(_) => "set_options",
68 UpdateContext(_) => "update_context",
69 SkipNext(_) => "skip_next",
70 SkipPrev(_) => "skip_prev",
71 Resume(_) => "resume",
72 Unknown(json) => {
73 json.as_object()
74 .and_then(|obj| obj.get("endpoint").map(|v| v.as_str()))
75 .flatten()
76 .unwrap_or("???")
77 }
78 }
79 )
80 }
81}
82
83#[derive(Clone, Debug, Deserialize)]
84pub struct TransferCommand {
85 #[serde(default, deserialize_with = "base64_proto")]
86 pub data: Option<TransferState>,
87 pub options: TransferOptions,
88 pub from_device_identifier: String,
89 pub logging_params: LoggingParams,
90}
91
92#[derive(Clone, Debug, Deserialize)]
93pub struct PlayCommand {
94 #[serde(deserialize_with = "json_proto")]
95 pub context: Context,
96 #[serde(deserialize_with = "json_proto")]
97 pub play_origin: PlayOrigin,
98 pub options: PlayOptions,
99 pub logging_params: LoggingParams,
100}
101
102#[derive(Clone, Debug, Deserialize)]
103pub struct PauseCommand {
104 pub logging_params: LoggingParams,
106}
107
108#[derive(Clone, Debug, Deserialize)]
109pub struct SeekToCommand {
110 pub value: u32,
111 pub position: u32,
112 pub logging_params: LoggingParams,
113}
114
115#[derive(Clone, Debug, Deserialize)]
116pub struct SkipNextCommand {
117 #[serde(default, deserialize_with = "option_json_proto")]
118 pub track: Option<ProvidedTrack>,
119 pub logging_params: LoggingParams,
120}
121
122#[derive(Clone, Debug, Deserialize)]
123pub struct SetValueCommand {
124 pub value: bool,
125 pub logging_params: LoggingParams,
126}
127
128#[derive(Clone, Debug, Deserialize)]
129pub struct AddToQueueCommand {
130 #[serde(deserialize_with = "json_proto")]
131 pub track: ProvidedTrack,
132 pub logging_params: LoggingParams,
133}
134
135#[derive(Clone, Debug, Deserialize)]
136pub struct SetQueueCommand {
137 #[serde(deserialize_with = "vec_json_proto")]
138 pub next_tracks: Vec<ProvidedTrack>,
139 #[serde(deserialize_with = "vec_json_proto")]
140 pub prev_tracks: Vec<ProvidedTrack>,
141 pub queue_revision: String,
144 pub logging_params: LoggingParams,
145}
146
147#[derive(Clone, Debug, Deserialize)]
148pub struct SetOptionsCommand {
149 pub shuffling_context: Option<bool>,
150 pub repeating_context: Option<bool>,
151 pub repeating_track: Option<bool>,
152 pub options: Option<OptionsOptions>,
153 pub logging_params: LoggingParams,
154}
155
156#[derive(Clone, Debug, Deserialize)]
157pub struct UpdateContextCommand {
158 #[serde(deserialize_with = "json_proto")]
159 pub context: Context,
160 pub session_id: Option<String>,
161}
162
163#[derive(Clone, Debug, Deserialize)]
164pub struct GenericCommand {
165 pub logging_params: LoggingParams,
166}
167
168#[derive(Clone, Debug, Default, Deserialize, Serialize)]
169pub struct TransferOptions {
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub restore_paused: Option<String>,
172 #[serde(skip_serializing_if = "Option::is_none")]
173 pub restore_position: Option<String>,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub restore_track: Option<String>,
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub retain_session: Option<String>,
178}
179
180#[derive(Clone, Debug, Deserialize)]
181pub struct PlayOptions {
182 pub skip_to: Option<SkipTo>,
183 #[serde(default, deserialize_with = "option_json_proto")]
184 pub player_options_override: Option<ContextPlayerOptionOverrides>,
185 pub license: Option<String>,
186 pub seek_to: Option<u32>,
188 pub always_play_something: Option<bool>,
190 pub audio_stream: Option<String>,
191 pub initially_paused: Option<bool>,
192 pub prefetch_level: Option<String>,
193 pub system_initiated: Option<bool>,
194}
195
196#[derive(Clone, Debug, Deserialize)]
197pub struct OptionsOptions {
198 only_for_local_device: bool,
199 override_restrictions: bool,
200 system_initiated: bool,
201}
202
203#[derive(Clone, Debug, Deserialize, Default)]
204pub struct SkipTo {
205 pub track_uid: Option<String>,
206 pub track_uri: Option<String>,
207 pub track_index: Option<u32>,
208}
209
210#[derive(Clone, Debug, Deserialize)]
211pub struct LoggingParams {
212 pub interaction_ids: Option<Vec<String>>,
213 pub device_identifier: Option<String>,
214 pub command_initiated_time: Option<i64>,
215 pub page_instance_ids: Option<Vec<String>>,
216 pub command_id: Option<String>,
217}