librespot_core/
config.rs

1use std::{fmt, path::PathBuf, str::FromStr};
2
3use url::Url;
4
5pub(crate) const KEYMASTER_CLIENT_ID: &str = "65b708073fc0480ea92a077233ca87bd";
6pub(crate) const ANDROID_CLIENT_ID: &str = "9a8d2f0ce77a4e248bb71fefcb557637";
7pub(crate) const IOS_CLIENT_ID: &str = "58bd3c95768941ea9eb4350aaa033eb3";
8
9// Easily adjust the current platform to mock the behavior on it. If for example
10// android or ios needs to be mocked, the `os_version` has to be set to a valid version.
11// Otherwise, client-token or login5 requests will fail with a generic invalid-credential error.
12/// See [std::env::consts::OS]
13pub const OS: &str = std::env::consts::OS;
14
15// valid versions for some os:
16// 'android': 30
17// 'ios': 17
18/// See [sysinfo::System::os_version]
19pub fn os_version() -> String {
20    sysinfo::System::os_version().unwrap_or("0".into())
21}
22
23#[derive(Clone, Debug)]
24pub struct SessionConfig {
25    pub client_id: String,
26    pub device_id: String,
27    pub proxy: Option<Url>,
28    pub ap_port: Option<u16>,
29    pub tmp_dir: PathBuf,
30    pub autoplay: Option<bool>,
31}
32
33impl SessionConfig {
34    pub(crate) fn default_for_os(os: &str) -> Self {
35        let device_id = uuid::Uuid::new_v4().as_hyphenated().to_string();
36        let client_id = match os {
37            "android" => ANDROID_CLIENT_ID,
38            "ios" => IOS_CLIENT_ID,
39            _ => KEYMASTER_CLIENT_ID,
40        }
41        .to_owned();
42
43        Self {
44            client_id,
45            device_id,
46            proxy: None,
47            ap_port: None,
48            tmp_dir: std::env::temp_dir(),
49            autoplay: None,
50        }
51    }
52}
53
54impl Default for SessionConfig {
55    fn default() -> Self {
56        Self::default_for_os(OS)
57    }
58}
59
60#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq, Default)]
61pub enum DeviceType {
62    Unknown = 0,
63    Computer = 1,
64    Tablet = 2,
65    Smartphone = 3,
66    #[default]
67    Speaker = 4,
68    Tv = 5,
69    Avr = 6,
70    Stb = 7,
71    AudioDongle = 8,
72    GameConsole = 9,
73    CastAudio = 10,
74    CastVideo = 11,
75    Automobile = 12,
76    Smartwatch = 13,
77    Chromebook = 14,
78    UnknownSpotify = 100,
79    CarThing = 101,
80    Observer = 102,
81    HomeThing = 103,
82}
83
84impl FromStr for DeviceType {
85    type Err = ();
86    fn from_str(s: &str) -> Result<Self, Self::Err> {
87        use self::DeviceType::*;
88        match s.to_lowercase().as_ref() {
89            "computer" => Ok(Computer),
90            "tablet" => Ok(Tablet),
91            "smartphone" => Ok(Smartphone),
92            "speaker" => Ok(Speaker),
93            "tv" => Ok(Tv),
94            "avr" => Ok(Avr),
95            "stb" => Ok(Stb),
96            "audiodongle" => Ok(AudioDongle),
97            "gameconsole" => Ok(GameConsole),
98            "castaudio" => Ok(CastAudio),
99            "castvideo" => Ok(CastVideo),
100            "automobile" => Ok(Automobile),
101            "smartwatch" => Ok(Smartwatch),
102            "chromebook" => Ok(Chromebook),
103            "carthing" => Ok(CarThing),
104            "homething" => Ok(HomeThing),
105            _ => Err(()),
106        }
107    }
108}
109
110impl From<&DeviceType> for &str {
111    fn from(d: &DeviceType) -> &'static str {
112        use self::DeviceType::*;
113        match d {
114            Unknown => "Unknown",
115            Computer => "Computer",
116            Tablet => "Tablet",
117            Smartphone => "Smartphone",
118            Speaker => "Speaker",
119            Tv => "TV",
120            Avr => "AVR",
121            Stb => "STB",
122            AudioDongle => "AudioDongle",
123            GameConsole => "GameConsole",
124            CastAudio => "CastAudio",
125            CastVideo => "CastVideo",
126            Automobile => "Automobile",
127            Smartwatch => "Smartwatch",
128            Chromebook => "Chromebook",
129            UnknownSpotify => "UnknownSpotify",
130            CarThing => "CarThing",
131            Observer => "Observer",
132            HomeThing => "HomeThing",
133        }
134    }
135}
136
137impl From<DeviceType> for &str {
138    fn from(d: DeviceType) -> &'static str {
139        (&d).into()
140    }
141}
142
143impl fmt::Display for DeviceType {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        let str: &str = self.into();
146        f.write_str(str)
147    }
148}