plex_api/media_container/
devices.rs

1use secrecy::SecretString;
2use serde::Deserialize;
3use serde_plain::derive_fromstr_from_deserialize;
4use serde_with::{formats::CommaSeparator, serde_as, NoneAsEmptyString, StringWithSeparator};
5use time::OffsetDateTime;
6
7#[derive(Debug, Deserialize, Clone)]
8#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
9#[serde(rename_all = "camelCase")]
10pub struct DevicesMediaContainer {
11    #[serde(rename = "Device", default)]
12    pub devices: Vec<Device>,
13
14    // TODO: The rest of the fields should belong to MediaContainer struct, but
15    // quick-qml (and serde-xml-rs) has some issues with `flatten`.
16    // https://github.com/tafia/quick-xml/issues/226
17    #[serde(rename = "@size", default)]
18    pub size: Option<i32>,
19
20    #[serde(rename = "@publicAddress")]
21    pub public_address: Option<String>,
22    // #[serde(flatten)]
23    // pub media_container: MediaContainer,
24}
25
26#[serde_as]
27#[derive(Debug, Deserialize, Clone)]
28#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
29pub struct Device {
30    #[serde(rename = "@name")]
31    pub name: String,
32    #[serde(rename = "@product")]
33    pub product: String,
34    #[serde(rename = "@publicAddress")]
35    pub public_address: String,
36    #[serde(rename = "@productVersion")]
37    pub product_version: String,
38    #[serde(rename = "@platform")]
39    pub platform: String,
40    #[serde(rename = "@platformVersion")]
41    pub platform_version: String,
42    #[serde(rename = "@device")]
43    pub device: String,
44    #[serde(rename = "@model")]
45    pub model: Option<String>,
46    #[serde(rename = "@vendor")]
47    pub vendor: Option<String>,
48    #[serde_as(as = "StringWithSeparator::<CommaSeparator, Feature>")]
49    #[serde(rename = "@provides")]
50    pub provides: Vec<Feature>,
51    #[serde(rename = "@clientIdentifier")]
52    pub client_identifier: String,
53    #[serde(rename = "@version")]
54    pub version: Option<String>,
55    #[serde(rename = "@id")]
56    pub id: Option<u32>,
57    #[serde(rename = "@token")]
58    pub token: Option<SecretString>,
59    #[serde(rename = "@accessToken")]
60    pub access_token: Option<SecretString>,
61    #[serde(with = "time::serde::timestamp", rename = "@createdAt")]
62    pub created_at: OffsetDateTime,
63    #[serde(with = "time::serde::timestamp", rename = "@lastSeenAt")]
64    pub last_seen_at: OffsetDateTime,
65    #[serde_as(as = "StringWithSeparator::<CommaSeparator, String>")]
66    #[serde(default, rename = "@screenResolution")]
67    pub screen_resolution: Vec<String>,
68    #[serde_as(as = "NoneAsEmptyString")]
69    #[serde(default, rename = "@screenDensity")]
70    pub screen_density: Option<u16>,
71    #[serde(rename = "Connection", default)]
72    pub connections: Vec<Connection>,
73    #[serde(rename = "@httpsRequired")]
74    pub https_required: Option<bool>,
75    #[serde(rename = "@synced")]
76    pub synced: Option<bool>,
77    #[serde(rename = "@relay")]
78    pub relay: Option<bool>,
79    #[serde(rename = "@publicAddressMatches")]
80    pub public_address_matches: Option<bool>,
81    #[serde(rename = "@presence")]
82    pub presence: Option<bool>,
83    #[serde(rename = "@owned")]
84    pub owned: Option<bool>,
85    #[serde(rename = "@ownerId")]
86    pub owner_id: Option<u64>,
87    #[serde(rename = "@home")]
88    pub home: Option<bool>,
89    #[serde(rename = "@sourceTitle")]
90    pub source_title: Option<String>,
91    #[serde(rename = "SyncList")]
92    pub sync_list: Option<SyncList>,
93    #[serde(default = "create_empty_secret_string", rename = "@authToken")]
94    pub auth_token: SecretString,
95    #[serde(rename = "@dnsRebindingProtection")]
96    pub dns_rebinding_protection: Option<bool>,
97    #[serde(rename = "@natLoopbackSupported")]
98    pub nat_loopback_supported: Option<bool>,
99    #[serde(rename = "@searchEnabled")]
100    pub search_enabled: Option<bool>,
101}
102
103fn create_empty_secret_string() -> SecretString {
104    SecretString::new("".into())
105}
106
107#[derive(Debug, Deserialize, Clone)]
108#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
109pub struct SyncList {
110    #[serde(rename = "@itemsCompleteCount")]
111    pub items_complete_count: u32,
112    #[serde(rename = "@totalSize")]
113    pub total_size: u64,
114    #[serde(rename = "@version")]
115    pub version: u32,
116}
117
118#[derive(Debug, Deserialize, Clone)]
119#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
120pub struct Connection {
121    #[serde(with = "http_serde::uri", rename = "@uri")]
122    pub uri: http::Uri,
123    #[serde(rename = "@protocol")]
124    pub protocol: Option<String>,
125    #[serde(rename = "@address")]
126    pub address: Option<String>,
127    #[serde(rename = "@port")]
128    pub port: Option<u32>,
129    #[serde(rename = "@local")]
130    pub local: Option<bool>,
131    #[serde(rename = "@relay")]
132    pub relay: Option<bool>,
133}
134
135#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)]
136#[serde(rename_all = "kebab-case")]
137pub enum Feature {
138    Server,
139    Client,
140    Controller,
141    Player,
142    PubsubPlayer,
143    ProviderPlayback,
144    SyncTarget,
145    #[cfg(not(feature = "tests_deny_unknown_fields"))]
146    #[serde(other)]
147    Unknown,
148}
149
150derive_fromstr_from_deserialize!(Feature);