plex_api/media_container/server/library/
guid.rs

1use 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}