ytmapi_rs/
query.rs

1//! Type safe queries to pass to the API, and the traits to allow you to
2//! implement new ones.
3//! # Implementation example
4//! Note, to implement Query, you must also meet the trait bounds for
5//! QueryMethod. In practice, this means you must implement both Query and
6//! PostQuery when using PostMethod, and Query and GetQuery when using
7//! GetMethod.
8//! In addition, note that your output type will need to implement ParseFrom -
9//! see [`crate::parse`] for implementation notes.
10//! ```no_run
11//! # #[derive(Debug)]
12//! # struct Date;
13//! # impl ytmapi_rs::parse::ParseFrom<GetDateQuery> for Date {
14//! #     fn parse_from(_: ytmapi_rs::parse::ProcessedResult<GetDateQuery>) -> ytmapi_rs::Result<Self> {todo!()}
15//! # }
16//! struct GetDateQuery;
17//! impl ytmapi_rs::query::Query<ytmapi_rs::auth::BrowserToken> for GetDateQuery {
18//!     type Output = Date;
19//!     type Method = ytmapi_rs::query::PostMethod;
20//! }
21//! // Note that this is not a real Innertube endpoint - example for reference only!
22//! impl ytmapi_rs::query::PostQuery for GetDateQuery {
23//!     fn header(&self) -> serde_json::Map<String, serde_json::Value> {
24//!         serde_json::Map::from_iter([("get_date".to_string(), serde_json::json!("YYYYMMDD"))])
25//!     }
26//!     fn params(&self) -> Vec<(&str, std::borrow::Cow<str>)> {
27//!         vec![]
28//!     }
29//!     fn path(&self) -> &str {
30//!         "date"
31//!     }
32//! }
33//! ```
34use crate::auth::{AuthToken, raw_query_get, raw_query_post};
35use crate::parse::ParseFrom;
36use crate::{RawResult, Result};
37use private::Sealed;
38use std::borrow::Cow;
39use std::fmt::Debug;
40use std::future::Future;
41
42pub mod album;
43#[doc(inline)]
44pub use album::GetAlbumQuery;
45pub mod artist;
46#[doc(inline)]
47pub use artist::{
48    GetArtistAlbumsQuery, GetArtistQuery, SubscribeArtistQuery, UnsubscribeArtistsQuery,
49};
50pub mod continuations;
51#[doc(inline)]
52pub use continuations::GetContinuationsQuery;
53pub mod history;
54#[doc(inline)]
55pub use history::{AddHistoryItemQuery, GetHistoryQuery, RemoveHistoryItemsQuery};
56pub mod library;
57#[doc(inline)]
58pub use library::{
59    EditSongLibraryStatusQuery, GetLibraryAlbumsQuery, GetLibraryArtistSubscriptionsQuery,
60    GetLibraryArtistsQuery, GetLibraryChannelsQuery, GetLibraryPlaylistsQuery,
61    GetLibraryPodcastsQuery, GetLibrarySongsQuery,
62};
63pub mod playlist;
64#[doc(inline)]
65pub use playlist::{
66    AddPlaylistItemsQuery, CreatePlaylistQuery, DeletePlaylistQuery, EditPlaylistQuery,
67    GetPlaylistDetailsQuery, GetPlaylistTracksQuery, GetWatchPlaylistQuery,
68    RemovePlaylistItemsQuery,
69};
70pub mod podcasts;
71#[doc(inline)]
72pub use podcasts::{
73    GetChannelEpisodesQuery, GetChannelQuery, GetEpisodeQuery, GetNewEpisodesQuery, GetPodcastQuery,
74};
75pub mod rate;
76#[doc(inline)]
77pub use rate::{RatePlaylistQuery, RateSongQuery};
78pub mod recommendations;
79#[doc(inline)]
80pub use recommendations::{
81    GetMoodCategoriesQuery, GetMoodPlaylistsQuery, GetTasteProfileQuery, SetTasteProfileQuery,
82};
83pub mod search;
84#[doc(inline)]
85pub use search::{GetSearchSuggestionsQuery, SearchQuery};
86pub mod song;
87#[doc(inline)]
88pub use song::{GetLyricsIDQuery, GetLyricsQuery, GetSongTrackingUrlQuery};
89pub mod upload;
90#[doc(inline)]
91pub use upload::{
92    DeleteUploadEntityQuery, GetLibraryUploadAlbumQuery, GetLibraryUploadAlbumsQuery,
93    GetLibraryUploadArtistQuery, GetLibraryUploadArtistsQuery, GetLibraryUploadSongsQuery,
94};
95pub mod user;
96#[doc(inline)]
97pub use user::{GetUserPlaylistsQuery, GetUserQuery, GetUserVideosQuery};
98
99mod private {
100    pub trait Sealed {}
101}
102
103/// Represents a query that can be passed to Innertube.
104/// The Output associated type describes how to parse a result from the query,
105/// and the Method associated type describes how to call the query.
106pub trait Query<A: AuthToken>: Sized {
107    type Output: ParseFrom<Self>;
108    type Method: QueryMethod<Self, A>;
109}
110
111/// Represents a plain POST query that can be sent to Innertube.
112pub trait PostQuery {
113    fn header(&self) -> serde_json::Map<String, serde_json::Value>;
114    fn params(&self) -> Vec<(&str, Cow<'_, str>)>;
115    fn path(&self) -> &str;
116}
117/// Represents a plain GET query that can be sent to Innertube.
118pub trait GetQuery {
119    fn url(&self) -> &str;
120    fn params(&self) -> Vec<(&str, Cow<'_, str>)>;
121}
122
123/// The GET query method
124pub struct GetMethod;
125/// The POST query method
126pub struct PostMethod;
127
128/// Represents a method of calling an query, using a query, client and auth
129/// token. Not intended to be implemented by api users, the pre-implemented
130/// GetMethod and PostMethod structs should be sufficient, and in addition,
131/// async methods are required currently.
132// Use of async fn in trait is OK here, trait is Sealed.
133#[allow(async_fn_in_trait)]
134pub trait QueryMethod<Q, A>: Sealed
135where
136    A: AuthToken,
137{
138    async fn call<'a>(
139        query: &'a Q,
140        client: &crate::client::Client,
141        tok: &A,
142    ) -> Result<RawResult<'a, Q, A>>;
143}
144
145impl Sealed for GetMethod {}
146impl<Q, A> QueryMethod<Q, A> for GetMethod
147where
148    Q: GetQuery,
149    A: AuthToken,
150{
151    fn call<'a>(
152        query: &'a Q,
153        client: &crate::client::Client,
154        tok: &A,
155    ) -> impl Future<Output = Result<RawResult<'a, Q, A>>>
156    where
157        Self: Sized,
158    {
159        raw_query_get(tok, client, query)
160    }
161}
162
163impl Sealed for PostMethod {}
164impl<Q, A> QueryMethod<Q, A> for PostMethod
165where
166    Q: PostQuery,
167    A: AuthToken,
168{
169    fn call<'a>(
170        query: &'a Q,
171        client: &crate::client::Client,
172        tok: &A,
173    ) -> impl Future<Output = Result<RawResult<'a, Q, A>>>
174    where
175        Self: Sized,
176    {
177        raw_query_post(query, tok, client)
178    }
179}