ytmapi_rs/query/playlist/
create.rs1use super::PrivacyStatus;
2use crate::auth::AuthToken;
3use crate::common::{PlaylistID, VideoID};
4use crate::query::{PostMethod, PostQuery, Query};
5use serde_json::json;
6use std::borrow::Cow;
7
8pub trait CreatePlaylistType {
9 fn additional_header(&self) -> Option<(String, serde_json::Value)>;
10}
11
12#[derive(Debug, Clone, PartialEq)]
15pub struct CreatePlaylistQuery<'a, C: CreatePlaylistType> {
16 title: Cow<'a, str>,
17 description: Option<Cow<'a, str>>,
18 privacy_status: PrivacyStatus,
19 query_type: C,
20}
21
22#[derive(Default, Debug, Clone, PartialEq)]
24pub struct BasicCreatePlaylist {}
25#[derive(Default, Debug, Clone, PartialEq)]
27pub struct CreatePlaylistFromVideos<'a> {
28 video_ids: Vec<VideoID<'a>>,
29}
30#[derive(Debug, Clone, PartialEq)]
32pub struct CreatePlaylistFromPlaylist<'a> {
33 source_playlist: PlaylistID<'a>,
34}
35
36impl CreatePlaylistType for BasicCreatePlaylist {
37 fn additional_header(&self) -> Option<(String, serde_json::Value)> {
38 None
39 }
40}
41impl CreatePlaylistType for CreatePlaylistFromVideos<'_> {
42 fn additional_header(&self) -> Option<(String, serde_json::Value)> {
43 Some(("videoIds".into(), json!(self.video_ids)))
44 }
45}
46impl CreatePlaylistType for CreatePlaylistFromPlaylist<'_> {
47 fn additional_header(&self) -> Option<(String, serde_json::Value)> {
48 Some(("sourcePlaylistId".into(), json!(self.source_playlist)))
49 }
50}
51
52impl<'a> CreatePlaylistQuery<'a, BasicCreatePlaylist> {
53 pub fn new(
54 title: &'a str,
55 description: Option<&'a str>,
56 privacy_status: PrivacyStatus,
57 ) -> CreatePlaylistQuery<'a, BasicCreatePlaylist> {
58 CreatePlaylistQuery {
59 title: title.into(),
60 description: description.map(|d| d.into()),
61 privacy_status,
62 query_type: BasicCreatePlaylist {},
63 }
64 }
65}
66
67impl<'a> CreatePlaylistQuery<'a, BasicCreatePlaylist> {
68 pub fn with_source<T: Into<PlaylistID<'a>>>(
69 self,
70 source_playlist: T,
71 ) -> CreatePlaylistQuery<'a, CreatePlaylistFromPlaylist<'a>> {
72 let CreatePlaylistQuery {
73 title,
74 description,
75 privacy_status,
76 ..
77 } = self;
78 CreatePlaylistQuery {
79 title,
80 description,
81 privacy_status,
82 query_type: CreatePlaylistFromPlaylist {
83 source_playlist: source_playlist.into(),
84 },
85 }
86 }
87}
88
89impl<'a> CreatePlaylistQuery<'a, BasicCreatePlaylist> {
90 pub fn with_video_ids(
91 self,
92 video_ids: impl IntoIterator<Item = VideoID<'a>>,
93 ) -> CreatePlaylistQuery<'a, CreatePlaylistFromVideos<'a>> {
94 let CreatePlaylistQuery {
95 title,
96 description,
97 privacy_status,
98 ..
99 } = self;
100 CreatePlaylistQuery {
101 title,
102 description,
103 privacy_status,
104 query_type: CreatePlaylistFromVideos {
105 video_ids: video_ids.into_iter().collect(),
106 },
107 }
108 }
109}
110
111impl<A: AuthToken, C: CreatePlaylistType> Query<A> for CreatePlaylistQuery<'_, C> {
112 type Output = PlaylistID<'static>;
113 type Method = PostMethod;
114}
115impl<C: CreatePlaylistType> PostQuery for CreatePlaylistQuery<'_, C> {
116 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
117 let serde_json::Value::Object(mut map) = json!({
119 "title" : self.title,
120 "privacyStatus" : self.privacy_status.to_string(),
121 }) else {
122 unreachable!()
123 };
124 if let Some(description) = &self.description {
125 map.insert("description".to_string(), description.as_ref().into());
129 }
130 if let Some(additional_header) = self.query_type.additional_header() {
131 map.insert(additional_header.0, additional_header.1);
132 }
133 map
134 }
135 fn path(&self) -> &str {
136 "playlist/create"
137 }
138 fn params(&self) -> Vec<(&str, Cow<'_, str>)> {
139 vec![]
140 }
141}