ytmapi_rs/query/
playlist.rs

1use super::{PostMethod, PostQuery, Query};
2use crate::{
3    auth::AuthToken,
4    common::{PlaylistID, SetVideoID, YoutubeID},
5    parse::GetPlaylist,
6};
7pub use additems::*;
8pub use create::*;
9pub use edit::*;
10use serde::{Deserialize, Serialize};
11use serde_json::json;
12use std::{borrow::Cow, fmt::Display};
13
14pub mod additems;
15pub mod create;
16pub mod edit;
17
18// Potentially same functionality as similar trait for Create.
19pub trait SpecialisedQuery {
20    fn additional_header(&self) -> Option<(String, serde_json::Value)>;
21}
22
23//TODO: Likely Common
24#[derive(Default, PartialEq, Debug, Clone, Deserialize, Serialize)]
25pub enum PrivacyStatus {
26    Public,
27    #[default]
28    Private,
29    Unlisted,
30}
31impl Display for PrivacyStatus {
32    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
33        let str = match self {
34            PrivacyStatus::Public => "PUBLIC",
35            PrivacyStatus::Private => "PRIVATE",
36            PrivacyStatus::Unlisted => "UNLISTED",
37        };
38        write!(f, "{}", str)
39    }
40}
41
42// Suspect this requires a browseId, not a playlistId - i.e requires VL at the
43// start.
44pub struct GetPlaylistQuery<'a> {
45    id: PlaylistID<'a>,
46}
47
48pub struct DeletePlaylistQuery<'a> {
49    id: PlaylistID<'a>,
50}
51
52pub struct RemovePlaylistItemsQuery<'a> {
53    id: PlaylistID<'a>,
54    video_items: Vec<SetVideoID<'a>>,
55}
56
57impl<'a> GetPlaylistQuery<'a> {
58    pub fn new(id: PlaylistID<'a>) -> GetPlaylistQuery<'a> {
59        GetPlaylistQuery { id }
60    }
61}
62impl<'a> DeletePlaylistQuery<'a> {
63    pub fn new(id: PlaylistID<'a>) -> DeletePlaylistQuery<'a> {
64        DeletePlaylistQuery { id }
65    }
66}
67impl<'a> RemovePlaylistItemsQuery<'a> {
68    pub fn new(
69        id: PlaylistID<'a>,
70        video_items: Vec<SetVideoID<'a>>,
71    ) -> RemovePlaylistItemsQuery<'a> {
72        RemovePlaylistItemsQuery { id, video_items }
73    }
74}
75
76impl<A: AuthToken> Query<A> for GetPlaylistQuery<'_> {
77    type Output = GetPlaylist;
78    type Method = PostMethod;
79}
80impl PostQuery for GetPlaylistQuery<'_> {
81    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
82        // TODO: Confirm if processing required to add 'VL' portion of playlistId
83        let serde_json::Value::Object(map) = json!({
84            "browseId" : self.id.get_raw(),
85        }) else {
86            unreachable!()
87        };
88        map
89    }
90    fn path(&self) -> &str {
91        "browse"
92    }
93    fn params(&self) -> Vec<(&str, Cow<str>)> {
94        vec![]
95    }
96}
97
98impl<A: AuthToken> Query<A> for DeletePlaylistQuery<'_> {
99    type Output = ();
100    type Method = PostMethod;
101}
102impl PostQuery for DeletePlaylistQuery<'_> {
103    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
104        // TODO: Confirm if processing required to remove 'VL' portion of playlistId
105        let serde_json::Value::Object(map) = json!({
106            "playlistId" : self.id.get_raw(),
107        }) else {
108            unreachable!()
109        };
110        map
111    }
112    fn path(&self) -> &str {
113        "playlist/delete"
114    }
115    fn params(&self) -> Vec<(&str, Cow<str>)> {
116        vec![]
117    }
118}
119impl<'a> From<PlaylistID<'a>> for DeletePlaylistQuery<'a> {
120    fn from(value: PlaylistID<'a>) -> Self {
121        DeletePlaylistQuery { id: value }
122    }
123}
124
125impl<A: AuthToken> Query<A> for RemovePlaylistItemsQuery<'_> {
126    type Output = ();
127    type Method = PostMethod;
128}
129impl PostQuery for RemovePlaylistItemsQuery<'_> {
130    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
131        let serde_json::Value::Object(mut map) = json!({
132            "playlistId": self.id,
133        }) else {
134            unreachable!()
135        };
136        let actions: Vec<serde_json::Value> = self
137            .video_items
138            .iter()
139            .map(|v| {
140                json!(
141                {
142                    "setVideoId" : v,
143                    "action" : "ACTION_REMOVE_VIDEO",
144                })
145            })
146            .collect();
147        map.insert("actions".into(), json!(actions));
148        map
149    }
150    fn path(&self) -> &str {
151        "browse/edit_playlist"
152    }
153    fn params(&self) -> Vec<(&str, Cow<str>)> {
154        vec![]
155    }
156}