Skip to content

Commit

Permalink
Complete Query implementations, complete test inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
nick42d committed Sep 1, 2024
1 parent 600d6bb commit 85ea237
Show file tree
Hide file tree
Showing 23 changed files with 135,668 additions and 107 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,12 @@ Feature parity with `ytmusicapi`
|DeletePlaylist|[x]||
|AddPlaylistItems|[x]||
|RemovePlaylistItems|[x]||
|GetChannel|[ ]||
|GetChannelEpisodes|[ ]||
|GetPodcast|[ ]|[ ]|
|GetEpisode|[ ]||
|GetEpisodesPlaylist|[ ]||
|GetChannel|[*]||
|GetChannelEpisodes|[*]||
|GetPodcast|[*]|[ ]|
|GetEpisode|[*]||
|GetEpisodesPlaylist|Not Planned*||
|Original: GetNewEpisodes|[*]||
|GetLibraryUploadSongs|[x]|[ ]|
|GetLibraryUploadArtists|[x]|[ ]|
|GetLibraryUploadAlbums|[x]|[ ]|
Expand All @@ -151,6 +152,8 @@ Feature parity with `ytmusicapi`

\* Note, significantly dynamic pages, such as Get Home are not currently planned.

\* GetEpisodesPlaylist is not implemented - it seems the only use case is to get the New Episodes playlist, which has been implemented instead as GetNewEpisodes.

## Developer notes
See the wiki for additional information
https://github.com/nick42d/youtui/wiki
4 changes: 2 additions & 2 deletions youtui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use tracing::info;
use tracing_subscriber::prelude::*;
use ui::WindowContext;
use ui::YoutuiWindow;
use ytmapi_rs::common::{ChannelID, VideoID};
use ytmapi_rs::common::{ArtistChannelID, VideoID};

