ytmapi_rs/query/playlist/
additems.rs1use serde_json::json;
2
3use crate::{
4 auth::AuthToken,
5 common::{PlaylistID, VideoID},
6 parse::AddPlaylistItem,
7 query::{PostMethod, PostQuery, Query},
8};
9use std::borrow::Cow;
10
11use super::SpecialisedQuery;
12
13#[derive(Default, Debug, Clone, PartialEq)]
14pub enum DuplicateHandlingMode {
15 #[default]
16 ReturnError,
17 Unhandled,
18}
19
20pub struct AddPlaylistItemsQuery<'a, T: SpecialisedQuery> {
22 id: PlaylistID<'a>,
23 query_type: T,
24}
25#[derive(Default, Debug, Clone, PartialEq)]
27pub struct AddVideosToPlaylist<'a> {
28 video_ids: Vec<VideoID<'a>>,
29 duplicate_handling_mode: DuplicateHandlingMode,
30}
31#[derive(Debug, Clone, PartialEq)]
33pub struct AddPlaylistToPlaylist<'a> {
34 source_playlist: PlaylistID<'a>,
35}
36impl SpecialisedQuery for AddVideosToPlaylist<'_> {
37 fn additional_header(&self) -> Option<(String, serde_json::Value)> {
38 let actions = self
39 .video_ids
40 .iter()
41 .map(|v| match self.duplicate_handling_mode {
42 DuplicateHandlingMode::ReturnError => json!({
43 "action" : "ACTION_ADD_VIDEO",
44 "addedVideoId" : v,
45 }),
46 DuplicateHandlingMode::Unhandled => json!({
47 "action" : "ACTION_ADD_VIDEO",
48 "addedVideoId" : v,
49 "dedupeOption" : "DEDUPE_OPTION_SKIP",
50 }),
51 });
52 Some(("actions".to_string(), actions.collect()))
53 }
54}
55impl SpecialisedQuery for AddPlaylistToPlaylist<'_> {
56 fn additional_header(&self) -> Option<(String, serde_json::Value)> {
57 Some((
58 "actions".to_string(),
59 json!([{
60 "action" : "ACTION_ADD_PLAYLIST",
61 "addedFullListId" : self.source_playlist,
62 },
63 {
64 "action" : "ACTION_ADD_VIDEO",
65 "addedVideoId" : null,
66 }]),
67 ))
68 }
69}
70impl<'a> AddPlaylistItemsQuery<'a, AddPlaylistToPlaylist<'a>> {
71 pub fn new_from_playlist(id: PlaylistID<'a>, source_playlist: PlaylistID<'a>) -> Self {
72 Self {
73 id,
74 query_type: AddPlaylistToPlaylist { source_playlist },
75 }
76 }
77}
78impl<'a> AddPlaylistItemsQuery<'a, AddVideosToPlaylist<'a>> {
79 pub fn new_from_videos(
80 id: PlaylistID<'a>,
81 video_ids: Vec<VideoID<'a>>,
82 duplicate_handling_mode: DuplicateHandlingMode,
83 ) -> Self {
84 Self {
85 id,
86 query_type: AddVideosToPlaylist {
87 video_ids,
88 duplicate_handling_mode,
89 },
90 }
91 }
92}
93
94impl<A: AuthToken, T: SpecialisedQuery> Query<A> for AddPlaylistItemsQuery<'_, T> {
95 type Output = Vec<AddPlaylistItem>;
96 type Method = PostMethod;
97}
98impl<T: SpecialisedQuery> PostQuery for AddPlaylistItemsQuery<'_, T> {
99 fn header(&self) -> serde_json::Map<String, serde_json::Value> {
100 let serde_json::Value::Object(mut map) = json!({
101 "playlistId" : self.id,
102 }) else {
103 unreachable!()
104 };
105 if let Some(additional_header) = self.query_type.additional_header() {
106 map.insert(additional_header.0, additional_header.1);
107 }
108 map
109 }
110 fn path(&self) -> &str {
111 "browse/edit_playlist"
112 }
113 fn params(&self) -> Vec<(&str, Cow<str>)> {
114 vec![]
115 }
116}