Compare commits
No commits in common. "2cd74b1da84fa5bcd7a05279c23a9f815ef89e03" and "e4046aef009066c5bb46e184f2a1cf0017503e5b" have entirely different histories.
2cd74b1da8
...
e4046aef00
15 changed files with 19 additions and 271 deletions
|
@ -24,8 +24,8 @@ inspired by [NewPipe](https://github.com/TeamNewPipe/NewPipeExtractor).
|
||||||
- [X] **Artist**
|
- [X] **Artist**
|
||||||
- [X] **Search**
|
- [X] **Search**
|
||||||
- [ ] **Search suggestions**
|
- [ ] **Search suggestions**
|
||||||
- [X] **Radio**
|
- [ ] **Radio**
|
||||||
- [ ] **Track details** (lyrics, recommendations)
|
- [ ] **Track details**
|
||||||
- [ ] **Moods**
|
- [ ] **Moods**
|
||||||
- [ ] **Charts**
|
- [ ] **Charts**
|
||||||
- [ ] **New**
|
- [ ] **New**
|
||||||
|
|
|
@ -50,7 +50,6 @@ pub async fn download_testfiles(project_root: &Path) {
|
||||||
music_search_cont(&testfiles).await;
|
music_search_cont(&testfiles).await;
|
||||||
music_artist(&testfiles).await;
|
music_artist(&testfiles).await;
|
||||||
music_details(&testfiles).await;
|
music_details(&testfiles).await;
|
||||||
music_lyrics(&testfiles).await;
|
|
||||||
music_radio(&testfiles).await;
|
music_radio(&testfiles).await;
|
||||||
music_radio_cont(&testfiles).await;
|
music_radio_cont(&testfiles).await;
|
||||||
}
|
}
|
||||||
|
@ -717,24 +716,6 @@ async fn music_details(testfiles: &Path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn music_lyrics(testfiles: &Path) {
|
|
||||||
let mut json_path = testfiles.to_path_buf();
|
|
||||||
json_path.push("music_details");
|
|
||||||
json_path.push("lyrics.json");
|
|
||||||
if json_path.exists() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rp = RustyPipe::new();
|
|
||||||
let res = rp.query().music_details("n4tK7LYFxI0").await.unwrap();
|
|
||||||
|
|
||||||
let rp = rp_testfile(&json_path);
|
|
||||||
rp.query()
|
|
||||||
.music_lyrics(&res.lyrics_id.unwrap())
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn music_radio(testfiles: &Path) {
|
async fn music_radio(testfiles: &Path) {
|
||||||
for (name, id) in [("mv", "RDAMVMZeerrnuLi5E"), ("track", "RDAMVM7nigXQS1Xb0")] {
|
for (name, id) in [("mv", "RDAMVMZeerrnuLi5E"), ("track", "RDAMVM7nigXQS1Xb0")] {
|
||||||
let mut json_path = testfiles.to_path_buf();
|
let mut json_path = testfiles.to_path_buf();
|
||||||
|
|
|
@ -136,7 +136,7 @@ struct ThirdParty<'a> {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct QBrowse<'a> {
|
struct QBrowse<'a> {
|
||||||
context: YTContext<'a>,
|
context: YTContext<'a>,
|
||||||
browse_id: &'a str,
|
browse_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
@ -990,14 +990,6 @@ impl RustyPipeQuery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a YouTube Music visitor data cookie, which is necessary for certain requests
|
|
||||||
async fn get_ytm_visitor_data(&self) -> Result<String, Error> {
|
|
||||||
match &self.opts.visitor_data {
|
|
||||||
Some(vd) => Ok(vd.to_owned()),
|
|
||||||
None => self.client.get_ytm_visitor_data().await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Execute a request to the YouTube API, then deobfuscate and map the response.
|
/// Execute a request to the YouTube API, then deobfuscate and map the response.
|
||||||
///
|
///
|
||||||
/// Creates a report in case of failure for easy debugging.
|
/// Creates a report in case of failure for easy debugging.
|
||||||
|
|
|
@ -32,13 +32,17 @@ impl RustyPipeQuery {
|
||||||
all_albums: bool,
|
all_albums: bool,
|
||||||
) -> Result<MusicArtist, Error> {
|
) -> Result<MusicArtist, Error> {
|
||||||
if all_albums {
|
if all_albums {
|
||||||
let visitor_data = self.get_ytm_visitor_data().await?;
|
let visitor_data = match &self.opts.visitor_data {
|
||||||
|
Some(vd) => vd.to_owned(),
|
||||||
|
None => self.client.get_ytm_visitor_data().await?,
|
||||||
|
};
|
||||||
|
|
||||||
let context = self
|
let context = self
|
||||||
.get_context(ClientType::DesktopMusic, true, Some(&visitor_data))
|
.get_context(ClientType::DesktopMusic, true, Some(&visitor_data))
|
||||||
.await;
|
.await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
browse_id: artist_id,
|
browse_id: artist_id.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mut artist, album_page_params) = self
|
let (mut artist, album_page_params) = self
|
||||||
|
@ -74,7 +78,7 @@ impl RustyPipeQuery {
|
||||||
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
browse_id: artist_id,
|
browse_id: artist_id.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.execute_request::<response::MusicArtist, _, _>(
|
self.execute_request::<response::MusicArtist, _, _>(
|
||||||
|
|
|
@ -4,14 +4,14 @@ use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, ExtractionError},
|
error::{Error, ExtractionError},
|
||||||
model::{Lyrics, Paginator, TrackDetails, TrackItem},
|
model::{Paginator, TrackDetails, TrackItem},
|
||||||
param::Language,
|
param::Language,
|
||||||
serializer::MapResult,
|
serializer::MapResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
response::{self, music_item::map_queue_item},
|
response::{self, music_item::map_queue_item},
|
||||||
ClientType, MapResponse, QBrowse, RustyPipeQuery, YTContext,
|
ClientType, MapResponse, RustyPipeQuery, YTContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
@ -54,23 +54,6 @@ impl RustyPipeQuery {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn music_lyrics(&self, lyrics_id: &str) -> Result<Lyrics, Error> {
|
|
||||||
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
|
||||||
let request_body = QBrowse {
|
|
||||||
context,
|
|
||||||
browse_id: lyrics_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.execute_request::<response::MusicLyrics, _, _>(
|
|
||||||
ClientType::DesktopMusic,
|
|
||||||
"music_lyrics",
|
|
||||||
lyrics_id,
|
|
||||||
"browse",
|
|
||||||
&request_body,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn music_radio(&self, radio_id: &str) -> Result<Paginator<TrackItem>, Error> {
|
pub async fn music_radio(&self, radio_id: &str) -> Result<Paginator<TrackItem>, Error> {
|
||||||
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
||||||
let request_body = QRadio {
|
let request_body = QRadio {
|
||||||
|
@ -231,31 +214,6 @@ impl MapResponse<Paginator<TrackItem>> for response::MusicDetails {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapResponse<Lyrics> for response::MusicLyrics {
|
|
||||||
fn map_response(
|
|
||||||
self,
|
|
||||||
_id: &str,
|
|
||||||
_lang: Language,
|
|
||||||
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
|
|
||||||
) -> Result<MapResult<Lyrics>, ExtractionError> {
|
|
||||||
let lyrics = self
|
|
||||||
.contents
|
|
||||||
.section_list_renderer
|
|
||||||
.contents
|
|
||||||
.into_iter()
|
|
||||||
.find_map(|item| item.music_description_shelf_renderer)
|
|
||||||
.ok_or(ExtractionError::InvalidData(Cow::Borrowed("no content")))?;
|
|
||||||
|
|
||||||
Ok(MapResult {
|
|
||||||
c: Lyrics {
|
|
||||||
body: lyrics.description,
|
|
||||||
footer: lyrics.footer,
|
|
||||||
},
|
|
||||||
warnings: Vec::new(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{fs::File, io::BufReader, path::Path};
|
use std::{fs::File, io::BufReader, path::Path};
|
||||||
|
@ -306,21 +264,4 @@ mod tests {
|
||||||
);
|
);
|
||||||
insta::assert_ron_snapshot!(format!("map_music_radio_{}", name), map_res.c);
|
insta::assert_ron_snapshot!(format!("map_music_radio_{}", name), map_res.c);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map_lyrics() {
|
|
||||||
let json_path = Path::new("testfiles/music_details/lyrics.json");
|
|
||||||
let json_file = File::open(json_path).unwrap();
|
|
||||||
|
|
||||||
let lyrics: response::MusicLyrics =
|
|
||||||
serde_json::from_reader(BufReader::new(json_file)).unwrap();
|
|
||||||
let map_res: MapResult<Lyrics> = lyrics.map_response("", Language::En, None).unwrap();
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
map_res.warnings.is_empty(),
|
|
||||||
"deserialization/mapping warnings: {:?}",
|
|
||||||
map_res.warnings
|
|
||||||
);
|
|
||||||
insta::assert_ron_snapshot!(format!("map_music_lyrics"), map_res.c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ impl RustyPipeQuery {
|
||||||
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
browse_id: &format!("VL{}", playlist_id),
|
browse_id: "VL".to_owned() + playlist_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.execute_request::<response::MusicPlaylist, _, _>(
|
self.execute_request::<response::MusicPlaylist, _, _>(
|
||||||
|
@ -37,7 +37,7 @@ impl RustyPipeQuery {
|
||||||
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
browse_id: album_id,
|
browse_id: album_id.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.execute_request::<response::MusicPlaylist, _, _>(
|
self.execute_request::<response::MusicPlaylist, _, _>(
|
||||||
|
|
|
@ -18,7 +18,7 @@ impl RustyPipeQuery {
|
||||||
let context = self.get_context(ClientType::Desktop, true, None).await;
|
let context = self.get_context(ClientType::Desktop, true, None).await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
browse_id: &format!("VL{}", playlist_id),
|
browse_id: "VL".to_owned() + playlist_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.execute_request::<response::Playlist, _, _>(
|
self.execute_request::<response::Playlist, _, _>(
|
||||||
|
|
|
@ -16,7 +16,6 @@ pub(crate) use channel::Channel;
|
||||||
pub(crate) use music_artist::MusicArtist;
|
pub(crate) use music_artist::MusicArtist;
|
||||||
pub(crate) use music_artist::MusicArtistAlbums;
|
pub(crate) use music_artist::MusicArtistAlbums;
|
||||||
pub(crate) use music_details::MusicDetails;
|
pub(crate) use music_details::MusicDetails;
|
||||||
pub(crate) use music_details::MusicLyrics;
|
|
||||||
pub(crate) use music_item::MusicContinuation;
|
pub(crate) use music_item::MusicContinuation;
|
||||||
pub(crate) use music_playlist::MusicPlaylist;
|
pub(crate) use music_playlist::MusicPlaylist;
|
||||||
pub(crate) use music_search::MusicSearch;
|
pub(crate) use music_search::MusicSearch;
|
||||||
|
@ -63,12 +62,6 @@ pub(crate) struct Tab<T> {
|
||||||
pub tab_renderer: ContentRenderer<T>,
|
pub tab_renderer: ContentRenderer<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct SectionList<T> {
|
|
||||||
pub section_list_renderer: ContentsRenderer<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Deserialize)]
|
#[derive(Default, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub(crate) struct ThumbnailsWrap {
|
pub(crate) struct ThumbnailsWrap {
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_with::serde_as;
|
|
||||||
|
|
||||||
use crate::serializer::text::Text;
|
use super::{music_item::PlaylistPanelRenderer, ContentRenderer};
|
||||||
|
|
||||||
use super::{music_item::PlaylistPanelRenderer, ContentRenderer, SectionList};
|
|
||||||
|
|
||||||
/// Response model for YouTube Music track details
|
/// Response model for YouTube Music track details
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -94,25 +91,3 @@ pub(crate) struct TabContent {
|
||||||
pub(crate) struct PlaylistPanel {
|
pub(crate) struct PlaylistPanel {
|
||||||
pub playlist_panel_renderer: PlaylistPanelRenderer,
|
pub playlist_panel_renderer: PlaylistPanelRenderer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct MusicLyrics {
|
|
||||||
pub contents: SectionList<LyricsContents>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct LyricsContents {
|
|
||||||
pub music_description_shelf_renderer: Option<LyricsRenderer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub(crate) struct LyricsRenderer {
|
|
||||||
#[serde_as(as = "Text")]
|
|
||||||
pub description: String,
|
|
||||||
#[serde_as(as = "Text")]
|
|
||||||
pub footer: String,
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
source: src/client/music_details.rs
|
|
||||||
expression: map_res.c
|
|
||||||
---
|
|
||||||
Lyrics(
|
|
||||||
body: "Eyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it\'s no use\n\'Cause you can\'t stop it from shining through\nIt\'s true\nBaby let the light shine through\nIf you believe it\'s true\nBaby won\'t you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nWon\'t you let the light shine through\n\nEyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it\'s no use\n\'Cause you can\'t stop it from shining through\nIt\'s true\nBaby let the light shine through\nIf you believe it\'s true\nBaby won\'t you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you",
|
|
||||||
footer: "Source: Musixmatch",
|
|
||||||
)
|
|
|
@ -15,7 +15,7 @@ impl RustyPipeQuery {
|
||||||
let context = self.get_context(ClientType::Desktop, true, None).await;
|
let context = self.get_context(ClientType::Desktop, true, None).await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
browse_id: "FEwhat_to_watch",
|
browse_id: "FEwhat_to_watch".to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.execute_request::<response::Startpage, _, _>(
|
self.execute_request::<response::Startpage, _, _>(
|
||||||
|
@ -32,7 +32,7 @@ impl RustyPipeQuery {
|
||||||
let context = self.get_context(ClientType::Desktop, true, None).await;
|
let context = self.get_context(ClientType::Desktop, true, None).await;
|
||||||
let request_body = QBrowse {
|
let request_body = QBrowse {
|
||||||
context,
|
context,
|
||||||
browse_id: "FEtrending",
|
browse_id: "FEtrending".to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.execute_request::<response::Trending, _, _>(
|
self.execute_request::<response::Trending, _, _>(
|
||||||
|
|
|
@ -1239,10 +1239,3 @@ pub struct TrackDetails {
|
||||||
pub lyrics_id: Option<String>,
|
pub lyrics_id: Option<String>,
|
||||||
pub related_id: Option<String>,
|
pub related_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub struct Lyrics {
|
|
||||||
pub body: String,
|
|
||||||
pub footer: String,
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
{
|
|
||||||
"contents": {
|
|
||||||
"sectionListRenderer": {
|
|
||||||
"contents": [
|
|
||||||
{
|
|
||||||
"musicDescriptionShelfRenderer": {
|
|
||||||
"description": {
|
|
||||||
"runs": [
|
|
||||||
{
|
|
||||||
"text": "Eyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it's no use\n'Cause you can't stop it from shining through\nIt's true\nBaby let the light shine through\nIf you believe it's true\nBaby won't you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nWon't you let the light shine through\n\nEyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it's no use\n'Cause you can't stop it from shining through\nIt's true\nBaby let the light shine through\nIf you believe it's true\nBaby won't you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"footer": {
|
|
||||||
"runs": [
|
|
||||||
{
|
|
||||||
"text": "Source: Musixmatch"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"maxCollapsedLines": 0,
|
|
||||||
"maxExpandedLines": 0,
|
|
||||||
"onShowCommands": [
|
|
||||||
{
|
|
||||||
"clickTrackingParams": "CAIQ2fQEGAAiEwjpyODp3aT7AhUe0REIHV-EAKs=",
|
|
||||||
"logLyricEventCommand": {
|
|
||||||
"serializedLyricInfo": "Eg10X3E4eGptbTdDbEpMGAIiCDE4NTc2OTU0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"trackingParams": "CAIQ2fQEGAAiEwjpyODp3aT7AhUe0REIHV-EAKs="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"trackingParams": "CAEQui8iEwjpyODp3aT7AhUe0REIHV-EAKs="
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responseContext": {
|
|
||||||
"serviceTrackingParams": [
|
|
||||||
{
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "has_unlimited_entitlement",
|
|
||||||
"value": "False"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "browse_id",
|
|
||||||
"value": "MPLYt_q8xjmm7ClJL"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "logged_in",
|
|
||||||
"value": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "e",
|
|
||||||
"value": "1714259,23804281,23848211,23882503,23918597,23934970,23940248,23946420,23966208,23983296,23998056,24001373,24002022,24002025,24004644,24007246,24034168,24036948,24077241,24078244,24080738,24108447,24120819,24135310,24135692,24140247,24147965,24161116,24162920,24164186,24169501,24181174,24185614,24187043,24187377,24191629,24197450,24199724,24200839,24209350,24211178,24216167,24217535,24219713,24228638,24230619,24241378,24248091,24253729,24255165,24255543,24255545,24260783,24262346,24263796,24267564,24267570,24268142,24269410,24278596,24279196,24279852,24281671,24283556,24286005,24286017,24287327,24288043,24290971,24292955,24293803,24295708,24299747,24390374,24390675,24391018,24391537,24392450,24392500,24394549,24396819,24397910,24398998,24399052,24399916,24401557,24402891,24403118,24404641,24406605,24407199,24407665,24409401,24410273,24413557,24413558,24415139,24590921,39322504,39322574"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"service": "GFEEDBACK"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "c",
|
|
||||||
"value": "WEB_REMIX"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "cver",
|
|
||||||
"value": "1.20221107.01.00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "yt_li",
|
|
||||||
"value": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "GetBrowseTrackLyricsPage_rid",
|
|
||||||
"value": "0x8d12ba6a166bab0c"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"service": "CSI"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "client.version",
|
|
||||||
"value": "1.20000101"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "client.name",
|
|
||||||
"value": "WEB_REMIX"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "client.fexp",
|
|
||||||
"value": "24217535,24295708,24590921,24401557,24410273,24120819,24278596,24001373,24290971,24077241,24292955,23848211,24036948,24255545,24286005,24219713,39322504,24279196,24002022,24080738,24413557,23918597,24404641,24209350,39322574,24390675,23940248,24169501,24391018,24002025,24262346,24392500,24396819,24255165,24241378,24279852,24281671,24162920,1714259,24181174,24200839,24034168,24108447,24402891,24216167,24197450,24253729,23998056,24283556,24007246,24403118,24255543,24406605,24161116,24293803,24004644,24230619,24399052,24191629,24211178,24407199,24135310,23882503,24260783,24263796,24391537,24392450,23983296,24415139,24267564,24187043,24409401,24286017,24287327,24399916,23934970,24228638,24398998,24185614,24268142,24394549,24187377,24140247,24164186,24135692,24269410,24288043,24407665,24199724,24390374,24397910,23966208,24267570,24078244,24248091,24147965,24413558,23946420,23804281,24299747"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"service": "ECATCHER"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"visitorData": "Cgs3R19icmhVUkNYOCikibabBg%3D%3D"
|
|
||||||
},
|
|
||||||
"trackingParams": "CAAQhGciEwjpyODp3aT7AhUe0REIHV-EAKs="
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
source: tests/youtube.rs
|
|
||||||
expression: lyrics
|
|
||||||
---
|
|
||||||
Lyrics(
|
|
||||||
body: "Eyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it\'s no use\n\'Cause you can\'t stop it from shining through\nIt\'s true\nBaby let the light shine through\nIf you believe it\'s true\nBaby won\'t you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nWon\'t you let the light shine through\n\nEyes, in the sky, gazing far into the night\nI raise my hand to the fire, but it\'s no use\n\'Cause you can\'t stop it from shining through\nIt\'s true\nBaby let the light shine through\nIf you believe it\'s true\nBaby won\'t you let the light shine through\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you\nFor you",
|
|
||||||
footer: "Source: Musixmatch",
|
|
||||||
)
|
|
|
@ -1769,18 +1769,6 @@ async fn music_details(#[case] name: &str, #[case] id: &str) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn music_lyrics() {
|
|
||||||
let rp = RustyPipe::builder().strict().build();
|
|
||||||
let track = rp.query().music_details("n4tK7LYFxI0").await.unwrap();
|
|
||||||
let lyrics = rp
|
|
||||||
.query()
|
|
||||||
.music_lyrics(&track.lyrics_id.unwrap())
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
insta::assert_ron_snapshot!(lyrics);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn music_radio_track() {
|
async fn music_radio_track() {
|
||||||
let rp = RustyPipe::builder().strict().build();
|
let rp = RustyPipe::builder().strict().build();
|
||||||
|
@ -1796,7 +1784,7 @@ async fn music_radio_playlist() {
|
||||||
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ")
|
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ")
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_next(tracks, &rp.query(), 10, 1).await;
|
assert_next(tracks, &rp.query(), 20, 1).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#TESTUTIL
|
//#TESTUTIL
|
||||||
|
|
Loading…
Reference in a new issue