feat: add support for new artist discography page
This commit is contained in:
parent
bf80db8a9a
commit
c8e2d342c6
25 changed files with 73368 additions and 91615 deletions
|
|
@ -1,6 +1,5 @@
|
|||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use futures::{stream, StreamExt};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
|
||||
|
|
@ -13,7 +12,7 @@ use crate::{
|
|||
|
||||
use super::{
|
||||
response::{self, music_item::MusicListMapper, url_endpoint::PageType},
|
||||
ClientType, MapResponse, QBrowse, QBrowseParams, RustyPipeQuery,
|
||||
ClientType, MapResponse, QBrowse, RustyPipeQuery,
|
||||
};
|
||||
|
||||
impl RustyPipeQuery {
|
||||
|
|
@ -26,99 +25,57 @@ impl RustyPipeQuery {
|
|||
all_albums: bool,
|
||||
) -> Result<MusicArtist, Error> {
|
||||
let artist_id = artist_id.as_ref();
|
||||
let visitor_data = if all_albums {
|
||||
Some(self.get_visitor_data().await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let res = self._music_artist(artist_id, visitor_data.as_deref()).await;
|
||||
let res = self._music_artist(artist_id, all_albums).await;
|
||||
|
||||
if let Err(Error::Extraction(ExtractionError::Redirect(id))) = res {
|
||||
log::debug!("music artist {} redirects to {}", artist_id, &id);
|
||||
self._music_artist(&id, visitor_data.as_deref()).await
|
||||
self._music_artist(&id, all_albums).await
|
||||
} else {
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
async fn _music_artist(
|
||||
&self,
|
||||
artist_id: &str,
|
||||
all_albums_vdata: Option<&str>,
|
||||
) -> Result<MusicArtist, Error> {
|
||||
match all_albums_vdata {
|
||||
Some(visitor_data) => {
|
||||
let context = self
|
||||
.get_context(ClientType::DesktopMusic, true, Some(visitor_data))
|
||||
.await;
|
||||
let request_body = QBrowse {
|
||||
context,
|
||||
browse_id: artist_id,
|
||||
};
|
||||
async fn _music_artist(&self, artist_id: &str, all_albums: bool) -> Result<MusicArtist, Error> {
|
||||
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
||||
let request_body = QBrowse {
|
||||
context,
|
||||
browse_id: artist_id,
|
||||
};
|
||||
|
||||
let (mut artist, album_page_params) = self
|
||||
.execute_request::<response::MusicArtist, _, _>(
|
||||
ClientType::DesktopMusic,
|
||||
"music_artist",
|
||||
artist_id,
|
||||
"browse",
|
||||
&request_body,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let visitor_data = Rc::new(visitor_data);
|
||||
let album_page_results = stream::iter(album_page_params)
|
||||
.map(|params| {
|
||||
let visitor_data = visitor_data.clone();
|
||||
async move {
|
||||
self.music_artist_album_page(artist_id, ¶ms, &visitor_data)
|
||||
.await
|
||||
}
|
||||
})
|
||||
.buffer_unordered(2)
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
|
||||
for res in album_page_results {
|
||||
let mut res = res?;
|
||||
artist.albums.append(&mut res);
|
||||
}
|
||||
|
||||
Ok(artist)
|
||||
}
|
||||
None => {
|
||||
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
||||
let request_body = QBrowse {
|
||||
context,
|
||||
browse_id: artist_id,
|
||||
};
|
||||
|
||||
self.execute_request::<response::MusicArtist, _, _>(
|
||||
if all_albums {
|
||||
let (mut artist, can_fetch_more) = self
|
||||
.execute_request::<response::MusicArtist, _, _>(
|
||||
ClientType::DesktopMusic,
|
||||
"music_artist",
|
||||
artist_id,
|
||||
"browse",
|
||||
&request_body,
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
if can_fetch_more {
|
||||
artist.albums = self.music_artist_albums(artist_id).await?;
|
||||
}
|
||||
|
||||
Ok(artist)
|
||||
} else {
|
||||
self.execute_request::<response::MusicArtist, _, _>(
|
||||
ClientType::DesktopMusic,
|
||||
"music_artist",
|
||||
artist_id,
|
||||
"browse",
|
||||
&request_body,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
async fn music_artist_album_page(
|
||||
&self,
|
||||
artist_id: &str,
|
||||
params: &str,
|
||||
visitor_data: &str,
|
||||
) -> Result<Vec<AlbumItem>, Error> {
|
||||
let context = self
|
||||
.get_context(ClientType::DesktopMusic, true, Some(visitor_data))
|
||||
.await;
|
||||
let request_body = QBrowseParams {
|
||||
/// Get a list of all albums of a YouTube Music artist
|
||||
pub async fn music_artist_albums(&self, artist_id: &str) -> Result<Vec<AlbumItem>, Error> {
|
||||
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
||||
let request_body = QBrowse {
|
||||
context,
|
||||
browse_id: artist_id,
|
||||
params,
|
||||
browse_id: &format!("{}{}", util::ARTIST_DISCOGRAPHY_PREFIX, artist_id),
|
||||
};
|
||||
|
||||
self.execute_request::<response::MusicArtistAlbums, _, _>(
|
||||
|
|
@ -147,13 +104,13 @@ impl MapResponse<MusicArtist> for response::MusicArtist {
|
|||
}
|
||||
}
|
||||
|
||||
impl MapResponse<(MusicArtist, Vec<String>)> for response::MusicArtist {
|
||||
impl MapResponse<(MusicArtist, bool)> for response::MusicArtist {
|
||||
fn map_response(
|
||||
self,
|
||||
id: &str,
|
||||
lang: crate::param::Language,
|
||||
_deobf: Option<&crate::deobfuscate::DeobfData>,
|
||||
) -> Result<MapResult<(MusicArtist, Vec<String>)>, ExtractionError> {
|
||||
) -> Result<MapResult<(MusicArtist, bool)>, ExtractionError> {
|
||||
map_artist_page(self, id, lang, true)
|
||||
}
|
||||
}
|
||||
|
|
@ -163,7 +120,7 @@ fn map_artist_page(
|
|||
id: &str,
|
||||
lang: crate::param::Language,
|
||||
skip_extendables: bool,
|
||||
) -> Result<MapResult<(MusicArtist, Vec<String>)>, ExtractionError> {
|
||||
) -> Result<MapResult<(MusicArtist, bool)>, ExtractionError> {
|
||||
// dbg!(&res);
|
||||
|
||||
let header = res.header.music_immersive_header_renderer;
|
||||
|
|
@ -203,7 +160,7 @@ fn map_artist_page(
|
|||
|
||||
let mut tracks_playlist_id = None;
|
||||
let mut videos_playlist_id = None;
|
||||
let mut album_page_params = Vec::new();
|
||||
let mut can_fetch_more = false;
|
||||
|
||||
for section in sections {
|
||||
match section {
|
||||
|
|
@ -242,6 +199,11 @@ fn map_artist_page(
|
|||
videos_playlist_id = Some(bep.browse_id);
|
||||
}
|
||||
}
|
||||
// Albums
|
||||
PageType::ArtistDiscography => {
|
||||
can_fetch_more = true;
|
||||
extendable_albums = true;
|
||||
}
|
||||
// Albums or playlists
|
||||
PageType::Artist => {
|
||||
// Peek at the first item to determine type
|
||||
|
|
@ -250,7 +212,7 @@ fn map_artist_page(
|
|||
be.browse_endpoint_context_supported_configs.as_ref().map(|config| {
|
||||
config.browse_endpoint_context_music_config.page_type
|
||||
})}) {
|
||||
album_page_params.push(bep.params);
|
||||
can_fetch_more = true;
|
||||
extendable_albums = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -318,7 +280,7 @@ fn map_artist_page(
|
|||
videos_playlist_id,
|
||||
radio_id,
|
||||
},
|
||||
album_page_params,
|
||||
can_fetch_more,
|
||||
),
|
||||
warnings: mapped.warnings,
|
||||
})
|
||||
|
|
@ -333,6 +295,10 @@ impl MapResponse<Vec<AlbumItem>> for response::MusicArtistAlbums {
|
|||
) -> Result<MapResult<Vec<AlbumItem>>, ExtractionError> {
|
||||
// dbg!(&self);
|
||||
|
||||
let Some(header) = self.header else {
|
||||
return Err(ExtractionError::NotFound { id: id.into(), msg: "no header".into() });
|
||||
};
|
||||
|
||||
let grids = self
|
||||
.contents
|
||||
.single_column_browse_results_renderer
|
||||
|
|
@ -349,7 +315,7 @@ impl MapResponse<Vec<AlbumItem>> for response::MusicArtistAlbums {
|
|||
lang,
|
||||
ArtistId {
|
||||
id: Some(id.to_owned()),
|
||||
name: self.header.music_header_renderer.title,
|
||||
name: header.music_header_renderer.title,
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -380,7 +346,6 @@ mod tests {
|
|||
|
||||
#[rstest]
|
||||
#[case::default("default", "UClmXPfaYhXOYsNn_QUyheWQ")]
|
||||
#[case::no_more_albums("no_more_albums", "UC_vmjW5e1xEHhYjY2a0kK1A")]
|
||||
#[case::only_singles("only_singles", "UCfwCE5VhPMGxNPFxtVv7lRw")]
|
||||
#[case::no_artist("no_artist", "UCh8gHdtzO2tXd593_bjErWg")]
|
||||
#[case::only_more_singles("only_more_singles", "UC0aXrjVxG5pZr99v77wZdPQ")]
|
||||
|
|
@ -388,30 +353,27 @@ mod tests {
|
|||
let json_path = path!(*TESTFILES / "music_artist" / format!("artist_{name}.json"));
|
||||
let json_file = File::open(json_path).unwrap();
|
||||
|
||||
let mut album_page_paths = Vec::new();
|
||||
for i in 1..=2 {
|
||||
let json_path = path!(*TESTFILES / "music_artist" / format!("artist_{name}_{i}.json"));
|
||||
if !json_path.exists() {
|
||||
break;
|
||||
}
|
||||
album_page_paths.push(json_path);
|
||||
let mut album_page_path = None;
|
||||
let json_path = path!(*TESTFILES / "music_artist" / format!("artist_{name}_1.json"));
|
||||
if json_path.exists() {
|
||||
album_page_path = Some(json_path);
|
||||
}
|
||||
|
||||
let resp: response::MusicArtist =
|
||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||
let map_res: MapResult<(MusicArtist, Vec<String>)> =
|
||||
let map_res: MapResult<(MusicArtist, bool)> =
|
||||
resp.map_response(id, Language::En, None).unwrap();
|
||||
let (mut artist, album_page_params) = map_res.c;
|
||||
let (mut artist, can_fetch_more) = map_res.c;
|
||||
|
||||
assert!(
|
||||
map_res.warnings.is_empty(),
|
||||
"deserialization/mapping warnings: {:?}",
|
||||
map_res.warnings
|
||||
);
|
||||
assert_eq!(album_page_params.len(), album_page_paths.len());
|
||||
assert_eq!(can_fetch_more, album_page_path.is_some());
|
||||
|
||||
for json_path in album_page_paths {
|
||||
let json_file = File::open(json_path).unwrap();
|
||||
if let Some(album_page_path) = album_page_path {
|
||||
let json_file = File::open(album_page_path).unwrap();
|
||||
let resp: response::MusicArtistAlbums =
|
||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
||||
let mut map_res: MapResult<Vec<AlbumItem>> =
|
||||
|
|
|
|||
|
|
@ -73,9 +73,12 @@ pub(crate) struct ShareEntityEndpoint {
|
|||
}
|
||||
|
||||
/// Response model for YouTube Music artist album page
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct MusicArtistAlbums {
|
||||
pub header: SimpleHeader,
|
||||
#[serde(default)]
|
||||
#[serde_as(as = "DefaultOnError")]
|
||||
pub header: Option<SimpleHeader>,
|
||||
pub contents: SingleColumnBrowseResult<Tab<SectionList<Grid>>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use serde::Deserialize;
|
||||
use serde_with::{serde_as, DefaultOnError};
|
||||
|
||||
use crate::model::UrlTarget;
|
||||
use crate::{model::UrlTarget, util};
|
||||
|
||||
/// navigation/resolve_url response model
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
@ -152,6 +152,8 @@ pub(crate) enum PageType {
|
|||
alias = "MUSIC_PAGE_TYPE_AUDIOBOOK_ARTIST"
|
||||
)]
|
||||
Artist,
|
||||
#[serde(rename = "MUSIC_PAGE_TYPE_ARTIST_DISCOGRAPHY")]
|
||||
ArtistDiscography,
|
||||
#[serde(rename = "MUSIC_PAGE_TYPE_ALBUM", alias = "MUSIC_PAGE_TYPE_AUDIOBOOK")]
|
||||
Album,
|
||||
#[serde(
|
||||
|
|
@ -169,6 +171,9 @@ impl PageType {
|
|||
pub(crate) fn to_url_target(self, id: String) -> Option<UrlTarget> {
|
||||
match self {
|
||||
PageType::Artist | PageType::Channel => Some(UrlTarget::Channel { id }),
|
||||
PageType::ArtistDiscography => id
|
||||
.strip_prefix(util::ARTIST_DISCOGRAPHY_PREFIX)
|
||||
.map(|id| UrlTarget::Channel { id: id.to_owned() }),
|
||||
PageType::Album => Some(UrlTarget::Album { id }),
|
||||
PageType::Playlist => Some(UrlTarget::Playlist { id }),
|
||||
PageType::Unknown => None,
|
||||
|
|
@ -192,7 +197,7 @@ impl From<PageType> for MusicPageType {
|
|||
PageType::Artist => MusicPageType::Artist,
|
||||
PageType::Album => MusicPageType::Album,
|
||||
PageType::Playlist => MusicPageType::Playlist,
|
||||
PageType::Channel => MusicPageType::None,
|
||||
PageType::Channel | PageType::ArtistDiscography => MusicPageType::None,
|
||||
PageType::Unknown => MusicPageType::Unknown,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -7,27 +7,27 @@ MusicArtist(
|
|||
name: "Doobydobap",
|
||||
header_image: [
|
||||
Thumbnail(
|
||||
url: "https://yt3.ggpht.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w540-h225-p-l90-rj",
|
||||
url: "https://yt3.googleusercontent.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w540-h225-p-l90-rj",
|
||||
width: 540,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://yt3.ggpht.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w816-h340-p-l90-rj",
|
||||
url: "https://yt3.googleusercontent.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w816-h340-p-l90-rj",
|
||||
width: 816,
|
||||
height: 340,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://yt3.ggpht.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w1440-h600-p-l90-rj",
|
||||
url: "https://yt3.googleusercontent.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w1440-h600-p-l90-rj",
|
||||
width: 1440,
|
||||
height: 600,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://yt3.ggpht.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w1920-h800-p-l90-rj",
|
||||
url: "https://yt3.googleusercontent.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w1920-h800-p-l90-rj",
|
||||
width: 1920,
|
||||
height: 800,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://yt3.ggpht.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w2436-h1015-p-l90-rj",
|
||||
url: "https://yt3.googleusercontent.com/BvnAqgiursrXpmS9AgDLtkOSTQfOG_Dqn0KzY5hcwO9XrHTEQTVgaflI913f9KRp7d0U2qBp=w2436-h1015-p-l90-rj",
|
||||
width: 2436,
|
||||
height: 1015,
|
||||
),
|
||||
|
|
@ -39,16 +39,82 @@ MusicArtist(
|
|||
albums: [],
|
||||
playlists: [
|
||||
MusicPlaylistItem(
|
||||
id: "PLwkM1QxaP342hjju64dtqG5wKqx2hNgjr",
|
||||
name: "After Hours & Doob Gourmand",
|
||||
id: "PLwkM1QxaP341MxmqdPrw_3ffjqLofZXOj",
|
||||
name: "🌟 best of... doobyvlog",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/38Gd6TdmNVs/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3lbh9XVK3zCkDHMxgOnDokkqE3kwg",
|
||||
url: "https://i.ytimg.com/vi/0onVbAuBGWI/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3mUFLfu6rAMobj83G1P7wFtrbRuqg",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/38Gd6TdmNVs/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3k4lcTkiScLDPpmxBPfEub3xft7iQ",
|
||||
url: "https://i.ytimg.com/vi/0onVbAuBGWI/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3nU_px4mXhplu4zYKhseBKdYUJh0g",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelId(
|
||||
id: "UCh8gHdtzO2tXd593_bjErWg",
|
||||
name: "Doobydobap",
|
||||
)),
|
||||
track_count: None,
|
||||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "PLwkM1QxaP343YqeP6g5VPGsgJdO1_SV4I",
|
||||
name: "love & relationships",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/PXsK9-CFoH4/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3kaG7qOCwpNsPCgSCEoxkeeFW2SUg",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/PXsK9-CFoH4/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3ktLL_rN7UujT_48Np6bSaK0Un1pA",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelId(
|
||||
id: "UCh8gHdtzO2tXd593_bjErWg",
|
||||
name: "Doobydobap",
|
||||
)),
|
||||
track_count: None,
|
||||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "PLwkM1QxaP340xbkARIPpiD1aHuzJVuZUg",
|
||||
name: "🏠 opening a restaurant",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/7ebSD1ezP-M/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3n-xqleEhGCII_Qfza-POZT66c3Tg",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/7ebSD1ezP-M/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3ntBQTkAyTuRhx6HNxBEJtc4RpgWQ",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
channel: Some(ChannelId(
|
||||
id: "UCh8gHdtzO2tXd593_bjErWg",
|
||||
name: "Doobydobap",
|
||||
)),
|
||||
track_count: None,
|
||||
from_ytm: false,
|
||||
),
|
||||
MusicPlaylistItem(
|
||||
id: "PLwkM1QxaP342hjju64dtqG5wKqx2hNgjr",
|
||||
name: "🍽\u{fe0f} after hours & doob gourmand",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/2tg0MNZwUSQ/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3kqvMhctjtDMJ4u84hAp2h5UXT-QA",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/2tg0MNZwUSQ/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3nxfWmvCHZgvWYolc_mlJEWD1TkZQ",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
|
|
@ -62,15 +128,15 @@ MusicArtist(
|
|||
),
|
||||
MusicPlaylistItem(
|
||||
id: "PLwkM1QxaP342v1hhoB3XLiruSQOzmdmBt",
|
||||
name: "doobyvlog",
|
||||
name: "📹 doobyvlog",
|
||||
thumbnail: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/CN-u8_2ixOU/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3kCdNu1hqEubXzcLcci_xhWSI9q-Q",
|
||||
url: "https://i.ytimg.com/vi/7ebSD1ezP-M/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3n-xqleEhGCII_Qfza-POZT66c3Tg",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/CN-u8_2ixOU/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3lN1-hs5ItQ_DJXBp-aUQQ-DLjMVg",
|
||||
url: "https://i.ytimg.com/vi/7ebSD1ezP-M/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3ntBQTkAyTuRhx6HNxBEJtc4RpgWQ",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -34,7 +34,7 @@ MusicArtist(
|
|||
],
|
||||
description: Some("Choi Jin-ri, better known by her stage name Sulli, was a South Korean actress and singer. She first made her debut as a child actress, appearing as a supporting cast member on the SBS historical drama Ballad of Seodong. Following this, she earned a number of guest roles, appearing in the television series Love Needs a Miracle and Drama City, and the film Vacation. She then subsequently appeared in the independent films Punch Lady and BA:BO, the former being her first time cast in a substantial dramatic role.\nAfter signing a record deal with SM Entertainment, Sulli rose to prominence as a member of the girl group f(x) formed in 2009. The group achieved both critical and commercial success, with four Korean number-one singles and international recognition after becoming the first K-pop act to perform at SXSW. Concurrently with her music career, Sulli returned to acting by starring in the SBS romantic comedy series, To the Beautiful You, a Korean adaptation of the shōjo manga Hana-Kimi where her performance was positively received and earned her two SBS Drama Awards and a nomination at the 49th Paeksang Arts Awards.\n\nFrom Wikipedia (https://en.wikipedia.org/wiki/Sulli) under Creative Commons Attribution CC-BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/legalcode)"),
|
||||
wikipedia_url: Some("https://en.wikipedia.org/wiki/Sulli"),
|
||||
subscriber_count: Some(74400),
|
||||
subscriber_count: Some(80800),
|
||||
tracks: [
|
||||
TrackItem(
|
||||
id: "BGcUVJXViqQ",
|
||||
|
|
@ -156,7 +156,7 @@ MusicArtist(
|
|||
],
|
||||
artist_id: Some("UCfwCE5VhPMGxNPFxtVv7lRw"),
|
||||
album: None,
|
||||
view_count: Some(19000000),
|
||||
view_count: Some(20000000),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
|
|
@ -185,7 +185,7 @@ MusicArtist(
|
|||
],
|
||||
artist_id: Some("UClGBYGUZmpzUaHgeb9gOBww"),
|
||||
album: None,
|
||||
view_count: Some(206000),
|
||||
view_count: Some(211000),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
|
|
@ -209,7 +209,7 @@ MusicArtist(
|
|||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCfaO3pZL5XOr8BvNZkrKeVA"),
|
||||
name: "iKissesByMaki",
|
||||
name: "ramuditas",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCfaO3pZL5XOr8BvNZkrKeVA"),
|
||||
|
|
@ -243,152 +243,36 @@ MusicArtist(
|
|||
],
|
||||
artist_id: Some("UCgVWicpO5Jn3VfxqgIU6cpA"),
|
||||
album: None,
|
||||
view_count: Some(3600),
|
||||
view_count: Some(15000),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "94q_2Zsq2os",
|
||||
name: "Sulli - On The Moon (sped up)",
|
||||
id: "N217ZuMQnfY",
|
||||
name: "음악캠프 - Dorothy - Picnic, 도로시 - 소풍, Music Camp 20040417",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/94q_2Zsq2os/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3kf1HgaRExXYDCNGVqeqe-TKxJ2aQ",
|
||||
url: "https://i.ytimg.com/vi/N217ZuMQnfY/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3kBmlxLhMmsi9VLaMVosj6Ie4aAyw",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/94q_2Zsq2os/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3mbke4_Zc9nkj4NvVMlYpA7aSrkzQ",
|
||||
url: "https://i.ytimg.com/vi/N217ZuMQnfY/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3mHxVVuDdgr8HxoJjgtvYwaxtVbzA",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCgVWicpO5Jn3VfxqgIU6cpA"),
|
||||
name: "Jpn Sch",
|
||||
id: Some("UCe52oeb7Xv_KaJsEzcKXJJg"),
|
||||
name: "MBCkpop",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCgVWicpO5Jn3VfxqgIU6cpA"),
|
||||
artist_id: Some("UCe52oeb7Xv_KaJsEzcKXJJg"),
|
||||
album: None,
|
||||
view_count: Some(2900),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "fBce3VihpIQ",
|
||||
name: "sulli - goblin (sped up)",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/fBce3VihpIQ/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3nVd442JLu3mxKbipFglRgRift5cA",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/fBce3VihpIQ/sddefault.jpg?sqp=-oaymwEWCKoDEPABIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3nxWW7AAdAGbEGuDXOVFgFaLW3XbA",
|
||||
width: 426,
|
||||
height: 240,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCwZLmi2q2ReEJvt-8bgVwwg"),
|
||||
name: "e p i l o g u e",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCwZLmi2q2ReEJvt-8bgVwwg"),
|
||||
album: None,
|
||||
view_count: Some(11000),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "0-HXdJc-zDQ",
|
||||
name: "Sulli - Dorothy (sped up)",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/0-HXdJc-zDQ/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3l_Cj2X9UftBVID7UoJ708Dd6UGUA",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/0-HXdJc-zDQ/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3n2XskAJVpE4eQ3okG60Lf6dPPFqQ",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCgVWicpO5Jn3VfxqgIU6cpA"),
|
||||
name: "Jpn Sch",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCgVWicpO5Jn3VfxqgIU6cpA"),
|
||||
album: None,
|
||||
view_count: Some(2200),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "Bae4Fv7GlMY",
|
||||
name: "Sulli\'nin goblin M/V\'sindeki korkutucu detaylar!😱💥",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/Bae4Fv7GlMY/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3nXyTG8uM24-GkmqaUvx2gQqjJO-g",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/Bae4Fv7GlMY/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3m2mg6beaz7Lg-zRFebE5jHHbiiJw",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCuoa8Ie9kA1-AKIjNhsIGxQ"),
|
||||
name: "JenDia` #Emrlsoolarbenim",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCuoa8Ie9kA1-AKIjNhsIGxQ"),
|
||||
album: None,
|
||||
view_count: Some(6900),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "Rq_JkcROjsI",
|
||||
name: "𝗀𝗈𝖻𝗅𝗂𝗇 // 𝗌𝗎𝗅𝗅𝗂 ༄ 𝗌𝗅𝗈𝗐𝖾𝖽 + 𝗋𝖾𝗏𝖾𝗋𝖻",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/Rq_JkcROjsI/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3ntvxfQE8ErdwpxdksKA_Gtcza3Rw",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/Rq_JkcROjsI/sddefault.jpg?sqp=-oaymwEWCKoDEPABIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3kyJ7LFsJWz4Ac44uL8GPxsRldOng",
|
||||
width: 426,
|
||||
height: 240,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCMPqKiPdiSoi8eCW5Dou1IQ"),
|
||||
name: "ᴜᴋɪʏᴏ",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCMPqKiPdiSoi8eCW5Dou1IQ"),
|
||||
album: None,
|
||||
view_count: Some(23000),
|
||||
view_count: Some(1200),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
|
|
@ -417,7 +301,123 @@ MusicArtist(
|
|||
],
|
||||
artist_id: Some("UCFFvwAcyQhpeQfuAgBN1XZw"),
|
||||
album: None,
|
||||
view_count: Some(9900),
|
||||
view_count: Some(12000),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "v5KZ5dalhzU",
|
||||
name: "intp kpop songs (kpop mbti series pt.9)",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/v5KZ5dalhzU/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3nMdCDQ1v-pG312TsgWId2TsMo1zw",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/v5KZ5dalhzU/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3mS7zCcBbRf8t29XGtChWkxd3owMg",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UC_xEL8cbkItBH00KrGz9fbQ"),
|
||||
name: "orbitiny사샤",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UC_xEL8cbkItBH00KrGz9fbQ"),
|
||||
album: None,
|
||||
view_count: Some(7400),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "vaSSdzgDNw0",
|
||||
name: "Goblin~ Sulli English Cover",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/vaSSdzgDNw0/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3lbkZLY174thtujXlmmPqngKOtxvQ",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/vaSSdzgDNw0/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3k5nsO0ap7vTsm8JoihXd9opC9QwA",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCaFqztcJss3HrXNurzQJyqQ"),
|
||||
name: "Bee",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCaFqztcJss3HrXNurzQJyqQ"),
|
||||
album: None,
|
||||
view_count: Some(1400),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "Rq_JkcROjsI",
|
||||
name: "𝗀𝗈𝖻𝗅𝗂𝗇 // 𝗌𝗎𝗅𝗅𝗂 ༄ 𝗌𝗅𝗈𝗐𝖾𝖽 + 𝗋𝖾𝗏𝖾𝗋𝖻",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/Rq_JkcROjsI/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3ntvxfQE8ErdwpxdksKA_Gtcza3Rw",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/Rq_JkcROjsI/sddefault.jpg?sqp=-oaymwEWCKoDEPABIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3kyJ7LFsJWz4Ac44uL8GPxsRldOng",
|
||||
width: 426,
|
||||
height: 240,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCMPqKiPdiSoi8eCW5Dou1IQ"),
|
||||
name: "ᴜᴋɪʏᴏ",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCMPqKiPdiSoi8eCW5Dou1IQ"),
|
||||
album: None,
|
||||
view_count: Some(25000),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
),
|
||||
TrackItem(
|
||||
id: "5VNZWTzJFso",
|
||||
name: "Dorothy - Picnic, 도로시 - 소풍, Music Camp 20040529",
|
||||
duration: None,
|
||||
cover: [
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/5VNZWTzJFso/sddefault.jpg?sqp=-oaymwEWCJADEOEBIAQqCghqEJQEGHgg6AJIWg&rs=AMzJL3niVh6jZ_8X2utHrUst0PgILeoY4g",
|
||||
width: 400,
|
||||
height: 225,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://i.ytimg.com/vi/5VNZWTzJFso/hq720.jpg?sqp=-oaymwEXCKAGEMIDIAQqCwjVARCqCBh4INgESFo&rs=AMzJL3nKv3B3uev0Pg01kUNF_F4GHO39qg",
|
||||
width: 800,
|
||||
height: 450,
|
||||
),
|
||||
],
|
||||
artists: [
|
||||
ArtistId(
|
||||
id: Some("UCe52oeb7Xv_KaJsEzcKXJJg"),
|
||||
name: "MBCkpop",
|
||||
),
|
||||
],
|
||||
artist_id: Some("UCe52oeb7Xv_KaJsEzcKXJJg"),
|
||||
album: None,
|
||||
view_count: Some(3700),
|
||||
is_video: true,
|
||||
track_nr: None,
|
||||
by_va: false,
|
||||
|
|
@ -454,89 +454,21 @@ MusicArtist(
|
|||
playlists: [],
|
||||
similar_artists: [
|
||||
ArtistItem(
|
||||
id: "UCHmZYTfdTyVKQEJicLiXEOg",
|
||||
name: "Red Velvet",
|
||||
id: "UCpUChkP-KE20GRsyfjU83_g",
|
||||
name: "CHUNG HA",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/eGQ0NAW1LeeaD0V0pe5HFg2ENDqn-T4qJfi4zBrLuoMHmEzYEHzT64p95_45UdXWTB6WTMskbzfXNw=w226-h226-p-l90-rj",
|
||||
url: "https://lh3.googleusercontent.com/gfAf1lvXJt_ExLMV0FqnWrTGyAiFpRZW7zeb1ooahA542nBqjLTzcxdhFQtvVWvR0_jzcKOccjIyiFnP=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/eGQ0NAW1LeeaD0V0pe5HFg2ENDqn-T4qJfi4zBrLuoMHmEzYEHzT64p95_45UdXWTB6WTMskbzfXNw=w544-h544-p-l90-rj",
|
||||
url: "https://lh3.googleusercontent.com/gfAf1lvXJt_ExLMV0FqnWrTGyAiFpRZW7zeb1ooahA542nBqjLTzcxdhFQtvVWvR0_jzcKOccjIyiFnP=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(5200000),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCvAUJvMNPy1LLVKpFiu-X9w",
|
||||
name: "SEULGI",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/Gs5_FbRLCCPLjzgZgJ3Rzz9LJ-U4J825o2dTS-JRnEADJEt9qzMENRA52qRdVx8qavapNYsZDJX4jQ=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/Gs5_FbRLCCPLjzgZgJ3Rzz9LJ-U4J825o2dTS-JRnEADJEt9qzMENRA52qRdVx8qavapNYsZDJX4jQ=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(32100),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCyoD3vxUcLLdU1JQ0MMet-Q",
|
||||
name: "Red Velvet - IRENE & SEULGI",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/jwZVdeVkLWjvoi5aXAKbT_ipid5krOyDCo9zGlMLm4uysvbtMwnYWHHemKmCLjM7DcsxNHfouD3caA=w226-h226-p-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/jwZVdeVkLWjvoi5aXAKbT_ipid5krOyDCo9zGlMLm4uysvbtMwnYWHHemKmCLjM7DcsxNHfouD3caA=w544-h544-p-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(34700),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCod8XS1t8Y9JADHv0AWDMLw",
|
||||
name: "Seohyun",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/0uAuF9rHyOlwm18Q0c6DqjLwRzZWqGFwMLWCh5g802HYpy0AVa6VWs1jNmqXhcB-GAMw2fehnrF0P4s=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/0uAuF9rHyOlwm18Q0c6DqjLwRzZWqGFwMLWCh5g802HYpy0AVa6VWs1jNmqXhcB-GAMw2fehnrF0P4s=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(24400),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCOCo09j3eIVdj3HkbJ9c40Q",
|
||||
name: "HYOYEON ",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/N46gjgCRMewGNJBym4Xqa10-GXxo97bcFf_MJeiAxZl2mQpbJn1MWGzzgmYBUG4XUIUlHpkHHrAZlOc=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/N46gjgCRMewGNJBym4Xqa10-GXxo97bcFf_MJeiAxZl2mQpbJn1MWGzzgmYBUG4XUIUlHpkHHrAZlOc=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(133000),
|
||||
subscriber_count: Some(1470000),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCmeskqhmPRuteGVH4yCXT0A",
|
||||
|
|
@ -553,24 +485,7 @@ MusicArtist(
|
|||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(1480000),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCF9KUOyCpRNq67dDKlB0tbw",
|
||||
name: "HA:TFELT",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/9FoZXRMcJp_iIMTqQJ4NHEYumcdwNYN1JfUC2aXUILrRFzbAypG9Yq1r6mMRQzVfDxZ_4OADbruAn5Q=w226-h226-p-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/9FoZXRMcJp_iIMTqQJ4NHEYumcdwNYN1JfUC2aXUILrRFzbAypG9Yq1r6mMRQzVfDxZ_4OADbruAn5Q=w544-h544-p-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(18300),
|
||||
subscriber_count: Some(1490000),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCVXeNwNQs07XQ8d1HtvuxVg",
|
||||
|
|
@ -587,41 +502,126 @@ MusicArtist(
|
|||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(26900),
|
||||
subscriber_count: Some(31400),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCHHz6g3igy0BFUfCSiC_6aw",
|
||||
name: "HyunA",
|
||||
id: "UCvAUJvMNPy1LLVKpFiu-X9w",
|
||||
name: "SEULGI",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/L8EVj7a6sEbbj2oszOtVxQo_pJ6Mm1pIyVWcDXPyaEDynkHBa0yRMsxmfkwKBfPJSGLynsIM-CGjmw=w226-h226-p-l90-rj",
|
||||
url: "https://lh3.googleusercontent.com/NT9GLSF-1zyAb76sixVb9SfMuGef0Dh5aiKODfWt_wWvtGYBnAPs_DcRtOErLw36zYZb4xbsQEzM8ek=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/L8EVj7a6sEbbj2oszOtVxQo_pJ6Mm1pIyVWcDXPyaEDynkHBa0yRMsxmfkwKBfPJSGLynsIM-CGjmw=w544-h544-p-l90-rj",
|
||||
url: "https://lh3.googleusercontent.com/NT9GLSF-1zyAb76sixVb9SfMuGef0Dh5aiKODfWt_wWvtGYBnAPs_DcRtOErLw36zYZb4xbsQEzM8ek=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(3130000),
|
||||
subscriber_count: Some(41100),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCveaR1hvVMrEQaKR6Xl8NDw",
|
||||
name: "f(x)",
|
||||
id: "UC277cpXD9BLeaGgh3yDP40w",
|
||||
name: "블랙스완 BLACKSWAN",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/VQcMudR55EKlNeZCdhQKLy1dh_nojH8YAqwjXPAl515U1hFham1IRGWhcPWITm1X3yUHSQBHUYSWlh0=w226-h226-p-l90-rj",
|
||||
url: "https://lh3.googleusercontent.com/a-/ACB-R5RmPcZVcm8zNXAbprhgqATOJMU6RNbj3OuQyERLHA=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/VQcMudR55EKlNeZCdhQKLy1dh_nojH8YAqwjXPAl515U1hFham1IRGWhcPWITm1X3yUHSQBHUYSWlh0=w544-h544-p-l90-rj",
|
||||
url: "https://lh3.googleusercontent.com/a-/ACB-R5RmPcZVcm8zNXAbprhgqATOJMU6RNbj3OuQyERLHA=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(474000),
|
||||
subscriber_count: Some(603000),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCrt7YUoF7m7PvV_Dt9xWqJQ",
|
||||
name: "LUNA",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/MISR863mLnf03T-2YBEvxYFQPIvPYJ_clea7H5gZhdsN30i8ufw_2NnvOvVxQTOK7-lx_sRW8Q7A5uM=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/MISR863mLnf03T-2YBEvxYFQPIvPYJ_clea7H5gZhdsN30i8ufw_2NnvOvVxQTOK7-lx_sRW8Q7A5uM=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(4510),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCBj8m2FEsjfovt0Fxq0HEJg",
|
||||
name: "Ladies\' Code",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/JC2ZAjp-IUVIStNvPpxgaJknX_WkUZmV1XqLQvJSr-_Kg9_bVfUJi_3DYztbI1ObFA6LejJimJfKdfjp=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/JC2ZAjp-IUVIStNvPpxgaJknX_WkUZmV1XqLQvJSr-_Kg9_bVfUJi_3DYztbI1ObFA6LejJimJfKdfjp=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(11400),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCdhWlMXp2dQBaG5rZS_aSkQ",
|
||||
name: "DAWN",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/a-/ACB-R5QVBnhjI6XKoLtxuTf6LuijMMtJb7e5S2IlOeqo2Q=w226-h226-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/a-/ACB-R5QVBnhjI6XKoLtxuTf6LuijMMtJb7e5S2IlOeqo2Q=w544-h544-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(802000),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCWT2ZfW7d8YI-HinHEVhyCA",
|
||||
name: "(G)I-DLE",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/uZQSZdDnDJCajJtE6Ig9tqgdO7-uogJpdk9TM0p7iEBmnAQXaSGqYET-W-SHTY-NL9UQ2sdOVtIhd54=w226-h226-p-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/uZQSZdDnDJCajJtE6Ig9tqgdO7-uogJpdk9TM0p7iEBmnAQXaSGqYET-W-SHTY-NL9UQ2sdOVtIhd54=w544-h544-p-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(5310000),
|
||||
),
|
||||
ArtistItem(
|
||||
id: "UCOCo09j3eIVdj3HkbJ9c40Q",
|
||||
name: "HYO",
|
||||
avatar: [
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/olRNTvkhjENW-kLcKRg9LQDmWwS3V0KHhTtw4Y8ETFpFLNxlI371_EDh22CtTw0UKgm7YpbGJUUf6nEt=w226-h226-p-l90-rj",
|
||||
width: 226,
|
||||
height: 226,
|
||||
),
|
||||
Thumbnail(
|
||||
url: "https://lh3.googleusercontent.com/olRNTvkhjENW-kLcKRg9LQDmWwS3V0KHhTtw4Y8ETFpFLNxlI371_EDh22CtTw0UKgm7YpbGJUUf6nEt=w544-h544-p-l90-rj",
|
||||
width: 544,
|
||||
height: 544,
|
||||
),
|
||||
],
|
||||
subscriber_count: Some(141000),
|
||||
),
|
||||
],
|
||||
tracks_playlist_id: None,
|
||||
|
|
|
|||
|
|
@ -119,6 +119,14 @@ impl RustyPipeQuery {
|
|||
Ok(UrlTarget::Channel { id: id.to_owned() })
|
||||
} else if util::ALBUM_ID_REGEX.is_match(id) {
|
||||
Ok(UrlTarget::Album { id: id.to_owned() })
|
||||
} else if id
|
||||
.strip_prefix(util::ARTIST_DISCOGRAPHY_PREFIX)
|
||||
.map(|cid| util::CHANNEL_ID_REGEX.is_match(cid))
|
||||
.unwrap_or_default()
|
||||
{
|
||||
Ok(UrlTarget::Channel {
|
||||
id: id[4..].to_owned(),
|
||||
})
|
||||
} else {
|
||||
Err(Error::Other("invalid url: no browse id".into()))
|
||||
}
|
||||
|
|
@ -261,6 +269,14 @@ impl RustyPipeQuery {
|
|||
}
|
||||
} else if util::ALBUM_ID_REGEX.is_match(s) {
|
||||
Ok(UrlTarget::Album { id: s.to_owned() })
|
||||
} else if s
|
||||
.strip_prefix(util::ARTIST_DISCOGRAPHY_PREFIX)
|
||||
.map(|cid| util::CHANNEL_ID_REGEX.is_match(cid))
|
||||
.unwrap_or_default()
|
||||
{
|
||||
Ok(UrlTarget::Channel {
|
||||
id: s[4..].to_owned(),
|
||||
})
|
||||
}
|
||||
// Channel name only
|
||||
else if util::VANITY_PATH_REGEX.is_match(s) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ pub static VANITY_PATH_REGEX: Lazy<Regex> = Lazy::new(|| {
|
|||
pub const DOT_SEPARATOR: &str = " • ";
|
||||
pub const VARIOUS_ARTISTS: &str = "Various Artists";
|
||||
pub const PLAYLIST_ID_ALBUM_PREFIX: &str = "OLAK";
|
||||
pub const ARTIST_DISCOGRAPHY_PREFIX: &str = "MPAD";
|
||||
|
||||
const CONTENT_PLAYBACK_NONCE_ALPHABET: &[u8; 64] =
|
||||
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
|
|
|||
Reference in a new issue