1use crate::media_container::server::library::Guid;
8use serde::{Deserialize, Serialize};
9use serde_aux::prelude::deserialize_option_number_from_string;
10use time::OffsetDateTime;
11
12#[derive(Deserialize, Debug)]
13#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
14pub struct Webhook {
15 pub event: Event,
16 pub user: bool,
17 pub owner: bool,
18 #[serde(rename = "Account")]
19 pub account: Account,
20 #[serde(rename = "Server")]
21 pub server: Server,
22 #[serde(rename = "Player")]
23 pub player: Option<Player>,
24 #[serde(rename = "Metadata")]
25 pub metadata: Option<Metadata>,
26}
27
28#[derive(Deserialize, Debug)]
29#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
30pub struct Account {
31 pub id: u64,
32 #[serde(with = "http_serde::uri")]
33 pub thumb: http::Uri,
34 pub title: String,
35}
36
37#[derive(Deserialize, Debug)]
38#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
39pub struct Server {
40 pub title: String,
41 pub uuid: String,
42}
43
44#[derive(Deserialize, Debug)]
45#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
46#[serde(rename_all = "camelCase")]
47pub struct Player {
48 pub local: bool,
49 pub public_address: String,
50 pub title: String,
51 pub uuid: String,
52}
53
54#[derive(Deserialize, Debug)]
56#[cfg_attr(feature = "tests_deny_unknown_fields", serde(deny_unknown_fields))]
57#[serde(rename_all = "camelCase")]
58pub struct Metadata {
59 pub title: String,
60 #[serde(with = "time::serde::timestamp")]
61 pub added_at: OffsetDateTime,
62
63 pub library_section_type: Option<String>,
64 pub key: Option<String>,
65 pub parent_key: Option<String>,
66 pub grandparent_key: Option<String>,
67 pub rating_key: Option<String>,
68 pub parent_rating_key: Option<String>,
69 pub grandparent_rating_key: Option<String>,
70 pub guid: Option<Guid>,
71 #[serde(rename = "librarySectionID")]
72 #[serde(deserialize_with = "deserialize_option_number_from_string")]
73 pub library_section_id: Option<u32>,
74 pub r#type: Option<String>,
75 pub parent_title: Option<String>,
76 pub grandparent_title: Option<String>,
77 pub summary: Option<String>,
78 pub index: Option<u32>,
79 pub parent_index: Option<u32>,
80 pub rating_count: Option<u64>,
81 pub thumb: Option<String>,
82 pub parent_thumb: Option<String>,
83 pub grandparent_thumb: Option<String>,
84 pub art: Option<String>,
85 pub grandparent_art: Option<String>,
86 #[serde(with = "time::serde::timestamp::option")]
87 pub updated_at: Option<OffsetDateTime>,
88}
89
90#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
92pub enum Event {
93 #[serde(rename = "library.on.deck")]
96 LibraryOnDeck,
97 #[serde(rename = "library.new")]
100 LibraryNew,
101
102 #[serde(rename = "media.pause")]
104 MediaPause,
105 #[serde(rename = "media.play")]
107 MediaPlay,
108 #[serde(rename = "media.rate")]
110 MediaRate,
111 #[serde(rename = "media.resume")]
113 MediaResume,
114 #[serde(rename = "media.scrobble")]
116 MediaScrobble,
117 #[serde(rename = "media.stop")]
119 MediaStop,
120
121 #[serde(rename = "admin.database.backup")]
123 AdminDatabaseBackup,
124 #[serde(rename = "admin.database.corrupted")]
126 AdminDatabaseCorrupted,
127 #[serde(rename = "device.new")]
131 DeviceNew,
132 #[serde(rename = "playback.started")]
135 PlaybackStarted,
136
137 #[cfg(not(feature = "tests_deny_unknown_fields"))]
138 #[serde(other)]
139 Unknown,
140}
141
142#[cfg(test)]
143mod test {
144 #[plex_api_test_helper::offline_test]
145 fn check_parsing() {
146 serde_json::from_str::<super::Webhook>(WEBHOOK_JSON).expect("failed to parse webhook");
147 }
148
149 const WEBHOOK_JSON: &str = r#"{
150 "event": "media.play",
151 "user": true,
152 "owner": true,
153 "Account": {
154 "id": 1,
155 "thumb": "https://plex.tv/users/1022b120ffbaa/avatar?c=1465525047",
156 "title": "elan"
157 },
158 "Server": {
159 "title": "Office",
160 "uuid": "54664a3d8acc39983675640ec9ce00b70af9cc36"
161 },
162 "Player": {
163 "local": true,
164 "publicAddress": "200.200.200.200",
165 "title": "Plex Web (Safari)",
166 "uuid": "r6yfkdnfggbh2bdnvkffwbms"
167 },
168 "Metadata": {
169 "librarySectionType": "artist",
170 "ratingKey": "1936545",
171 "key": "/library/metadata/1936545",
172 "parentRatingKey": "1936544",
173 "grandparentRatingKey": "1936543",
174 "guid": "com.plexapp.agents.plexmusic://gracenote/track/7572499-91016293BE6BF7F1AB2F848F736E74E5/7572500-3CBAE310D4F3E66C285E104A1458B272?lang=en",
175 "librarySectionID": 1224,
176 "type": "track",
177 "title": "Love The One You're With",
178 "grandparentKey": "/library/metadata/1936543",
179 "parentKey": "/library/metadata/1936544",
180 "grandparentTitle": "Stephen Stills",
181 "parentTitle": "Stephen Stills",
182 "summary": "",
183 "index": 1,
184 "parentIndex": 1,
185 "ratingCount": 6794,
186 "thumb": "/library/metadata/1936544/thumb/1432897518",
187 "art": "/library/metadata/1936543/art/1485951497",
188 "parentThumb": "/library/metadata/1936544/thumb/1432897518",
189 "grandparentThumb": "/library/metadata/1936543/thumb/1485951497",
190 "grandparentArt": "/library/metadata/1936543/art/1485951497",
191 "addedAt": 1000396126,
192 "updatedAt": 1432897518
193 }
194 }
195"#;
196}