1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
mod device;
mod settings;

pub use self::device::*;
pub use self::settings::*;
use crate::serde_helpers::{
    bool_from_int, option_bool_from_int, option_comma_separated_to_vec, option_seconds_to_datetime,
};
use chrono::{DateTime, Utc};

#[derive(Debug, Deserialize, Clone)]
#[cfg_attr(test, serde(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
pub struct MediaContainerWrapper {
    #[serde(rename = "MediaContainer")]
    media_container: MediaContainer,
}

impl MediaContainerWrapper {
    pub fn unwrap_media_container(self) -> MediaContainer {
        self.media_container
    }
}

#[derive(Debug, Deserialize, Clone)]
#[cfg_attr(test, serde(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
pub struct MediaContainer {
    size: Option<u32>,
    total_size: Option<u32>,
    public_address: Option<String>,
    friendly_name: Option<String>,
    identifier: Option<String>,
    machine_identifier: Option<String>,
    #[serde(rename = "Device")]
    devices: Option<Vec<Device>>,
    #[serde(rename = "User")]
    users: Option<Vec<User>>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    allow_camera_upload: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    allow_channel_access: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    allow_media_deletion: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    allow_sharing: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    allow_sync: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    allow_tuners: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    background_processing: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    certificate: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    companion_proxy: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    event_stream: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    hub_search: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    item_clusters: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    media_providers: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    multiuser: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    my_plex: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    my_plex_subscription: Option<bool>,
    country_code: Option<String>,
    #[serde(default, deserialize_with = "option_comma_separated_to_vec")]
    diagnostics: Option<Vec<String>>,
    livetv: Option<u8>,
    my_plex_mapping_state: Option<String>,
    my_plex_signin_state: Option<String>,
    my_plex_username: Option<String>,
    #[serde(deserialize_with = "option_comma_separated_to_vec", default)]
    owner_features: Option<Vec<String>>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    photo_auto_tag: Option<bool>,
    platform: Option<String>,
    platform_version: Option<String>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    plugin_host: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    request_parameters_in_cookie: Option<bool>,
    read_only_libraries: Option<u16>,
    #[serde(rename = "streamingBrainABRVersion")]
    streaming_brain_abr_version: Option<u8>,
    streaming_brain_version: Option<u8>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    sync: Option<bool>,
    transcoder_active_video_sessions: Option<u8>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    transcoder_audio: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    transcoder_lyrics: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    transcoder_photo: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    transcoder_subtitles: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    transcoder_video: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    updater: Option<bool>,
    #[serde(default, deserialize_with = "option_bool_from_int")]
    voice_search: Option<bool>,
    #[serde(deserialize_with = "option_comma_separated_to_vec", default)]
    transcoder_video_bitrates: Option<Vec<u16>>,
    #[serde(deserialize_with = "option_comma_separated_to_vec", default)]
    transcoder_video_qualities: Option<Vec<u8>>,
    #[serde(deserialize_with = "option_comma_separated_to_vec", default)]
    transcoder_video_resolutions: Option<Vec<u16>>,
    #[serde(default, deserialize_with = "option_seconds_to_datetime")]
    updated_at: Option<DateTime<Utc>>,
    version: Option<String>,
    #[serde(rename = "Directory")]
    directories: Option<Vec<Directory>>,
    max_upload_bitrate: Option<u16>,
    max_upload_bitrate_reason: Option<String>,
    max_upload_bitrate_reason_message: Option<String>,
    #[serde(rename = "Setting", default)]
    settings: Option<Vec<Setting>>,
}

impl MediaContainer {
    pub fn get_devices(&self) -> Option<Vec<Device>> {
        self.devices.clone()
    }

    pub fn get_users(&self) -> Option<Vec<User>> {
        self.users.clone()
    }
}

impl From<MediaContainerWrapper> for MediaContainer {
    fn from(w: MediaContainerWrapper) -> Self {
        w.unwrap_media_container()
    }
}

#[derive(Debug, Deserialize, Clone)]
#[cfg_attr(test, serde(deny_unknown_fields))]
pub struct Directory {
    count: u16,
    key: String,
    title: String,
}

#[derive(Debug, Deserialize, Clone)]
#[cfg_attr(test, serde(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
pub struct User {
    id: u32,
    title: String,
    thumb: String,
    #[serde(deserialize_with = "bool_from_int")]
    protected: bool,
    #[serde(deserialize_with = "bool_from_int")]
    home: bool,
    #[serde(deserialize_with = "bool_from_int")]
    allow_sync: bool,
    #[serde(deserialize_with = "bool_from_int")]
    allow_camera_upload: bool,
    #[serde(deserialize_with = "bool_from_int")]
    allow_channels: bool,
    #[serde(deserialize_with = "bool_from_int")]
    allow_tuners: bool,
    #[serde(deserialize_with = "bool_from_int")]
    allow_subtitle_admin: bool,
    #[serde(deserialize_with = "bool_from_int")]
    restricted: bool,
    filter_all: String,
    filter_movies: String,
    filter_music: String,
    filter_photos: String,
    filter_television: String,
    #[serde(rename = "Server")]
    servers: Option<Vec<Server>>,
}

#[derive(Debug, Deserialize, Clone)]
#[cfg_attr(test, serde(deny_unknown_fields))]
#[serde(rename_all = "camelCase")]
struct Server {
    id: u32,
    server_id: u32,
    machine_identifier: String,
    name: String,
    #[serde(with = "chrono::serde::ts_seconds")]
    last_seen_at: DateTime<Utc>,
    num_libraries: u32,
    #[serde(deserialize_with = "bool_from_int")]
    all_libraries: bool,
    #[serde(deserialize_with = "bool_from_int")]
    owned: bool,
    #[serde(deserialize_with = "bool_from_int")]
    pending: bool,
}