librespot_metadata/playlist/
attribute.rs

1use std::{
2    collections::HashMap,
3    fmt::Debug,
4    ops::{Deref, DerefMut},
5};
6
7use crate::{
8    image::PictureSizes,
9    util::{impl_deref_wrapped, impl_from_repeated_copy},
10};
11
12use librespot_core::date::Date;
13
14use librespot_protocol as protocol;
15use protocol::playlist4_external::FormatListAttribute as PlaylistFormatAttributeMessage;
16pub use protocol::playlist4_external::ItemAttributeKind as PlaylistItemAttributeKind;
17use protocol::playlist4_external::ItemAttributes as PlaylistItemAttributesMessage;
18use protocol::playlist4_external::ItemAttributesPartialState as PlaylistPartialItemAttributesMessage;
19pub use protocol::playlist4_external::ListAttributeKind as PlaylistAttributeKind;
20use protocol::playlist4_external::ListAttributes as PlaylistAttributesMessage;
21use protocol::playlist4_external::ListAttributesPartialState as PlaylistPartialAttributesMessage;
22use protocol::playlist4_external::UpdateItemAttributes as PlaylistUpdateItemAttributesMessage;
23use protocol::playlist4_external::UpdateListAttributes as PlaylistUpdateAttributesMessage;
24
25#[derive(Debug, Clone)]
26pub struct PlaylistAttributes {
27    pub name: String,
28    pub description: String,
29    pub picture: Vec<u8>,
30    pub is_collaborative: bool,
31    pub pl3_version: String,
32    pub is_deleted_by_owner: bool,
33    pub client_id: String,
34    pub format: String,
35    pub format_attributes: PlaylistFormatAttribute,
36    pub picture_sizes: PictureSizes,
37}
38
39#[derive(Debug, Clone, Default)]
40pub struct PlaylistAttributeKinds(pub Vec<PlaylistAttributeKind>);
41
42impl_deref_wrapped!(PlaylistAttributeKinds, Vec<PlaylistAttributeKind>);
43
44impl_from_repeated_copy!(PlaylistAttributeKind, PlaylistAttributeKinds);
45
46#[derive(Debug, Clone, Default)]
47pub struct PlaylistFormatAttribute(pub HashMap<String, String>);
48
49impl_deref_wrapped!(PlaylistFormatAttribute, HashMap<String, String>);
50
51#[derive(Debug, Clone)]
52pub struct PlaylistItemAttributes {
53    pub added_by: String,
54    pub timestamp: Date,
55    pub seen_at: Date,
56    pub is_public: bool,
57    pub format_attributes: PlaylistFormatAttribute,
58    pub item_id: Vec<u8>,
59}
60
61#[derive(Debug, Clone, Default)]
62pub struct PlaylistItemAttributeKinds(pub Vec<PlaylistItemAttributeKind>);
63
64impl_deref_wrapped!(PlaylistItemAttributeKinds, Vec<PlaylistItemAttributeKind>);
65
66impl_from_repeated_copy!(PlaylistItemAttributeKind, PlaylistItemAttributeKinds);
67
68#[derive(Debug, Clone)]
69pub struct PlaylistPartialAttributes {
70    #[allow(dead_code)]
71    values: PlaylistAttributes,
72    #[allow(dead_code)]
73    no_value: PlaylistAttributeKinds,
74}
75
76#[derive(Debug, Clone)]
77pub struct PlaylistPartialItemAttributes {
78    #[allow(dead_code)]
79    values: PlaylistItemAttributes,
80    #[allow(dead_code)]
81    no_value: PlaylistItemAttributeKinds,
82}
83
84#[derive(Debug, Clone)]
85pub struct PlaylistUpdateAttributes {
86    pub new_attributes: PlaylistPartialAttributes,
87    pub old_attributes: PlaylistPartialAttributes,
88}
89
90#[derive(Debug, Clone)]
91pub struct PlaylistUpdateItemAttributes {
92    pub index: i32,
93    pub new_attributes: PlaylistPartialItemAttributes,
94    pub old_attributes: PlaylistPartialItemAttributes,
95}
96
97impl TryFrom<&PlaylistAttributesMessage> for PlaylistAttributes {
98    type Error = librespot_core::Error;
99    fn try_from(attributes: &PlaylistAttributesMessage) -> Result<Self, Self::Error> {
100        Ok(Self {
101            name: attributes.name().to_owned(),
102            description: attributes.description().to_owned(),
103            picture: attributes.picture().to_owned(),
104            is_collaborative: attributes.collaborative(),
105            pl3_version: attributes.pl3_version().to_owned(),
106            is_deleted_by_owner: attributes.deleted_by_owner(),
107            client_id: attributes.client_id().to_owned(),
108            format: attributes.format().to_owned(),
109            format_attributes: attributes.format_attributes.as_slice().into(),
110            picture_sizes: attributes.picture_size.as_slice().into(),
111        })
112    }
113}
114
115impl From<&[PlaylistFormatAttributeMessage]> for PlaylistFormatAttribute {
116    fn from(attributes: &[PlaylistFormatAttributeMessage]) -> Self {
117        let format_attributes = attributes
118            .iter()
119            .map(|attribute| (attribute.key().to_owned(), attribute.value().to_owned()))
120            .collect();
121
122        PlaylistFormatAttribute(format_attributes)
123    }
124}
125
126impl TryFrom<&PlaylistItemAttributesMessage> for PlaylistItemAttributes {
127    type Error = librespot_core::Error;
128    fn try_from(attributes: &PlaylistItemAttributesMessage) -> Result<Self, Self::Error> {
129        Ok(Self {
130            added_by: attributes.added_by().to_owned(),
131            timestamp: Date::from_timestamp_ms(attributes.timestamp())?,
132            seen_at: Date::from_timestamp_ms(attributes.seen_at())?,
133            is_public: attributes.public(),
134            format_attributes: attributes.format_attributes.as_slice().into(),
135            item_id: attributes.item_id().to_owned(),
136        })
137    }
138}
139impl TryFrom<&PlaylistPartialAttributesMessage> for PlaylistPartialAttributes {
140    type Error = librespot_core::Error;
141    fn try_from(attributes: &PlaylistPartialAttributesMessage) -> Result<Self, Self::Error> {
142        Ok(Self {
143            values: attributes.values.get_or_default().try_into()?,
144            no_value: attributes
145                .no_value
146                .iter()
147                .map(|v| v.enum_value_or_default())
148                .collect::<Vec<PlaylistAttributeKind>>()
149                .as_slice()
150                .into(),
151        })
152    }
153}
154
155impl TryFrom<&PlaylistPartialItemAttributesMessage> for PlaylistPartialItemAttributes {
156    type Error = librespot_core::Error;
157    fn try_from(attributes: &PlaylistPartialItemAttributesMessage) -> Result<Self, Self::Error> {
158        Ok(Self {
159            values: attributes.values.get_or_default().try_into()?,
160            no_value: attributes
161                .no_value
162                .iter()
163                .map(|v| v.enum_value_or_default())
164                .collect::<Vec<PlaylistItemAttributeKind>>()
165                .as_slice()
166                .into(),
167        })
168    }
169}
170
171impl TryFrom<&PlaylistUpdateAttributesMessage> for PlaylistUpdateAttributes {
172    type Error = librespot_core::Error;
173    fn try_from(update: &PlaylistUpdateAttributesMessage) -> Result<Self, Self::Error> {
174        Ok(Self {
175            new_attributes: update.new_attributes.get_or_default().try_into()?,
176            old_attributes: update.old_attributes.get_or_default().try_into()?,
177        })
178    }
179}
180
181impl TryFrom<&PlaylistUpdateItemAttributesMessage> for PlaylistUpdateItemAttributes {
182    type Error = librespot_core::Error;
183    fn try_from(update: &PlaylistUpdateItemAttributesMessage) -> Result<Self, Self::Error> {
184        Ok(Self {
185            index: update.index(),
186            new_attributes: update.new_attributes.get_or_default().try_into()?,
187            old_attributes: update.old_attributes.get_or_default().try_into()?,
188        })
189    }
190}