plex_api/media_container/server/library/
guid.rs1use std::fmt::Formatter;
2
3use serde::{
4 de::{MapAccess, Visitor},
5 Deserialize, Deserializer,
6};
7
8#[derive(Debug, Clone)]
9pub enum Guid {
10 Local(String),
11 Imdb(String),
12 Tmdb(String),
13 Tvdb(String),
14 LastFm(String),
15 Plex(String, String),
16 None(String),
17 Collection(String),
18 Mbid(String),
19 PlexMusic(String),
20 Iva(String),
21 File(String),
22 #[cfg(not(feature = "tests_deny_unknown_fields"))]
23 Unknown(String),
24}
25
26impl<'de> Deserialize<'de> for Guid {
27 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
28 where
29 D: Deserializer<'de>,
30 {
31 struct V;
32
33 impl<'de> Visitor<'de> for V {
34 type Value = Guid;
35
36 fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
37 formatter.write_str("plex-formatted guid string or object")
38 }
39
40 fn visit_str<E>(self, value: &str) -> Result<Guid, E>
41 where
42 E: ::serde::de::Error,
43 {
44 let parts = value.split("://").collect::<Vec<&str>>();
45 if parts.len() != 2 {
46 return Err(serde::de::Error::invalid_value(
47 serde::de::Unexpected::Str(value),
48 &"guid value formatted as protocol://path",
49 ));
50 }
51
52 Ok(match parts[..] {
53 ["imdb", id] | ["com.plexapp.agents.imdb", id] => Guid::Imdb(id.to_owned()),
54 ["local", id] => Guid::Local(id.to_owned()),
55 ["tvdb", id] | ["com.plexapp.agents.thetvdb", id] => Guid::Tvdb(id.to_owned()),
56 ["tmdb", id] => Guid::Tmdb(id.to_owned()),
57 ["collection", id] => Guid::Collection(id.to_owned()),
58 ["com.plexapp.agents.lastfm", id] => Guid::LastFm(id.to_owned()),
59 ["mbid", id] => Guid::Mbid(id.to_owned()),
60 ["com.plexapp.agents.none", id] => Guid::None(id.to_owned()),
61 ["com.plexapp.agents.plexmusic", id] => Guid::PlexMusic(id.to_owned()),
62 ["iva", id] => Guid::Iva(id.to_owned()),
63 ["file", path] => Guid::File(path.to_owned()),
64 ["plex", id] => {
65 let plex_guid_parts = id.split('/').collect::<Vec<&str>>();
66 if plex_guid_parts.len() != 2 {
67 return Err(serde::de::Error::invalid_value(
68 serde::de::Unexpected::Str(value),
69 &"guid value formatted as plex://media_type/id",
70 ));
71 }
72
73 Guid::Plex(plex_guid_parts[0].to_owned(), plex_guid_parts[1].to_owned())
74 }
75 _ => {
76 #[cfg(not(feature = "tests_deny_unknown_fields"))]
77 {
78 Guid::Unknown(value.to_owned())
79 }
80 #[cfg(feature = "tests_deny_unknown_fields")]
81 {
82 return Err(serde::de::Error::invalid_value(
83 serde::de::Unexpected::Str(value),
84 &"see source code for supported values",
85 ));
86 }
87 }
88 })
89 }
90
91 fn visit_map<M>(self, mut map: M) -> Result<Guid, M::Error>
92 where
93 M: MapAccess<'de>,
94 {
95 if let Some((key, value)) = map.next_entry::<&str, &str>()? {
96 if key == "id" {
97 self.visit_str(value)
98 } else {
99 Err(serde::de::Error::unknown_field(
100 value,
101 &["object shouldn't have fields other than id"],
102 ))
103 }
104 } else {
105 Err(serde::de::Error::missing_field("object must have id field"))
106 }
107 }
108 }
109
110 deserializer.deserialize_any(V)
111 }
112}