ytmapi_rs/query/
recommendations.rs

1use std::borrow::Cow;
2
3use serde_json::{json, Value};
4
5use super::{PostMethod, PostQuery, Query};
6use crate::{
7    auth::AuthToken,
8    common::{MoodCategoryParams, TasteToken},
9    parse::{MoodCategorySection, MoodPlaylistCategory, TasteProfileArtist},
10};
11
12#[derive(Clone)]
13pub struct GetTasteProfileQuery;
14
15#[derive(Clone)]
16pub struct SetTasteProfileQuery<'a, I>
17where
18    I: Iterator<Item = TasteToken<'a>> + Clone,
19{
20    taste_tokens: I,
21}
22
23#[derive(Clone)]
24pub struct GetMoodCategoriesQuery;
25
26#[derive(Clone)]
27pub struct GetMoodPlaylistsQuery<'a> {
28    params: MoodCategoryParams<'a>,
29}
30
31impl<'a, I> SetTasteProfileQuery<'a, I>
32where
33    I: Iterator<Item = TasteToken<'a>> + Clone,
34{
35    pub fn new<II: IntoIterator<IntoIter = I>>(taste_tokens: II) -> Self {
36        let taste_tokens = taste_tokens.into_iter();
37        Self { taste_tokens }
38    }
39}
40
41impl<'a> GetMoodPlaylistsQuery<'a> {
42    pub fn new(params: MoodCategoryParams<'a>) -> Self {
43        Self { params }
44    }
45}
46
47impl<A: AuthToken> Query<A> for GetTasteProfileQuery {
48    type Output = Vec<TasteProfileArtist>;
49    type Method = PostMethod;
50}
51impl PostQuery for GetTasteProfileQuery {
52    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
53        serde_json::Map::from_iter([("browseId".to_string(), json!("FEmusic_tastebuilder"))])
54    }
55    fn params(&self) -> Vec<(&str, Cow<str>)> {
56        vec![]
57    }
58    fn path(&self) -> &str {
59        "browse"
60    }
61}
62
63impl<'a, A, I> Query<A> for SetTasteProfileQuery<'a, I>
64where
65    A: AuthToken,
66    I: Iterator<Item = TasteToken<'a>> + Clone,
67{
68    type Output = ();
69    type Method = PostMethod;
70}
71impl<'a, I> PostQuery for SetTasteProfileQuery<'a, I>
72where
73    I: Iterator<Item = TasteToken<'a>> + Clone,
74{
75    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
76        let (impression_tokens, selection_tokens): (Vec<Value>, Vec<Value>) = self
77            .taste_tokens
78            .clone()
79            .map(|t| (json!(t.impression_value), json!(t.selection_value)))
80            .unzip();
81        serde_json::Map::from_iter([
82            ("browseId".to_string(), json!("FEmusic_home")),
83            (
84                "formData".to_string(),
85                json!({
86                    "impressionValues": impression_tokens,
87                    "selectedValues": selection_tokens
88                }),
89            ),
90        ])
91    }
92    fn params(&self) -> Vec<(&str, Cow<str>)> {
93        vec![]
94    }
95    fn path(&self) -> &str {
96        "browse"
97    }
98}
99
100impl<A: AuthToken> Query<A> for GetMoodCategoriesQuery {
101    type Output = Vec<MoodCategorySection>;
102    type Method = PostMethod;
103}
104impl PostQuery for GetMoodCategoriesQuery {
105    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
106        serde_json::Map::from_iter([("browseId".to_string(), json!("FEmusic_moods_and_genres"))])
107    }
108    fn params(&self) -> Vec<(&str, Cow<str>)> {
109        vec![]
110    }
111    fn path(&self) -> &str {
112        "browse"
113    }
114}
115
116impl<A: AuthToken> Query<A> for GetMoodPlaylistsQuery<'_> {
117    type Output = Vec<MoodPlaylistCategory>;
118    type Method = PostMethod;
119}
120impl PostQuery for GetMoodPlaylistsQuery<'_> {
121    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
122        serde_json::Map::from_iter([
123            (
124                "browseId".to_string(),
125                json!("FEmusic_moods_and_genres_category"),
126            ),
127            ("params".to_string(), json!(self.params)),
128        ])
129    }
130    fn params(&self) -> Vec<(&str, Cow<str>)> {
131        vec![]
132    }
133    fn path(&self) -> &str {
134        "browse"
135    }
136}