1055 lines
34 KiB
Rust
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}");
|
|
}
|