musixmatch-inofficial/tests/tests.rs

1055 lines
34 KiB
Rust

use std::{
num::NonZeroU32,
path::{Path, PathBuf},
sync::LazyLock,
};
use governor::{DefaultDirectRateLimiter, Quota, RateLimiter};
use path_macro::path;
use rstest::{fixture, rstest};
use time::macros::{date, datetime};
use musixmatch_inofficial::{
models::{AlbumId, ArtistId, TrackId},
Error, Musixmatch,
};
fn testfile<P: AsRef<Path>>(name: P) -> PathBuf {
path!(env!("CARGO_MANIFEST_DIR") / "testfiles" / name)
}
#[fixture]
async fn mxm() -> Musixmatch {
static LOGIN_LOCK: tokio::sync::OnceCell<()> = tokio::sync::OnceCell::const_new();
static MXM_LIMITER: LazyLock<DefaultDirectRateLimiter> =
LazyLock::new(|| RateLimiter::direct(Quota::per_second(NonZeroU32::new(1).unwrap())));
MXM_LIMITER.until_ready().await;
let mut mxm = Musixmatch::builder();
if let (Ok(email), Ok(password)) = (
std::env::var("MUSIXMATCH_EMAIL"),
std::env::var("MUSIXMATCH_PASSWORD"),
) {
mxm = mxm.credentials(email, password);
}
let mxm = mxm.build().unwrap();
LOGIN_LOCK.get_or_try_init(|| mxm.login()).await.unwrap();
mxm
}
mod album {
use super::*;
use musixmatch_inofficial::models::AlbumType;
#[rstest]
#[case::id(AlbumId::AlbumId(14248253))]
#[case::musicbrainz(AlbumId::Musicbrainz("6c3cf9d8-88a8-43ed-850b-55813f01e451"))]
#[tokio::test]
async fn by_id(#[case] album_id: AlbumId<'_>, #[future] mxm: Musixmatch) {
let album = mxm.await.album(album_id).await.unwrap();
assert_eq!(album.album_id, 14248253);
assert_eq!(
album.album_mbid.unwrap(),
"6c3cf9d8-88a8-43ed-850b-55813f01e451"
);
assert_eq!(album.album_name, "Gangnam Style (강남스타일)");
assert!(album.album_rating > 20);
assert_eq!(album.album_track_count, 0);
assert_eq!(album.album_release_date.unwrap(), date!(2012 - 01 - 01));
assert_eq!(album.album_release_type, AlbumType::Single);
assert_eq!(album.artist_id, 410698);
assert_eq!(album.artist_name, "PSY");
let first_pri_genre = &album.primary_genres.music_genre_list[0].music_genre;
assert_eq!(first_pri_genre.music_genre_id, 14);
assert_eq!(first_pri_genre.music_genre_parent_id, 34);
assert_eq!(first_pri_genre.music_genre_name, "Pop");
assert_eq!(first_pri_genre.music_genre_name_extended, "Pop");
assert_eq!(first_pri_genre.music_genre_vanity.as_ref().unwrap(), "Pop");
let first_sec_genre = &album.secondary_genres.music_genre_list[0].music_genre;
assert_eq!(first_sec_genre.music_genre_id, 17);
assert_eq!(first_sec_genre.music_genre_parent_id, 34);
assert_eq!(first_sec_genre.music_genre_name, "Dance");
assert_eq!(first_sec_genre.music_genre_name_extended, "Dance");
assert_eq!(
first_sec_genre.music_genre_vanity.as_ref().unwrap(),
"Dance"
);
assert_eq!(
album.album_copyright.unwrap(),
"© 2012 Schoolboy/Universal Republic Records, a division of UMG Recordings, Inc."
);
assert_eq!(
album.album_label.unwrap(),
"Silent Records/Universal Republic Records"
);
assert_eq!(album.album_vanity_id, "410698/Gangnam-Style-Single");
assert!(album.updated_time > datetime!(2022-6-3 0:00 UTC));
assert_imgurl(&album.album_coverart_100x100, "/26544045.jpg");
assert_imgurl(&album.album_coverart_350x350, "/26544045_350_350.jpg");
assert_imgurl(&album.album_coverart_500x500, "/26544045_500_500.jpg");
}
#[rstest]
#[tokio::test]
async fn album_ep(#[future] mxm: Musixmatch) {
let album = mxm.await.album(AlbumId::AlbumId(23976123)).await.unwrap();
assert_eq!(album.album_name, "Waldbrand EP");
// assert_eq!(album.album_release_type, AlbumType::Ep);
assert_eq!(album.album_release_date, Some(date!(2016 - 09 - 30)));
}
#[rstest]
#[tokio::test]
async fn by_id_missing(#[future] mxm: Musixmatch) {
let err = mxm
.await
.album(AlbumId::AlbumId(999999999999))
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
#[rstest]
#[tokio::test]
#[ignore]
async fn artist_albums(#[future] mxm: Musixmatch) {
let albums = mxm
.await
.artist_albums(ArtistId::ArtistId(1039), None, 10, 1)
.await
.unwrap();
assert_eq!(albums.len(), 10);
}
#[rstest]
#[tokio::test]
async fn artist_albums_missing(#[future] mxm: Musixmatch) {
let err = mxm
.await
.artist_albums(ArtistId::ArtistId(999999999999), None, 10, 1)
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
#[rstest]
#[tokio::test]
async fn charts(#[future] mxm: Musixmatch) {
let albums = mxm.await.chart_albums("US", 10, 1).await.unwrap();
assert_eq!(albums.len(), 10);
}
}
mod artist {
use super::*;
#[rstest]
#[case::id(ArtistId::ArtistId(410698))]
#[case::musicbrainz(ArtistId::Musicbrainz("f99b7d67-4e63-4678-aa66-4c6ac0f7d24a"))]
#[tokio::test]
async fn by_id(#[case] artist_id: ArtistId<'_>, #[future] mxm: Musixmatch) {
let artist = mxm.await.artist(artist_id).await.unwrap();
// dbg!(&artist);
assert_eq!(artist.artist_id, 410698);
assert_eq!(
artist.artist_mbid.unwrap(),
"f99b7d67-4e63-4678-aa66-4c6ac0f7d24a"
);
assert_eq!(artist.artist_name, "PSY");
assert!(
artist.artist_name_translation_list.iter().any(|tl| {
tl.artist_name_translation.language == "KO"
&& tl.artist_name_translation.translation == "싸이"
}),
"missing Korean translation in: {:?}",
artist.artist_name_translation_list
);
assert_eq!(artist.artist_country.unwrap(), "KR");
assert!(artist.artist_rating > 50);
let first_genre = &artist.primary_genres.music_genre_list[0].music_genre;
assert_eq!(first_genre.music_genre_id, 14);
assert_eq!(first_genre.music_genre_parent_id, 34);
assert_eq!(first_genre.music_genre_name, "Pop");
assert_eq!(first_genre.music_genre_name_extended, "Pop");
assert_eq!(first_genre.music_genre_vanity.as_ref().unwrap(), "Pop");
assert_eq!(
artist.artist_twitter_url.unwrap(),
"https://twitter.com/psy_oppa"
);
assert_eq!(
artist.artist_facebook_url.unwrap(),
"https://www.facebook.com/officialpsy"
);
assert_eq!(artist.artist_vanity_id, "410698");
assert!(artist.updated_time > datetime!(2016-6-30 0:00 UTC));
assert_eq!(artist.begin_date_year.unwrap(), 1977);
assert_eq!(artist.begin_date.unwrap(), date!(1977 - 12 - 31));
assert_eq!(artist.end_date_year, None);
assert_eq!(artist.end_date, None);
}
#[rstest]
#[tokio::test]
async fn by_id_missing(#[future] mxm: Musixmatch) {
let err = mxm
.await
.artist(ArtistId::ArtistId(999999999999))
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
#[rstest]
#[tokio::test]
async fn related(#[future] mxm: Musixmatch) {
let artists = mxm
.await
.artist_related(ArtistId::ArtistId(26485840), 10, 1)
.await
.unwrap();
assert_eq!(artists.len(), 10);
}
#[rstest]
#[tokio::test]
async fn related_missing(#[future] mxm: Musixmatch) {
let err = mxm
.await
.artist_related(ArtistId::ArtistId(999999999999), 10, 1)
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
#[rstest]
#[tokio::test]
async fn search(#[future] mxm: Musixmatch) {
let artists = mxm
.await
.artist_search("Snollebollekes", 5, 1)
.await
.unwrap();
let artist = &artists[0];
assert_eq!(artist.artist_id, 25344078);
assert_eq!(artist.artist_name, "Snollebollekes");
}
#[rstest]
#[tokio::test]
async fn search_empty(#[future] mxm: Musixmatch) {
let artists = mxm
.await
.artist_search(
"Rindfleischettikettierungsüberwachungsaufgabenübertragungsgesetz",
5,
1,
)
.await
.unwrap();
assert_eq!(artists.len(), 0);
}
#[rstest]
#[tokio::test]
async fn charts(#[future] mxm: Musixmatch) {
let artists = mxm.await.chart_artists("US", 10, 1).await.unwrap();
assert_eq!(artists.len(), 10);
}
#[rstest]
#[tokio::test]
async fn charts_no_country(#[future] mxm: Musixmatch) {
let artists = mxm.await.chart_artists("XY", 10, 1).await.unwrap();
assert_eq!(artists.len(), 10);
}
}
mod track {
use super::*;
use musixmatch_inofficial::models::{ChartName, SortOrder};
#[rstest]
#[case::no_translation(false, false)]
#[case::translation_2c(true, false)]
#[case::translation_3c(true, true)]
#[tokio::test]
async fn from_match(
#[case] translation_status: bool,
#[case] lang_3c: bool,
#[future] mxm: Musixmatch,
) {
let track = mxm
.await
.matcher_track(
"Poker Face",
"Lady Gaga",
"The Fame",
translation_status,
lang_3c,
)
.await
.unwrap();
// dbg!(&track);
assert_eq!(track.track_id, 85213841);
// assert_eq!(
// track.track_mbid.unwrap(),
// "080975b0-39b1-493c-ae64-5cb3292409bb"
// );
// assert_eq!(track.track_isrc.unwrap(), "USUM70824409");
assert!(
track.commontrack_isrcs[0]
.iter()
.any(|isrc| isrc == "USUM70824409"),
"commontrack_isrcs: {:?}",
&track.commontrack_isrcs[0],
);
assert_eq!(track.track_spotify_id.unwrap(), "1QV6tiMFM6fSOKOGLMHYYg");
assert!(
track
.commontrack_spotify_ids
.iter()
.any(|spid| spid == "1QV6tiMFM6fSOKOGLMHYYg"),
"commontrack_spotify_ids: {:?}",
track.commontrack_spotify_ids,
);
assert_eq!(track.track_name, "Poker Face");
assert!(track.track_rating > 50);
assert_eq!(track.commontrack_id, 47672612);
assert!(!track.instrumental);
assert!(track.explicit);
assert!(track.has_subtitles);
assert!(track.has_richsync);
assert!(track.has_track_structure);
assert!(track.num_favourite > 50);
assert!(track.lyrics_id.is_some());
assert_eq!(track.subtitle_id.unwrap(), 36450705);
assert_eq!(track.album_id, 20960801);
assert_eq!(track.album_name, "The Fame");
assert_eq!(track.artist_id, 378462);
assert_eq!(
track.artist_mbid.unwrap(),
"650e7db6-b795-4eb5-a702-5ea2fc46c848"
);
assert_eq!(track.artist_name, "Lady Gaga");
assert_imgurl(&track.album_coverart_100x100, "/32133892.jpg");
assert_imgurl(&track.album_coverart_350x350, "/32133892_350_350.jpg");
assert_imgurl(&track.album_coverart_500x500, "/32133892_500_500.jpg");
assert_imgurl(&track.album_coverart_800x800, "/32133892_800_800.jpg");
assert_eq!(track.commontrack_vanity_id, "Lady-Gaga/poker-face-1");
let first_release = track.first_release_date.unwrap();
assert_eq!(first_release.date(), date!(2008 - 1 - 1));
assert!(track.updated_time > datetime!(2023-1-17 0:00 UTC));
let first_pri_genre = &track.primary_genres.music_genre_list[0].music_genre;
assert_eq!(first_pri_genre.music_genre_id, 14);
assert_eq!(first_pri_genre.music_genre_parent_id, 34);
assert_eq!(first_pri_genre.music_genre_name, "Pop");
assert_eq!(first_pri_genre.music_genre_name_extended, "Pop");
assert_eq!(first_pri_genre.music_genre_vanity.as_ref().unwrap(), "Pop");
let first_sec_genre = &track.secondary_genres.music_genre_list[0].music_genre;
assert_eq!(first_sec_genre.music_genre_id, 17);
assert_eq!(first_sec_genre.music_genre_parent_id, 34);
assert_eq!(first_sec_genre.music_genre_name, "Dance");
assert_eq!(first_sec_genre.music_genre_name_extended, "Dance");
assert_eq!(
first_sec_genre.music_genre_vanity.as_ref().unwrap(),
"Dance"
);
if translation_status {
assert!(
track.track_lyrics_translation_status.iter().all(|tl| {
(if lang_3c {
tl.from.as_deref() == Some("eng")
} else {
tl.from.as_deref() == Some("en")
}) && tl.perc >= 0.0
&& tl.perc <= 1.0
}),
"translation: {:?}",
track.track_lyrics_translation_status
);
} else {
assert!(track.track_lyrics_translation_status.is_empty())
}
}
#[rstest]
#[case::trackid(TrackId::TrackId(205688271))]
#[case::commontrack(TrackId::Commontrack(118480583))]
#[case::vanity(TrackId::CommontrackVanity("aespa/Black-Mamba".into()))]
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
#[tokio::test]
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
let track = mxm.await.track(track_id, true, false).await.unwrap();
// dbg!(&track);
assert_eq!(track.track_id, 205688271);
assert_eq!(track.track_isrc.unwrap(), "KRA302000590");
assert_eq!(track.track_spotify_id.unwrap(), "1t2qYCAjUAoGfeFeoBlK51");
assert_eq!(track.track_name, "Black Mamba");
assert!(track.track_rating > 50);
assert_eq!(track.track_length, 175);
assert!(!track.explicit);
assert!(track.has_lyrics);
assert!(track.has_subtitles);
assert!(track.has_richsync);
assert!(track.num_favourite > 200);
assert!(track.lyrics_id.is_some());
assert_eq!(track.subtitle_id.unwrap(), 36476905);
assert_eq!(track.album_id, 41035954);
assert_eq!(track.album_name, "Black Mamba");
assert_eq!(track.artist_id, 46970441);
assert_eq!(track.artist_name, "aespa");
assert_imgurl(&track.album_coverart_100x100, "/52156772.jpg");
assert_imgurl(&track.album_coverart_350x350, "/52156772_350_350.jpg");
assert_imgurl(&track.album_coverart_500x500, "/52156772_500_500.jpg");
assert_eq!(track.commontrack_vanity_id, "aespa/Black-Mamba");
let release_date = track.first_release_date.unwrap();
assert_eq!(release_date.date(), date!(2020 - 11 - 17));
assert!(track.updated_time > datetime!(2022-8-27 0:00 UTC));
let first_tstatus = &track.track_lyrics_translation_status[0];
assert_eq!(first_tstatus.from.as_deref(), Some("ko"));
assert!(first_tstatus.perc >= 0.0 && first_tstatus.perc <= 1.0);
}
#[rstest]
#[case::no_translation(false, false)]
#[case::translation_2c(true, false)]
#[case::translation_3c(true, true)]
#[tokio::test]
async fn from_id_translations(
#[case] translation_status: bool,
#[case] lang_3c: bool,
#[future] mxm: Musixmatch,
) {
let track = mxm
.await
.track(TrackId::Commontrack(47672612), translation_status, lang_3c)
.await
.unwrap();
// dbg!(&track);
assert_eq!(track.track_id, 85213841);
// assert_eq!(
// track.track_mbid.unwrap(),
// "080975b0-39b1-493c-ae64-5cb3292409bb"
// );
// assert_eq!(track.track_isrc.unwrap(), "USUM70824409");
assert!(
track.commontrack_isrcs[0]
.iter()
.any(|isrc| isrc == "USUM70824409"),
"commontrack_isrcs: {:?}",
&track.commontrack_isrcs[0],
);
assert_eq!(track.track_spotify_id.unwrap(), "1QV6tiMFM6fSOKOGLMHYYg");
assert!(
track
.commontrack_spotify_ids
.iter()
.any(|spid| spid == "1QV6tiMFM6fSOKOGLMHYYg"),
"commontrack_spotify_ids: {:?}",
track.commontrack_spotify_ids,
);
assert_eq!(track.track_name, "Poker Face");
assert!(track.track_rating > 50);
assert_eq!(track.commontrack_id, 47672612);
assert!(!track.instrumental);
assert!(track.explicit);
assert!(track.has_subtitles);
assert!(track.has_richsync);
assert!(track.has_track_structure);
assert!(track.num_favourite > 50);
assert!(track.lyrics_id.is_some());
assert_eq!(track.subtitle_id.unwrap(), 36450705);
assert_eq!(track.album_id, 20960801);
assert_eq!(track.album_name, "The Fame");
assert_eq!(track.artist_id, 378462);
assert_eq!(
track.artist_mbid.unwrap(),
"650e7db6-b795-4eb5-a702-5ea2fc46c848"
);
assert_eq!(track.artist_name, "Lady Gaga");
assert_imgurl(&track.album_coverart_100x100, "/32133892.jpg");
assert_imgurl(&track.album_coverart_350x350, "/32133892_350_350.jpg");
assert_imgurl(&track.album_coverart_500x500, "/32133892_500_500.jpg");
assert_imgurl(&track.album_coverart_800x800, "/32133892_800_800.jpg");
assert_eq!(track.commontrack_vanity_id, "Lady-Gaga/poker-face-1");
let first_release = track.first_release_date.unwrap();
assert_eq!(first_release.date(), date!(2008 - 1 - 1));
assert!(track.updated_time > datetime!(2023-1-17 0:00 UTC));
let first_pri_genre = &track.primary_genres.music_genre_list[0].music_genre;
assert_eq!(first_pri_genre.music_genre_id, 14);
assert_eq!(first_pri_genre.music_genre_parent_id, 34);
assert_eq!(first_pri_genre.music_genre_name, "Pop");
assert_eq!(first_pri_genre.music_genre_name_extended, "Pop");
assert_eq!(first_pri_genre.music_genre_vanity.as_ref().unwrap(), "Pop");
let first_sec_genre = &track.secondary_genres.music_genre_list[0].music_genre;
assert_eq!(first_sec_genre.music_genre_id, 17);
assert_eq!(first_sec_genre.music_genre_parent_id, 34);
assert_eq!(first_sec_genre.music_genre_name, "Dance");
assert_eq!(first_sec_genre.music_genre_name_extended, "Dance");
assert_eq!(
first_sec_genre.music_genre_vanity.as_ref().unwrap(),
"Dance"
);
if translation_status {
assert!(
track.track_lyrics_translation_status.iter().all(|tl| {
(if lang_3c {
tl.from.as_deref() == Some("eng")
} else {
tl.from.as_deref() == Some("en")
}) && tl.perc >= 0.0
&& tl.perc <= 1.0
}),
"translation: {:?}",
track.track_lyrics_translation_status
);
} else {
assert!(track.track_lyrics_translation_status.is_empty())
}
}
#[rstest]
#[tokio::test]
async fn from_id_missing(#[future] mxm: Musixmatch) {
let err = mxm
.await
.track(TrackId::TrackId(999999999999), false, false)
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
#[rstest]
#[tokio::test]
async fn album_tracks(#[future] mxm: Musixmatch) {
let tracks = mxm
.await
.album_tracks(AlbumId::AlbumId(17118624), true, 20, 1)
.await
.unwrap();
// dbg!(&tracks);
let track_names = tracks
.iter()
.map(|t| t.track_name.to_owned())
.collect::<Vec<_>>();
assert_eq!(
track_names,
vec![
"Gäa",
"Vergiss mein nicht",
"Orome",
"Falke flieg",
"Minne",
"Das Lied der Ahnen",
"Hörst du den Wind",
"Nan Úye",
"Faolan",
"Hymne der Nacht",
"Avalon",
"Tolo Nan",
"Oonagh",
]
);
tracks.iter().for_each(|t| {
assert!(t.has_lyrics);
assert!(t.has_subtitles);
});
}
#[rstest]
#[tokio::test]
async fn album_missing(#[future] mxm: Musixmatch) {
let err = mxm
.await
.album_tracks(AlbumId::AlbumId(999999999999), false, 20, 1)
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
#[rstest]
#[case::top(ChartName::Top)]
#[case::hot(ChartName::Hot)]
#[tokio::test]
async fn charts(#[case] chart_name: ChartName, #[future] mxm: Musixmatch) {
let tracks = mxm
.await
.chart_tracks("US", chart_name, true, 20, 1)
.await
.unwrap();
assert_eq!(tracks.len(), 20);
}
#[rstest]
#[tokio::test]
async fn search(#[future] mxm: Musixmatch) {
let tracks = mxm
.await
.track_search()
.q_artist("Lena")
.q_track("Satellite")
.s_track_rating(SortOrder::Desc)
.send(1, 0)
.await
.unwrap();
// dbg!(&tracks);
assert_eq!(tracks.len(), 1);
let track = &tracks[0];
assert_eq!(track.commontrack_id, 72643758);
assert_eq!(track.track_name, "Satellite");
assert_eq!(track.artist_name, "Lena");
}
#[rstest]
#[tokio::test]
async fn search_lyrics(#[future] mxm: Musixmatch) {
let tracks = mxm
.await
.track_search()
.q_lyrics("the whole world stops and stares for a while")
.s_track_rating(SortOrder::Desc)
.send(10, 1)
.await
.unwrap();
assert_gte(tracks.len(), 8, "tracks");
let track = &tracks[0];
assert_eq!(track.track_name, "Just the Way You Are");
assert_eq!(track.artist_name, "Bruno Mars");
}
#[rstest]
#[tokio::test]
async fn search_empty(#[future] mxm: Musixmatch) {
let artists = mxm
.await
.track_search()
.q("Rindfleischettikettierungsüberwachungsaufgabenübertragungsgesetz")
.send(10, 1)
.await
.unwrap();
assert_eq!(artists.len(), 0);
}
#[rstest]
#[tokio::test]
async fn genres(#[future] mxm: Musixmatch) {
let genres = mxm.await.genres().await.unwrap();
assert!(genres.len() > 360);
dbg!(&genres);
}
#[rstest]
#[tokio::test]
async fn snippet(#[future] mxm: Musixmatch) {
let snippet = mxm
.await
.track_snippet(TrackId::Commontrack(8874280))
.await
.unwrap();
assert_eq!(snippet.snippet_id, 23036767);
assert_eq!(snippet.snippet_language.unwrap(), "en");
assert!(!snippet.instrumental);
assert!(snippet.updated_time > datetime!(2022-8-29 0:00 UTC));
assert_eq!(
snippet.snippet_body,
"There's not a thing that I would change"
);
}
}
mod lyrics {
use futures::stream::{self, StreamExt};
use std::{fs::File, io::BufWriter};
use super::*;
#[rstest]
#[tokio::test]
async fn from_match(#[future] mxm: Musixmatch) {
let lyrics = mxm.await.matcher_lyrics("Shine", "Spektrem").await.unwrap();
// dbg!(&lyrics);
assert_eq!(lyrics.lyrics_id, 34583240);
assert!(!lyrics.instrumental);
assert!(!lyrics.explicit);
assert!(
lyrics
.lyrics_body
.starts_with("Eyes in the sky gazing far into the night\n"),
"got: {}",
lyrics.lyrics_body
);
assert_eq!(lyrics.lyrics_language.unwrap(), "en");
assert_eq!(lyrics.lyrics_language_description.unwrap(), "English");
let copyright = lyrics.lyrics_copyright.unwrap();
assert!(copyright.contains("Jesse Warren"), "copyright: {copyright}",);
assert!(lyrics.updated_time > datetime!(2021-6-3 0:00 UTC));
}
#[rstest]
#[case::trackid(TrackId::TrackId(205688271))]
#[case::commontrack(TrackId::Commontrack(118480583))]
#[case::vanity(TrackId::CommontrackVanity("aespa/Black-Mamba".into()))]
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
#[tokio::test]
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
let lyrics = mxm.await.track_lyrics(track_id).await.unwrap();
// dbg!(&lyrics);
assert_eq!(lyrics.lyrics_id, 30126001);
assert_eq!(lyrics.lyrics_language.unwrap(), "ko");
assert_eq!(lyrics.lyrics_language_description.unwrap(), "Korean");
let copyright = lyrics.lyrics_copyright.unwrap();
assert!(
copyright.contains("Kenneth Scott Chesak"),
"copyright: {copyright}",
);
assert!(lyrics.updated_time > datetime!(2022-8-27 0:00 UTC));
}
/// This track has no lyrics
#[rstest]
#[tokio::test]
async fn instrumental(#[future] mxm: Musixmatch) {
let lyrics = mxm
.await
.matcher_lyrics("drivers license", "Bobby G")
.await
.unwrap();
assert_eq!(lyrics.lyrics_id, 25891609);
assert!(lyrics.instrumental);
assert!(!lyrics.explicit);
assert_eq!(lyrics.lyrics_body, "");
assert_eq!(lyrics.lyrics_language, None);
assert_eq!(lyrics.lyrics_language_description, None);
assert_eq!(lyrics.lyrics_copyright, None);
assert!(lyrics.updated_time > datetime!(2021-6-21 0:00 UTC));
}
/// This track does not exist
#[rstest]
#[tokio::test]
async fn missing(#[future] mxm: Musixmatch) {
let err = mxm
.await
.track_lyrics(TrackId::Spotify("2gwMMr1a4aXXN5L6KC80Pu".into()))
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
#[rstest]
#[tokio::test]
async fn download_testdata(#[future] mxm: Musixmatch) {
let mxm = mxm.await;
let json_path = testfile("lyrics.json");
if json_path.exists() {
return;
}
let lyrics = mxm
.track_lyrics(TrackId::Commontrack(18576954))
.await
.unwrap();
let json_file = File::create(json_path).unwrap();
serde_json::to_writer_pretty(BufWriter::new(json_file), &lyrics).unwrap();
}
#[rstest]
#[tokio::test]
async fn download_testdata_translation(#[future] mxm: Musixmatch) {
let mxm = mxm.await;
let json_path = testfile("translation.json");
if json_path.exists() {
return;
}
let translations = mxm
.track_lyrics_translation(TrackId::Commontrack(18576954), "de")
.await
.unwrap();
let json_file = File::create(json_path).unwrap();
serde_json::to_writer_pretty(BufWriter::new(json_file), &translations).unwrap();
}
#[rstest]
#[tokio::test]
async fn concurrency(#[future] mxm: Musixmatch) {
let mxm = mxm.await;
let album = mxm
.album_tracks(
musixmatch_inofficial::models::AlbumId::AlbumId(17118624),
true,
20,
1,
)
.await
.unwrap();
let x = stream::iter(album)
.map(|track| {
mxm.track_lyrics(musixmatch_inofficial::models::TrackId::TrackId(
track.track_id,
))
})
.buffered(8)
.collect::<Vec<_>>()
.await
.into_iter()
.map(Result::unwrap)
.collect::<Vec<_>>();
dbg!(x);
}
}
mod subtitles {
use std::{fs::File, io::BufWriter};
use super::*;
use musixmatch_inofficial::models::SubtitleFormat;
#[rstest]
#[tokio::test]
async fn from_match(#[future] mxm: Musixmatch) {
let subtitle = mxm
.await
.matcher_subtitle(
"Shine",
"Spektrem",
SubtitleFormat::Json,
Some(315.0),
Some(1.0),
)
.await
.unwrap();
// dbg!(&subtitle);
assert_eq!(subtitle.subtitle_id, 35340319);
assert_eq!(subtitle.subtitle_language.unwrap(), "en");
assert_eq!(subtitle.subtitle_language_description.unwrap(), "English");
let copyright = subtitle.lyrics_copyright.unwrap();
assert!(copyright.contains("Jesse Warren"), "copyright: {copyright}",);
assert_eq!(subtitle.subtitle_length, 316);
assert!(subtitle.updated_time > datetime!(2021-6-30 0:00 UTC));
}
#[rstest]
#[case::trackid(TrackId::TrackId(205688271))]
#[case::commontrack(TrackId::Commontrack(118480583))]
#[case::vanity(TrackId::CommontrackVanity("aespa/Black-Mamba".into()))]
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
#[tokio::test]
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
let subtitle = mxm
.await
.track_subtitle(track_id, SubtitleFormat::Json, Some(175.0), Some(1.0))
.await
.unwrap();
// dbg!(&subtitle);
assert_eq!(subtitle.subtitle_id, 36476905);
assert_eq!(subtitle.subtitle_language.unwrap(), "ko");
assert_eq!(subtitle.subtitle_language_description.unwrap(), "Korean");
let copyright = subtitle.lyrics_copyright.unwrap();
assert!(
copyright.contains("Kenneth Scott Chesak"),
"copyright: {copyright}",
);
assert_eq!(subtitle.subtitle_length, 175);
assert!(subtitle.updated_time > datetime!(2022-8-27 0:00 UTC));
}
/// This track has no lyrics
#[rstest]
#[tokio::test]
async fn instrumental(#[future] mxm: Musixmatch) {
let err = mxm
.await
.matcher_subtitle(
"drivers license",
"Bobby G",
SubtitleFormat::Json,
Some(246.0),
Some(1.0),
)
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
/// This track has not been synced
#[rstest]
#[tokio::test]
async fn unsynced(#[future] mxm: Musixmatch) {
let err = mxm
.await
.track_subtitle(
TrackId::Spotify("6oaWIABGL7eeiMILEDyGX1".into()),
SubtitleFormat::Json,
Some(213.0),
Some(1.0),
)
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
/// Try to get subtitles with wrong length parameter
#[rstest]
#[tokio::test]
async fn wrong_length(#[future] mxm: Musixmatch) {
let err = mxm
.await
.track_subtitle(
TrackId::Commontrack(118480583),
SubtitleFormat::Json,
Some(200.0),
Some(1.0),
)
.await
.unwrap_err();
assert!(matches!(err, Error::NotFound));
}
#[rstest]
#[tokio::test]
async fn download_testdata(#[future] mxm: Musixmatch) {
let json_path = testfile("subtitles.json");
if json_path.exists() {
return;
}
let subtitle = mxm
.await
.track_subtitle(
TrackId::Commontrack(18576954),
SubtitleFormat::Json,
Some(259.0),
Some(1.0),
)
.await
.unwrap();
let json_file = File::create(json_path).unwrap();
serde_json::to_writer_pretty(BufWriter::new(json_file), &subtitle).unwrap();
}
}
mod translation {
use std::{fs::File, io::BufReader};
use musixmatch_inofficial::models::{Lyrics, Subtitle, TranslationList, TranslationMap};
use crate::testfile;
#[test]
fn translation_test() {
let lyrics_path = testfile("lyrics.json");
let subtitles_path = testfile("subtitles.json");
let translation_path = testfile("translation.json");
let lyrics: Lyrics =
serde_json::from_reader(BufReader::new(File::open(lyrics_path).unwrap())).unwrap();
let subtitle: Subtitle =
serde_json::from_reader(BufReader::new(File::open(subtitles_path).unwrap())).unwrap();
let translations: TranslationList =
serde_json::from_reader(BufReader::new(File::open(translation_path).unwrap())).unwrap();
let t_map = TranslationMap::from(translations);
let lyrics_trans = t_map.translate_lyrics(&lyrics.lyrics_body);
let expected_lyrics = std::fs::read_to_string(testfile("translated_lyrics.txt")).unwrap();
assert_eq!(lyrics_trans.trim(), expected_lyrics.trim());
let subtitles_trans = t_map.translate_subtitles(&subtitle.to_lines().unwrap());
let expected_lrc = std::fs::read_to_string(testfile("translated_subtitles.lrc")).unwrap();
let expected_ttml = std::fs::read_to_string(testfile("translated_subtitles.xml")).unwrap();
assert_eq!(subtitles_trans.to_lrc().trim(), expected_lrc.trim());
assert_eq!(subtitles_trans.to_ttml().trim(), expected_ttml.trim());
}
}
#[track_caller]
fn assert_imgurl(url: &Option<String>, ends_with: &str) {
assert!(
url.as_deref().is_some_and(
|url| url.starts_with("https://s.mxmcdn.net/images-storage/")
&& url.ends_with(ends_with)
),
"expected url ending with {ends_with}\ngot {:?}",
url
);
}
/// Assert that number A is greater than or equal to number B
#[track_caller]
fn assert_gte<T: PartialOrd + std::fmt::Display>(a: T, b: T, msg: &str) {
assert!(a >= b, "expected >= {b} {msg}, got {a}");
}