mod component;
mod keycommand;
Expand Down Expand Up @@ -77,7 +77,7 @@ pub enum AppCallback {
IncreaseVolume(i8),
SearchArtist(String),
GetSearchSuggestions(String),
GetArtistSongs(ChannelID<'static>),
GetArtistSongs(ArtistChannelID<'static>),
AddSongsToPlaylist(Vec<ListSong>),
AddSongsToPlaylistAndPlay(Vec<ListSong>),
PlaySong(Arc<InMemSong>, ListSongID),
Expand Down
6 changes: 3 additions & 3 deletions youtui/src/app/server/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use tokio::{
use tracing::{error, info};
use ytmapi_rs::{
auth::{BrowserToken, OAuthToken},
common::{AlbumID, ChannelID, SearchSuggestion},
common::{AlbumID, ArtistChannelID, SearchSuggestion},
error::ErrorKind,
parse::{AlbumSong, GetAlbum, GetArtistAlbums},
query::{GetAlbumQuery, GetArtistAlbumsQuery},
Expand All @@ -25,7 +25,7 @@ use ytmapi_rs::{
pub enum KillableServerRequest {
GetSearchSuggestions(String),
NewArtistSearch(String),
SearchSelectedArtist(ChannelID<'static>),
SearchSelectedArtist(ArtistChannelID<'static>),
}
#[derive(Debug)]
pub enum UnkillableServerRequest {}
Expand Down Expand Up @@ -290,7 +290,7 @@ async fn get_search_suggestions_task(

async fn search_selected_artist_task(
api: ConcurrentApi,
browse_id: ChannelID<'static>,
browse_id: ArtistChannelID<'static>,
id: TaskID,
tx: Sender<ServerResponse>,
) {
Expand Down
4 changes: 2 additions & 2 deletions youtui/src/app/taskmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::sync::Arc;
use tokio::sync::mpsc;
use tokio::sync::oneshot;
use tracing::{debug, info, warn};
use ytmapi_rs::common::{ChannelID, VideoID};
use ytmapi_rs::common::{ArtistChannelID, VideoID};

const MESSAGE_QUEUE_LENGTH: usize = 256;

Expand Down Expand Up @@ -66,7 +66,7 @@ enum TaskMessage {
pub enum AppRequest {
SearchArtists(String),
GetSearchSuggestions(String),
GetArtistSongs(ChannelID<'static>),
GetArtistSongs(ArtistChannelID<'static>),
Download(VideoID<'static>, ListSongID),
IncreaseVolume(i8),
PlaySong(Arc<InMemSong>, ListSongID),
Expand Down
6 changes: 3 additions & 3 deletions youtui/src/cli/querybuilder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{api::DynamicYtMusic, Command};
use ytmapi_rs::{
auth::{BrowserToken, OAuthToken},
common::{
AlbumID, BrowseParams, ChannelID, FeedbackTokenAddToLibrary,
AlbumID, ArtistChannelID, BrowseParams, FeedbackTokenAddToLibrary,
FeedbackTokenRemoveFromHistory, LikeStatus, MoodCategoryParams, PlaylistID, SetVideoID,
SongTrackingUrl, TasteToken, TasteTokenImpression, TasteTokenSelection, UploadAlbumID,
UploadArtistID, UploadEntityID, VideoID, YoutubeID,
Expand Down Expand Up @@ -50,7 +50,7 @@ pub async fn command_to_query(
Command::GetArtist { channel_id } => {
get_string_output_of_query(
yt,
GetArtistQuery::new(ChannelID::from_raw(channel_id)),
GetArtistQuery::new(ArtistChannelID::from_raw(channel_id)),
cli_query,
)
.await
Expand All @@ -70,7 +70,7 @@ pub async fn command_to_query(
get_string_output_of_query(
yt,
GetArtistAlbumsQuery::new(
ChannelID::from_raw(channel_id),
ArtistChannelID::from_raw(channel_id),
BrowseParams::from_raw(browse_params),
),
cli_query,
Expand Down
7 changes: 5 additions & 2 deletions ytmapi-rs/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ pub struct PlaylistID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct AlbumID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct ChannelID<'a>(Cow<'a, str>);
pub struct ArtistChannelID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct PodcastChannelID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct ProfileID<'a>(Cow<'a, str>);
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -186,7 +188,8 @@ impl_youtube_id!(ProfileID<'a>);
impl_youtube_id!(PodcastID<'a>);
impl_youtube_id!(VideoID<'a>);
impl_youtube_id!(PlaylistID<'a>);
impl_youtube_id!(ChannelID<'a>);
impl_youtube_id!(ArtistChannelID<'a>);
impl_youtube_id!(PodcastChannelID<'a>);
impl_youtube_id!(LyricsID<'a>);
impl_youtube_id!(BrowseParams<'a>);
impl_youtube_id!(PodcastChannelParams<'a>);
Expand Down
4 changes: 2 additions & 2 deletions ytmapi-rs/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//! `From<ProcessedResult> for JsonCrawlerOwned` implementation.
use crate::{
auth::AuthToken,
common::{AlbumID, ChannelID, Thumbnail},
common::{AlbumID, ArtistChannelID, Thumbnail},
error,
json::Json,
nav_consts::*,
Expand Down Expand Up @@ -83,7 +83,7 @@ pub enum EpisodeDuration {
// Intentionally not marked non_exhaustive - not expecting this to change.
pub struct ParsedSongArtist {
pub name: String,
pub id: Option<ChannelID<'static>>,
pub id: Option<ArtistChannelID<'static>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
// Intentionally not marked non_exhaustive - not expecting this to change.
Expand Down
16 changes: 8 additions & 8 deletions ytmapi-rs/src/parse/artist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::{
};
use crate::{
common::{
AlbumID, AlbumType, BrowseParams, ChannelID, Explicit, LibraryManager, LibraryStatus,
AlbumID, AlbumType, ArtistChannelID, BrowseParams, Explicit, LibraryManager, LibraryStatus,
LikeStatus, PlaylistID, UploadEntityID, VideoID,
},
nav_consts::*,
Expand Down Expand Up @@ -138,7 +138,7 @@ impl<'a> ParseFrom<GetArtistQuery<'a>> for ArtistParams {
let category = r.take_value_pointer(concatcp!(CAROUSEL_TITLE, "/text"))?;
// Likely optional, need to confirm.
// XXX: Errors here
let browse_id: Option<ChannelID> = r
let browse_id: Option<ArtistChannelID> = r
.take_value_pointer(concatcp!(CAROUSEL_TITLE, NAVIGATION_BROWSE_ID))
.ok();
// XXX should only be mandatory for albums, singles, playlists
Expand Down Expand Up @@ -265,13 +265,13 @@ pub struct GetArtistVideos {
pub struct GetArtistAlbums {
pub results: Vec<AlbumResult>,
// XXX: Unsure if AlbumID is correct here.
pub browse_id: Option<ChannelID<'static>>,
pub browse_id: Option<ArtistChannelID<'static>>,
pub params: Option<BrowseParams<'static>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[non_exhaustive]
pub struct RelatedResult {
pub browse_id: ChannelID<'static>,
pub browse_id: ArtistChannelID<'static>,
pub title: String,
pub subscribers: String,
}
Expand Down Expand Up @@ -319,7 +319,7 @@ pub struct PlaylistVideo {
pub title: String,
// Could be 'ParsedVideoChannel'
pub channel_name: String,
pub channel_id: ChannelID<'static>,
pub channel_id: ArtistChannelID<'static>,
// TODO: Song like feedback tokens.
pub like_status: LikeStatus,
pub thumbnails: Vec<Thumbnail>,
Expand Down Expand Up @@ -723,7 +723,7 @@ impl<'a> ParseFrom<GetArtistAlbumsQuery<'a>> for Vec<GetArtistAlbumsAlbum> {
}
#[cfg(test)]
mod tests {
use crate::common::ChannelID;
use crate::common::ArtistChannelID;
use crate::{
auth::BrowserToken,
common::{BrowseParams, YoutubeID},
Expand All @@ -736,7 +736,7 @@ mod tests {
// Radiohead's albums.
"./test_json/browse_artist_albums.json",
"./test_json/browse_artist_albums_output.txt",
GetArtistAlbumsQuery::new(ChannelID::from_raw(""), BrowseParams::from_raw("")),
GetArtistAlbumsQuery::new(ArtistChannelID::from_raw(""), BrowseParams::from_raw("")),
BrowserToken
);
}
Expand All @@ -746,7 +746,7 @@ mod tests {
parse_test!(
"./test_json/get_artist_20240705.json",
"./test_json/get_artist_20240705_output.txt",
crate::query::GetArtistQuery::new(ChannelID::from_raw("")),
crate::query::GetArtistQuery::new(ArtistChannelID::from_raw("")),
BrowserToken
);
}
Expand Down
4 changes: 2 additions & 2 deletions ytmapi-rs/src/parse/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::{
};
use crate::{
common::{
ApiOutcome, ChannelID, Explicit, FeedbackTokenRemoveFromHistory, LibraryManager,
ApiOutcome, ArtistChannelID, Explicit, FeedbackTokenRemoveFromHistory, LibraryManager,
LikeStatus, PlaylistID, Thumbnail, UploadEntityID, VideoID,
},
nav_consts::{
Expand Down Expand Up @@ -70,7 +70,7 @@ pub struct HistoryItemVideo {
pub title: String,
// Could be 'ParsedVideoChannel'
pub channel_name: String,
pub channel_id: ChannelID<'static>,
pub channel_id: ArtistChannelID<'static>,
// TODO: Song like feedback tokens.
pub like_status: LikeStatus,
pub thumbnails: Vec<super::Thumbnail>,
Expand Down
6 changes: 3 additions & 3 deletions ytmapi-rs/src/parse/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::{
SearchResultAlbum, TableListSong, BADGE_LABEL, MENU_LIKE_STATUS, SUBTITLE, SUBTITLE2,
SUBTITLE3, SUBTITLE_BADGE_LABEL, THUMBNAILS,
};
use crate::common::{ApiOutcome, ChannelID, Explicit, PlaylistID, Thumbnail};
use crate::common::{ApiOutcome, ArtistChannelID, Explicit, PlaylistID, Thumbnail};
use crate::nav_consts::{
GRID, GRID_ITEMS, ITEM_SECTION, MENU_ITEMS, MRLIR, MTRIR, MUSIC_SHELF, NAVIGATION_BROWSE_ID,
NAVIGATION_PLAYLIST_ID, PLAY_BUTTON, SECTION_LIST, SECTION_LIST_ITEM, SINGLE_COLUMN_TAB,
Expand All @@ -25,7 +25,7 @@ use serde::{Deserialize, Serialize};
pub struct GetLibraryArtistSubscription {
pub name: String,
pub subscribers: String,
pub channel_id: ChannelID<'static>,
pub channel_id: ArtistChannelID<'static>,
pub thumbnails: Vec<Thumbnail>,
}

Expand All @@ -42,7 +42,7 @@ pub struct LibraryPlaylist {
#[derive(PartialEq, Debug, Clone, Deserialize, Serialize)]
#[non_exhaustive]
pub struct LibraryArtist {
pub channel_id: ChannelID<'static>,
pub channel_id: ArtistChannelID<'static>,
pub artist: String,
pub byline: String, // e.g 16 songs or 17.8k subscribers
}
Expand Down
45 changes: 25 additions & 20 deletions ytmapi-rs/src/parse/podcasts.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use super::ParseFrom;
use crate::query::{
GetChannelEpisodesQuery, GetChannelQuery, GetEpisodeQuery, GetEpisodesPlaylistQuery,
GetPodcastQuery,
GetChannelEpisodesQuery, GetChannelQuery, GetEpisodeQuery, GetNewEpisodesQuery, GetPodcastQuery,
};

impl ParseFrom<GetChannelQuery> for () {
// NOTE: This is technically the same page as the GetArtist page. It's possible
// this could be generalised.
impl<'a> ParseFrom<GetChannelQuery<'a>> for () {
fn parse_from(p: crate::ProcessedResult<GetChannelQuery>) -> crate::Result<Self> {
todo!()
}
Expand All @@ -14,18 +15,18 @@ impl<'a> ParseFrom<GetChannelEpisodesQuery<'a>> for () {
todo!()
}
}
impl ParseFrom<GetPodcastQuery> for () {
impl<'a> ParseFrom<GetPodcastQuery<'a>> for () {
fn parse_from(p: crate::ProcessedResult<GetPodcastQuery>) -> crate::Result<Self> {
todo!()
}
}
impl ParseFrom<GetEpisodeQuery> for () {
impl<'a> ParseFrom<GetEpisodeQuery<'a>> for () {
fn parse_from(p: crate::ProcessedResult<GetEpisodeQuery>) -> crate::Result<Self> {
todo!()
}
}
impl ParseFrom<GetEpisodesPlaylistQuery> for () {
fn parse_from(p: crate::ProcessedResult<GetEpisodesPlaylistQuery>) -> crate::Result<Self> {
impl ParseFrom<GetNewEpisodesQuery> for () {
fn parse_from(p: crate::ProcessedResult<GetNewEpisodesQuery>) -> crate::Result<Self> {
todo!()
}
}
Expand All @@ -34,18 +35,19 @@ impl ParseFrom<GetEpisodesPlaylistQuery> for () {
mod tests {
use crate::{
auth::BrowserToken,
common::{PodcastChannelID, PodcastChannelParams, PodcastID, VideoID, YoutubeID},
query::{
GetChannelEpisodesQuery, GetChannelQuery, GetEpisodeQuery, GetEpisodesPlaylistQuery,
GetChannelEpisodesQuery, GetChannelQuery, GetEpisodeQuery, GetNewEpisodesQuery,
GetPodcastQuery,
},
};

#[tokio::test]
async fn test_get_channel() {
parse_test_value!(
parse_test!(
"./test_json/get_channel_20240830.json",
"./test_json/get_channel_20240830_output.txt",
GetChannelQuery::new(),
GetChannelQuery::new(PodcastChannelID::from_raw("")),
BrowserToken
);
}
Expand All @@ -54,34 +56,37 @@ mod tests {
parse_test!(
"./test_json/get_channel_episodes_20240830.json",
"./test_json/get_channel_episodes_20240830_output.txt",
GetChannelEpisodesQuery::new(),
GetChannelEpisodesQuery::new(
PodcastChannelID::from_raw(""),
PodcastChannelParams::from_raw("")
),
BrowserToken
);
}
#[tokio::test]
async fn test_get_podcast() {
parse_test_value!(
parse_test!(
"./test_json/get_podcast_20240830.json",
"./test_json/get_podcast_20240830_output.txt",
GetPodcastQuery::new(),
GetPodcastQuery::new(PodcastID::from_raw("")),
BrowserToken
);
}
#[tokio::test]
async fn test_get_episode() {
parse_test_value!(
parse_test!(
"./test_json/get_episode_20240830.json",
"./test_json/get_episode_20240830_output.txt",
GetEpisodeQuery::new(),
GetEpisodeQuery::new(VideoID::from_raw("")),
BrowserToken
);
}
#[tokio::test]
async fn test_get_episodes_playlist() {
parse_test_value!(
"./test_json/get_episodes_playlist_20240830.json",
"./test_json/get_episodes_playlist_20240830_output.txt",
GetEpisodesPlaylistQuery::new(),
async fn test_get_new_episodes() {
parse_test!(
"./test_json/get_new_episodes_20240830.json",
"./test_json/get_new_episodes_20240830_output.txt",
GetNewEpisodesQuery,
BrowserToken
);
}
Expand Down
6 changes: 3 additions & 3 deletions ytmapi-rs/src/parse/search.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{parse_flex_column_item, ParseFrom, ProcessedResult, DISPLAY_POLICY};
use crate::common::{
AlbumID, AlbumType, ChannelID, Explicit, PlaylistID, PodcastID, ProfileID, SearchSuggestion,
SuggestionType, TextRun, Thumbnail, VideoID,
AlbumID, AlbumType, ArtistChannelID, Explicit, PlaylistID, PodcastID, ProfileID,
SearchSuggestion, SuggestionType, TextRun, Thumbnail, VideoID,
};
use crate::nav_consts::{
BADGE_LABEL, LIVE_BADGE_LABEL, MUSIC_CARD_SHELF, MUSIC_SHELF, NAVIGATION_BROWSE_ID,
Expand Down Expand Up @@ -96,7 +96,7 @@ pub struct SearchResultArtist {
pub artist: String,
/// An artist with no subscribers won't contain this field.
pub subscribers: Option<String>,
pub browse_id: ChannelID<'static>,
pub browse_id: ArtistChannelID<'static>,
pub thumbnails: Vec<Thumbnail>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
Expand Down
Loading

0 comments on commit 85ea237

Please sign in to comment.