1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use super::{PostMethod, PostQuery, Query};
use crate::{
    auth::AuthToken,
    common::{EpisodeID, PodcastChannelID, PodcastChannelParams, PodcastID, VideoID},
    parse::{Episode, GetEpisode, GetPodcast, GetPodcastChannel},
};
use serde_json::json;

pub struct GetChannelQuery<'a> {
    channel_id: PodcastChannelID<'a>,
}
pub struct GetChannelEpisodesQuery<'a> {
    channel_id: PodcastChannelID<'a>,
    podcast_channel_params: PodcastChannelParams<'a>,
}
pub struct GetPodcastQuery<'a> {
    podcast_id: PodcastID<'a>,
}
pub struct GetEpisodeQuery<'a> {
    episode_id: EpisodeID<'a>,
}
pub struct GetNewEpisodesQuery;

// NOTE: This is technically the same page as the GetArtist page. It's possible
// this could be generalised.
impl<'a> GetChannelQuery<'a> {
    pub fn new(channel_id: impl Into<PodcastChannelID<'a>>) -> Self {
        Self {
            channel_id: channel_id.into(),
        }
    }
}
impl<'a> GetChannelEpisodesQuery<'a> {
    pub fn new(
        channel_id: impl Into<PodcastChannelID<'a>>,
        podcast_channel_params: impl Into<PodcastChannelParams<'a>>,
    ) -> GetChannelEpisodesQuery<'a> {
        GetChannelEpisodesQuery {
            channel_id: channel_id.into(),
            podcast_channel_params: podcast_channel_params.into(),
        }
    }
}
impl<'a> GetPodcastQuery<'a> {
    pub fn new(podcast_id: impl Into<PodcastID<'a>>) -> Self {
        Self {
            podcast_id: podcast_id.into(),
        }
    }
}
impl<'a> GetEpisodeQuery<'a> {
    pub fn new(episode_id: impl Into<EpisodeID<'a>>) -> Self {
        Self {
            episode_id: episode_id.into(),
        }
    }
}

impl<'a, A: AuthToken> Query<A> for GetChannelQuery<'a> {
    type Output = GetPodcastChannel;
    type Method = PostMethod;
}
impl<'a, A: AuthToken> Query<A> for GetChannelEpisodesQuery<'a> {
    type Output = Vec<Episode>;
    type Method = PostMethod;
}
impl<'a, A: AuthToken> Query<A> for GetPodcastQuery<'a> {
    type Output = GetPodcast;
    type Method = PostMethod;
}
impl<'a, A: AuthToken> Query<A> for GetEpisodeQuery<'a> {
    type Output = GetEpisode;
    type Method = PostMethod;
}
impl<A: AuthToken> Query<A> for GetNewEpisodesQuery {
    type Output = Vec<Episode>;
    type Method = PostMethod;
}

impl<'a> PostQuery for GetChannelQuery<'a> {
    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
        FromIterator::from_iter([("browseId".into(), json!(self.channel_id))])
    }
    fn params(&self) -> Option<std::borrow::Cow<str>> {
        None
    }
    fn path(&self) -> &str {
        "browse"
    }
}
impl<'a> PostQuery for GetChannelEpisodesQuery<'a> {
    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
        FromIterator::from_iter([
            ("browseId".into(), json!(self.channel_id)),
            ("params".into(), json!(self.podcast_channel_params)),
        ])
    }
    fn params(&self) -> Option<std::borrow::Cow<str>> {
        None
    }
    fn path(&self) -> &str {
        "browse"
    }
}
// TODO: Continuations
impl<'a> PostQuery for GetPodcastQuery<'a> {
    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
        // TODO: Confirm if any parsing required
        FromIterator::from_iter([("browseId".into(), json!(self.podcast_id))])
    }
    fn params(&self) -> Option<std::borrow::Cow<str>> {
        None
    }
    fn path(&self) -> &str {
        "browse"
    }
}
impl<'a> PostQuery for GetEpisodeQuery<'a> {
    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
        // TODO: Confirm if any parsing required
        FromIterator::from_iter([("browseId".into(), json!(self.episode_id))])
    }
    fn params(&self) -> Option<std::borrow::Cow<str>> {
        None
    }
    fn path(&self) -> &str {
        "browse"
    }
}
// Gets the NewEpisodes auto-playlist. In future there could be other similar
// playlists, we can instead re-implement this as GetEpisodesPlaylist.
impl PostQuery for GetNewEpisodesQuery {
    fn header(&self) -> serde_json::Map<String, serde_json::Value> {
        FromIterator::from_iter([("browseId".into(), json!("VLRDPN"))])
    }
    fn params(&self) -> Option<std::borrow::Cow<str>> {
        None
    }
    fn path(&self) -> &str {
        "browse"
    }
}