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