Compare commits
7 commits
feat/captc
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 2848c8a85a | |||
| cb0567c227 | |||
| 5c91c0872c | |||
| 080ca253e1 | |||
| be8247666c | |||
| 266b282e04 | |||
| a5810b91c1 |
22 changed files with 149 additions and 90 deletions
|
|
@ -27,8 +27,9 @@ jobs:
|
||||||
run: cargo clippy --all -- -D warnings
|
run: cargo clippy --all -- -D warnings
|
||||||
|
|
||||||
- name: 🧪 Test
|
- name: 🧪 Test
|
||||||
run: cargo nextest run --config-file ~/.config/nextest.toml --profile ci --retries 2 -j 1 --workspace
|
run: cargo nextest run --config-file ~/.config/nextest.toml --profile ci --retries 2 --workspace --nocapture
|
||||||
env:
|
env:
|
||||||
|
RUST_LOG: info
|
||||||
ALL_PROXY: "http://warpproxy:8124"
|
ALL_PROXY: "http://warpproxy:8124"
|
||||||
|
|
||||||
- name: Move test report
|
- name: Move test report
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@ jobs:
|
||||||
} >> "$GITHUB_ENV"
|
} >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: 📤 Publish crate on crates.io
|
- name: 📤 Publish crate on crates.io
|
||||||
run: cargo publish --token ${{ secrets.CARGO_TOKEN }} --package "${{ env.CRATE }}"
|
run: cargo publish --package "${{ env.CRATE }}"
|
||||||
|
env:
|
||||||
|
CARGO_REGISTRY_TOKEN: "${{ secrets.CARGO_TOKEN }}"
|
||||||
|
|
||||||
- name: 🎉 Publish release
|
- name: 🎉 Publish release
|
||||||
uses: https://gitea.com/actions/release-action@main
|
uses: https://gitea.com/actions/release-action@main
|
||||||
|
|
|
||||||
17
CHANGELOG.md
17
CHANGELOG.md
|
|
@ -3,6 +3,23 @@
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
|
||||||
|
## [v0.5.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-inofficial/v0.4.0..musixmatch-inofficial/v0.5.0) - 2026-06-11
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Lock cache files before reading/writing - ([e188175](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/e188175f2ea849d4663235aa3f510759e2486ec4))
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Creation of session file - ([a5810b9](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/a5810b91c1094b7fac3ac1abdf65dac2e696f47e))
|
||||||
|
- Fix clippy lints - ([be82476](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/be8247666c27b6b6e841fd0e08355cd497f5d42a))
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Update dependencies - ([7383f15](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/7383f156626f7acc71e10ceb88e6a21ec43962a0))
|
||||||
|
- Update edition to 2024 - ([266b282](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/266b282e04f5813564ad07b87bd965be73fc3f7f))
|
||||||
|
|
||||||
|
|
||||||
## [v0.4.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-inofficial/v0.3.0..musixmatch-inofficial/v0.4.0) - 2025-12-19
|
## [v0.4.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-inofficial/v0.3.0..musixmatch-inofficial/v0.4.0) - 2025-12-19
|
||||||
|
|
||||||
### 🚀 Features
|
### 🚀 Features
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "musixmatch-inofficial"
|
name = "musixmatch-inofficial"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
rust-version = "1.89.0"
|
rust-version = "1.89.0"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|
@ -15,7 +15,7 @@ include = ["/src", "README.md", "CHANGELOG.md", "LICENSE"]
|
||||||
members = [".", "cli"]
|
members = [".", "cli"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
authors = ["ThetaDev <thetadev@magenta.de>"]
|
authors = ["ThetaDev <thetadev@magenta.de>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://codeberg.org/ThetaDev/musixmatch-inofficial"
|
repository = "https://codeberg.org/ThetaDev/musixmatch-inofficial"
|
||||||
|
|
@ -23,7 +23,7 @@ keywords = ["music", "lyrics"]
|
||||||
categories = ["api-bindings", "multimedia"]
|
categories = ["api-bindings", "multimedia"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
musixmatch-inofficial = { version = "0.4.0", path = ".", default-features = false }
|
musixmatch-inofficial = { version = "0.5.0", path = ".", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["default-tls"]
|
default = ["default-tls"]
|
||||||
|
|
@ -64,5 +64,4 @@ dotenvy = "0.15.5"
|
||||||
tokio = { version = "1.20.4", features = ["macros"] }
|
tokio = { version = "1.20.4", features = ["macros"] }
|
||||||
futures = "0.3.21"
|
futures = "0.3.21"
|
||||||
path_macro = "1.0.0"
|
path_macro = "1.0.0"
|
||||||
governor = "0.10.0"
|
|
||||||
test-log = "0.2.16"
|
test-log = "0.2.16"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,15 @@
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
|
||||||
|
## [v0.5.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-cli/v0.4.0..musixmatch-cli/v0.5.0) - 2026-06-12
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Update musixmatch to v0.5.0
|
||||||
|
- Update reqwest to 0.13.0 (new TLS feature flags)
|
||||||
|
- Update edition to 2024 - ([266b282](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/266b282e04f5813564ad07b87bd965be73fc3f7f))
|
||||||
|
|
||||||
|
|
||||||
## [v0.4.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-cli/v0.3.1..musixmatch-cli/v0.4.0) - 2025-12-19
|
## [v0.4.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-cli/v0.3.1..musixmatch-cli/v0.4.0) - 2025-12-19
|
||||||
|
|
||||||
### 🚀 Features
|
### 🚀 Features
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "musixmatch-cli"
|
name = "musixmatch-cli"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
rust-version = "1.89.0"
|
rust-version = "1.89.0"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@
|
||||||
#![warn(missing_docs, clippy::todo)]
|
#![warn(missing_docs, clippy::todo)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::{stdin, stdout, Write},
|
io::{Write, stdin, stdout},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{Result, anyhow, bail};
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use musixmatch_inofficial::{
|
use musixmatch_inofficial::{
|
||||||
models::{AlbumId, ArtistId, SubtitleFormat, Track, TrackId, TranslationMap},
|
|
||||||
Musixmatch,
|
Musixmatch,
|
||||||
|
models::{AlbumId, ArtistId, SubtitleFormat, Track, TrackId, TranslationMap},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
|
@ -233,31 +233,31 @@ async fn run(cli: Cli) -> Result<()> {
|
||||||
|
|
||||||
let mut lyrics_body = lyrics.lyrics_body;
|
let mut lyrics_body = lyrics.lyrics_body;
|
||||||
|
|
||||||
if let Some(lang) = lang {
|
if let Some(lang) = lang
|
||||||
if Some(&lang) != lyrics.lyrics_language.as_ref() {
|
&& Some(&lang) != lyrics.lyrics_language.as_ref()
|
||||||
let tl = mxm.track_lyrics_translation(track_id, &lang).await?;
|
{
|
||||||
if tl.is_empty() {
|
let tl = mxm.track_lyrics_translation(track_id, &lang).await?;
|
||||||
eprintln!("Translation not found. Returning lyrics in original language.");
|
if tl.is_empty() {
|
||||||
|
eprintln!("Translation not found. Returning lyrics in original language.");
|
||||||
|
} else {
|
||||||
|
eprintln!("Translated to: {}", tl.lang);
|
||||||
|
let tm = TranslationMap::from(tl);
|
||||||
|
let translated = tm.translate_lyrics(&lyrics_body);
|
||||||
|
lyrics_body = if bi {
|
||||||
|
lyrics_body
|
||||||
|
.lines()
|
||||||
|
.zip(translated.lines())
|
||||||
|
.map(|(a, b)| {
|
||||||
|
if a == b {
|
||||||
|
a.to_string() + "\n"
|
||||||
|
} else {
|
||||||
|
format!("{a}\n> {b}\n")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Translated to: {}", tl.lang);
|
translated
|
||||||
let tm = TranslationMap::from(tl);
|
};
|
||||||
let translated = tm.translate_lyrics(&lyrics_body);
|
|
||||||
lyrics_body = if bi {
|
|
||||||
lyrics_body
|
|
||||||
.lines()
|
|
||||||
.zip(translated.lines())
|
|
||||||
.map(|(a, b)| {
|
|
||||||
if a == b {
|
|
||||||
a.to_string() + "\n"
|
|
||||||
} else {
|
|
||||||
format!("{a}\n> {b}\n")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
} else {
|
|
||||||
translated
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use std::{marker::PhantomData, str::FromStr};
|
use std::{marker::PhantomData, str::FromStr};
|
||||||
|
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{DeserializeOwned, Visitor},
|
|
||||||
Deserialize, Deserializer, Serialize,
|
Deserialize, Deserializer, Serialize,
|
||||||
|
de::{DeserializeOwned, Visitor},
|
||||||
};
|
};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
|
|
@ -416,9 +416,9 @@ where
|
||||||
|
|
||||||
pub mod optional_date {
|
pub mod optional_date {
|
||||||
use super::*;
|
use super::*;
|
||||||
use serde::ser::Error as _;
|
|
||||||
use serde::Serializer;
|
use serde::Serializer;
|
||||||
use time::{macros::format_description, Date};
|
use serde::ser::Error as _;
|
||||||
|
use time::{Date, macros::format_description};
|
||||||
|
|
||||||
const DATE_FORMAT: &[time::format_description::FormatItem] =
|
const DATE_FORMAT: &[time::format_description::FormatItem] =
|
||||||
format_description!("[year]-[month]-[day]");
|
format_description!("[year]-[month]-[day]");
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
use crate::Musixmatch;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::album::{Album, AlbumBody, AlbumListBody};
|
use crate::models::album::{Album, AlbumBody, AlbumListBody};
|
||||||
use crate::models::{AlbumId, ArtistId, SortOrder};
|
use crate::models::{AlbumId, ArtistId, SortOrder};
|
||||||
use crate::Musixmatch;
|
|
||||||
|
|
||||||
impl Musixmatch {
|
impl Musixmatch {
|
||||||
/// Get the metadata for an album specified by its ID.
|
/// Get the metadata for an album specified by its ID.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::error::Result;
|
|
||||||
use crate::models::artist::{Artist, ArtistBody, ArtistListBody};
|
|
||||||
use crate::models::ArtistId;
|
|
||||||
use crate::Musixmatch;
|
use crate::Musixmatch;
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::models::ArtistId;
|
||||||
|
use crate::models::artist::{Artist, ArtistBody, ArtistListBody};
|
||||||
|
|
||||||
impl Musixmatch {
|
impl Musixmatch {
|
||||||
/// Get the metadata for an artist specified by its ID.
|
/// Get the metadata for an artist specified by its ID.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
use crate::Musixmatch;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
use crate::models::TrackId;
|
||||||
use crate::models::lyrics::{Lyrics, LyricsBody};
|
use crate::models::lyrics::{Lyrics, LyricsBody};
|
||||||
use crate::models::translation::{TranslationList, TranslationListBody};
|
use crate::models::translation::{TranslationList, TranslationListBody};
|
||||||
use crate::models::TrackId;
|
|
||||||
use crate::Musixmatch;
|
|
||||||
|
|
||||||
impl Musixmatch {
|
impl Musixmatch {
|
||||||
/// Get the lyrics for a track specified by its name and artist.
|
/// Get the lyrics for a track specified by its name and artist.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::error::Result;
|
|
||||||
use crate::models::richsync::{RichsyncBody, RichsyncLyrics};
|
|
||||||
use crate::models::TrackId;
|
|
||||||
use crate::Musixmatch;
|
use crate::Musixmatch;
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::models::TrackId;
|
||||||
|
use crate::models::richsync::{RichsyncBody, RichsyncLyrics};
|
||||||
|
|
||||||
impl Musixmatch {
|
impl Musixmatch {
|
||||||
/// Get the richsync (word-by-word synchronized lyrics) for a track specified by its ID.
|
/// Get the richsync (word-by-word synchronized lyrics) for a track specified by its ID.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::error::Result;
|
|
||||||
use crate::models::snippet::{Snippet, SnippetBody};
|
|
||||||
use crate::models::TrackId;
|
|
||||||
use crate::Musixmatch;
|
use crate::Musixmatch;
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::models::TrackId;
|
||||||
|
use crate::models::snippet::{Snippet, SnippetBody};
|
||||||
|
|
||||||
impl Musixmatch {
|
impl Musixmatch {
|
||||||
/// Get a lyrics snippet for a track specified by its ID.
|
/// Get a lyrics snippet for a track specified by its ID.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::error::Result;
|
|
||||||
use crate::models::subtitle::{Subtitle, SubtitleBody, SubtitleFormat};
|
|
||||||
use crate::models::TrackId;
|
|
||||||
use crate::Musixmatch;
|
use crate::Musixmatch;
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::models::TrackId;
|
||||||
|
use crate::models::subtitle::{Subtitle, SubtitleBody, SubtitleFormat};
|
||||||
|
|
||||||
impl Musixmatch {
|
impl Musixmatch {
|
||||||
/// Get the subtitles (synchronized lyrics) for a track specified by its name and artist.
|
/// Get the subtitles (synchronized lyrics) for a track specified by its name and artist.
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use time::Date;
|
use time::Date;
|
||||||
|
|
||||||
|
use crate::Musixmatch;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::track::{Track, TrackBody, TrackListBody};
|
use crate::models::track::{Track, TrackBody, TrackListBody};
|
||||||
use crate::models::{AlbumId, ChartName, Genre, Genres, SortOrder, TrackId};
|
use crate::models::{AlbumId, ChartName, Genre, Genres, SortOrder, TrackId};
|
||||||
use crate::Musixmatch;
|
|
||||||
|
|
||||||
impl Musixmatch {
|
impl Musixmatch {
|
||||||
/// Get the metadata for a track specified by its name, artist and album.
|
/// Get the metadata for a track specified by its name, artist and album.
|
||||||
|
|
@ -403,21 +403,17 @@ impl<'a> TrackSearchQuery<'a> {
|
||||||
}
|
}
|
||||||
if let Some(f_track_release_group_first_release_date_min) =
|
if let Some(f_track_release_group_first_release_date_min) =
|
||||||
self.f_track_release_group_first_release_date_min
|
self.f_track_release_group_first_release_date_min
|
||||||
{
|
&& let Ok(date) =
|
||||||
if let Ok(date) =
|
|
||||||
f_track_release_group_first_release_date_min.format(crate::YMD_FORMAT)
|
f_track_release_group_first_release_date_min.format(crate::YMD_FORMAT)
|
||||||
{
|
{
|
||||||
url_query.append_pair("f_track_release_group_first_release_date_min", &date);
|
url_query.append_pair("f_track_release_group_first_release_date_min", &date);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(f_track_release_group_first_release_date_max) =
|
if let Some(f_track_release_group_first_release_date_max) =
|
||||||
self.f_track_release_group_first_release_date_max
|
self.f_track_release_group_first_release_date_max
|
||||||
{
|
&& let Ok(date) =
|
||||||
if let Ok(date) =
|
|
||||||
f_track_release_group_first_release_date_max.format(crate::YMD_FORMAT)
|
f_track_release_group_first_release_date_max.format(crate::YMD_FORMAT)
|
||||||
{
|
{
|
||||||
url_query.append_pair("f_track_release_group_first_release_date_max", &date);
|
url_query.append_pair("f_track_release_group_first_release_date_max", &date);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(s_artist_rating) = &self.s_artist_rating {
|
if let Some(s_artist_rating) = &self.s_artist_rating {
|
||||||
url_query.append_pair("s_artist_rating", s_artist_rating.as_str());
|
url_query.append_pair("s_artist_rating", s_artist_rating.as_str());
|
||||||
|
|
|
||||||
13
src/lib.rs
13
src/lib.rs
|
|
@ -23,9 +23,9 @@ use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
use storage::{FileStorage, SessionStorage};
|
use storage::{FileStorage, SessionStorage};
|
||||||
|
use time::OffsetDateTime;
|
||||||
use time::format_description::well_known::Rfc3339;
|
use time::format_description::well_known::Rfc3339;
|
||||||
use time::macros::format_description;
|
use time::macros::format_description;
|
||||||
use time::OffsetDateTime;
|
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::api_model::parse_body;
|
use crate::api_model::parse_body;
|
||||||
|
|
@ -229,10 +229,8 @@ impl Musixmatch {
|
||||||
// Lock the session here to prevent concurrent tasks from obtaining sessions
|
// Lock the session here to prevent concurrent tasks from obtaining sessions
|
||||||
let mut stored_usertoken = self.inner.usertoken.lock().await;
|
let mut stored_usertoken = self.inner.usertoken.lock().await;
|
||||||
|
|
||||||
if !force_new {
|
if !force_new && let Some(usertoken) = &mut *stored_usertoken {
|
||||||
if let Some(usertoken) = &mut *stored_usertoken {
|
return Ok(usertoken.clone());
|
||||||
return Ok(usertoken.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let credentials = {
|
let credentials = {
|
||||||
|
|
@ -503,6 +501,9 @@ mod tests {
|
||||||
fn t_sign_url() {
|
fn t_sign_url() {
|
||||||
let mut url = Url::parse("https://apic.musixmatch.com/ws/1.1/track.subtitle.get?app_id=android-player-v1.0&usertoken=22092860c49e8d783b569a7bd847cd5b289bbec306f8a0bb2d3771&format=json&track_spotify_id=7Ga0ByppmSXWuKXdsD8JGL&subtitle_format=mxm").unwrap();
|
let mut url = Url::parse("https://apic.musixmatch.com/ws/1.1/track.subtitle.get?app_id=android-player-v1.0&usertoken=22092860c49e8d783b569a7bd847cd5b289bbec306f8a0bb2d3771&format=json&track_spotify_id=7Ga0ByppmSXWuKXdsD8JGL&subtitle_format=mxm").unwrap();
|
||||||
sign_url_with_date(&mut url, datetime!(2022-09-28 0:00 UTC));
|
sign_url_with_date(&mut url, datetime!(2022-09-28 0:00 UTC));
|
||||||
assert_eq!(url.as_str(), "https://apic.musixmatch.com/ws/1.1/track.subtitle.get?app_id=android-player-v1.0&usertoken=22092860c49e8d783b569a7bd847cd5b289bbec306f8a0bb2d3771&format=json&track_spotify_id=7Ga0ByppmSXWuKXdsD8JGL&subtitle_format=mxm&signature=78ywxkeXlazpevI%2BbD8E3YluLPc%3D%0A&signature_protocol=sha1")
|
assert_eq!(
|
||||||
|
url.as_str(),
|
||||||
|
"https://apic.musixmatch.com/ws/1.1/track.subtitle.get?app_id=android-player-v1.0&usertoken=22092860c49e8d783b569a7bd847cd5b289bbec306f8a0bb2d3771&format=json&track_spotify_id=7Ga0ByppmSXWuKXdsD8JGL&subtitle_format=mxm&signature=78ywxkeXlazpevI%2BbD8E3YluLPc%3D%0A&signature_protocol=sha1"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{borrow::Cow, convert::Infallible, fmt::Write, str::FromStr};
|
use std::{borrow::Cow, convert::Infallible, fmt::Write, str::FromStr};
|
||||||
|
|
||||||
use serde::{de::Visitor, Deserialize, Serialize};
|
use serde::{Deserialize, Serialize, de::Visitor};
|
||||||
|
|
||||||
use crate::IdError;
|
use crate::IdError;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
use crate::{error::Result, Error};
|
use crate::{Error, error::Result};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub(crate) struct LyricsBody {
|
pub(crate) struct LyricsBody {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
use crate::{error::Result, Error};
|
use crate::{Error, error::Result};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub(crate) struct SubtitleBody {
|
pub(crate) struct SubtitleBody {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
use super::{subtitle::SubtitleLines, SubtitleLine};
|
use super::{SubtitleLine, subtitle::SubtitleLines};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub(crate) struct TranslationListBody {
|
pub(crate) struct TranslationListBody {
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,14 @@ fn read_file(path: &Path) -> Result<String, std::io::Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_file(path: &Path, data: &str) -> Result<(), std::io::Error> {
|
fn write_file(path: &Path, data: &str) -> Result<(), std::io::Error> {
|
||||||
let mut f = File::options().read(true).append(true).open(path)?;
|
// Open file in append mode to not immediately truncate it
|
||||||
|
let mut f = File::options()
|
||||||
|
.create(true)
|
||||||
|
.read(true)
|
||||||
|
.append(true)
|
||||||
|
.open(path)?;
|
||||||
f.lock()?;
|
f.lock()?;
|
||||||
|
// Truncate file after making sure no one is reading/writing to it
|
||||||
f.set_len(0)?;
|
f.set_len(0)?;
|
||||||
f.write_all(data.as_bytes())?;
|
f.write_all(data.as_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
use std::{
|
use std::path::{Path, PathBuf};
|
||||||
path::{Path, PathBuf},
|
|
||||||
sync::LazyLock,
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use governor::{DefaultDirectRateLimiter, Quota, RateLimiter};
|
|
||||||
use path_macro::path;
|
use path_macro::path;
|
||||||
use rstest::{fixture, rstest};
|
use rstest::{fixture, rstest};
|
||||||
use time::macros::{date, datetime};
|
use time::macros::{date, datetime};
|
||||||
|
|
||||||
use musixmatch_inofficial::{
|
use musixmatch_inofficial::{
|
||||||
models::{AlbumId, ArtistId, TrackId},
|
|
||||||
Error, Musixmatch,
|
Error, Musixmatch,
|
||||||
|
models::{AlbumId, ArtistId, TrackId},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn testfile<P: AsRef<Path>>(name: P) -> PathBuf {
|
fn testfile<P: AsRef<Path>>(name: P) -> PathBuf {
|
||||||
|
|
@ -21,15 +16,6 @@ fn testfile<P: AsRef<Path>>(name: P) -> PathBuf {
|
||||||
#[fixture]
|
#[fixture]
|
||||||
async fn mxm() -> Musixmatch {
|
async fn mxm() -> Musixmatch {
|
||||||
static LOGIN_LOCK: tokio::sync::OnceCell<()> = tokio::sync::OnceCell::const_new();
|
static LOGIN_LOCK: tokio::sync::OnceCell<()> = tokio::sync::OnceCell::const_new();
|
||||||
static MXM_LIMITER: LazyLock<DefaultDirectRateLimiter> = LazyLock::new(|| {
|
|
||||||
RateLimiter::direct(if std::env::var("CI").is_ok() {
|
|
||||||
Quota::with_period(Duration::from_millis(2000)).unwrap()
|
|
||||||
} else {
|
|
||||||
Quota::with_period(Duration::from_millis(500)).unwrap()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
MXM_LIMITER.until_ready().await;
|
|
||||||
|
|
||||||
let mut mxm = Musixmatch::builder();
|
let mut mxm = Musixmatch::builder();
|
||||||
|
|
||||||
|
|
@ -54,6 +40,7 @@ mod album {
|
||||||
#[case::id(AlbumId::AlbumId(14248253))]
|
#[case::id(AlbumId::AlbumId(14248253))]
|
||||||
// #[case::musicbrainz(AlbumId::Musicbrainz("6c3cf9d8-88a8-43ed-850b-55813f01e451"))]
|
// #[case::musicbrainz(AlbumId::Musicbrainz("6c3cf9d8-88a8-43ed-850b-55813f01e451"))]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn by_id(#[case] album_id: AlbumId<'_>, #[future] mxm: Musixmatch) {
|
async fn by_id(#[case] album_id: AlbumId<'_>, #[future] mxm: Musixmatch) {
|
||||||
let album = mxm.await.album(album_id).await.unwrap();
|
let album = mxm.await.album(album_id).await.unwrap();
|
||||||
// dbg!(&album);
|
// dbg!(&album);
|
||||||
|
|
@ -105,6 +92,7 @@ mod album {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn album_ep(#[future] mxm: Musixmatch) {
|
async fn album_ep(#[future] mxm: Musixmatch) {
|
||||||
let album = mxm.await.album(AlbumId::AlbumId(23976123)).await.unwrap();
|
let album = mxm.await.album(AlbumId::AlbumId(23976123)).await.unwrap();
|
||||||
assert_eq!(album.album_name, "Waldbrand EP");
|
assert_eq!(album.album_name, "Waldbrand EP");
|
||||||
|
|
@ -114,6 +102,7 @@ mod album {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn by_id_missing(#[future] mxm: Musixmatch) {
|
async fn by_id_missing(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -126,6 +115,7 @@ mod album {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
async fn artist_albums(#[future] mxm: Musixmatch) {
|
async fn artist_albums(#[future] mxm: Musixmatch) {
|
||||||
let albums = mxm
|
let albums = mxm
|
||||||
|
|
@ -139,6 +129,7 @@ mod album {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn artist_albums_missing(#[future] mxm: Musixmatch) {
|
async fn artist_albums_missing(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -151,6 +142,7 @@ mod album {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn charts(#[future] mxm: Musixmatch) {
|
async fn charts(#[future] mxm: Musixmatch) {
|
||||||
let albums = mxm.await.chart_albums("US", 10, 1).await.unwrap();
|
let albums = mxm.await.chart_albums("US", 10, 1).await.unwrap();
|
||||||
|
|
||||||
|
|
@ -165,6 +157,7 @@ mod artist {
|
||||||
#[case::id(ArtistId::ArtistId(410698))]
|
#[case::id(ArtistId::ArtistId(410698))]
|
||||||
// #[case::musicbrainz(ArtistId::Musicbrainz("f99b7d67-4e63-4678-aa66-4c6ac0f7d24a"))]
|
// #[case::musicbrainz(ArtistId::Musicbrainz("f99b7d67-4e63-4678-aa66-4c6ac0f7d24a"))]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn by_id(#[case] artist_id: ArtistId<'_>, #[future] mxm: Musixmatch) {
|
async fn by_id(#[case] artist_id: ArtistId<'_>, #[future] mxm: Musixmatch) {
|
||||||
let artist = mxm.await.artist(artist_id).await.unwrap();
|
let artist = mxm.await.artist(artist_id).await.unwrap();
|
||||||
|
|
||||||
|
|
@ -229,6 +222,7 @@ mod artist {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn by_id_missing(#[future] mxm: Musixmatch) {
|
async fn by_id_missing(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -241,6 +235,7 @@ mod artist {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn search(#[future] mxm: Musixmatch) {
|
async fn search(#[future] mxm: Musixmatch) {
|
||||||
let artists = mxm
|
let artists = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -258,6 +253,7 @@ mod artist {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn search_empty(#[future] mxm: Musixmatch) {
|
async fn search_empty(#[future] mxm: Musixmatch) {
|
||||||
let artists = mxm
|
let artists = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -274,6 +270,7 @@ mod artist {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn charts(#[future] mxm: Musixmatch) {
|
async fn charts(#[future] mxm: Musixmatch) {
|
||||||
let artists = mxm.await.chart_artists("US", 10, 1).await.unwrap();
|
let artists = mxm.await.chart_artists("US", 10, 1).await.unwrap();
|
||||||
|
|
||||||
|
|
@ -282,6 +279,7 @@ mod artist {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn charts_no_country(#[future] mxm: Musixmatch) {
|
async fn charts_no_country(#[future] mxm: Musixmatch) {
|
||||||
let artists = mxm.await.chart_artists("XY", 10, 1).await.unwrap();
|
let artists = mxm.await.chart_artists("XY", 10, 1).await.unwrap();
|
||||||
|
|
||||||
|
|
@ -300,6 +298,7 @@ mod track {
|
||||||
#[case::translation_2c(true, false)]
|
#[case::translation_2c(true, false)]
|
||||||
#[case::translation_3c(true, true)]
|
#[case::translation_3c(true, true)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_match(
|
async fn from_match(
|
||||||
#[case] translation_status: bool,
|
#[case] translation_status: bool,
|
||||||
#[case] lang_3c: bool,
|
#[case] lang_3c: bool,
|
||||||
|
|
@ -400,6 +399,7 @@ mod track {
|
||||||
#[case::isrc(TrackId::Isrc("QZDA41918667".into()))]
|
#[case::isrc(TrackId::Isrc("QZDA41918667".into()))]
|
||||||
#[case::spotify(TrackId::Spotify("2roGy5AYlaJpmL9CuXj6tT".into()))]
|
#[case::spotify(TrackId::Spotify("2roGy5AYlaJpmL9CuXj6tT".into()))]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
|
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
|
||||||
let track = mxm.await.track(track_id, true, false, false).await.unwrap();
|
let track = mxm.await.track(track_id, true, false, false).await.unwrap();
|
||||||
|
|
||||||
|
|
@ -479,6 +479,7 @@ mod track {
|
||||||
#[case::translation_2c(true, false)]
|
#[case::translation_2c(true, false)]
|
||||||
#[case::translation_3c(true, true)]
|
#[case::translation_3c(true, true)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_id_translations(
|
async fn from_id_translations(
|
||||||
#[case] translation_status: bool,
|
#[case] translation_status: bool,
|
||||||
#[case] lang_3c: bool,
|
#[case] lang_3c: bool,
|
||||||
|
|
@ -584,6 +585,7 @@ mod track {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_id_missing(#[future] mxm: Musixmatch) {
|
async fn from_id_missing(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -596,6 +598,7 @@ mod track {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn album_tracks(#[future] mxm: Musixmatch) {
|
async fn album_tracks(#[future] mxm: Musixmatch) {
|
||||||
let tracks = mxm
|
let tracks = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -637,6 +640,7 @@ mod track {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn album_missing(#[future] mxm: Musixmatch) {
|
async fn album_missing(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -653,6 +657,7 @@ mod track {
|
||||||
#[case::weekly(ChartName::MxmWeekly)]
|
#[case::weekly(ChartName::MxmWeekly)]
|
||||||
#[case::weekly_new(ChartName::MxmWeeklyNew)]
|
#[case::weekly_new(ChartName::MxmWeeklyNew)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn charts(#[case] chart_name: ChartName, #[future] mxm: Musixmatch) {
|
async fn charts(#[case] chart_name: ChartName, #[future] mxm: Musixmatch) {
|
||||||
let tracks = mxm
|
let tracks = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -665,6 +670,7 @@ mod track {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn search(#[future] mxm: Musixmatch) {
|
async fn search(#[future] mxm: Musixmatch) {
|
||||||
let tracks = mxm
|
let tracks = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -688,6 +694,7 @@ mod track {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn search_lyrics(#[future] mxm: Musixmatch) {
|
async fn search_lyrics(#[future] mxm: Musixmatch) {
|
||||||
let tracks = mxm
|
let tracks = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -707,6 +714,7 @@ mod track {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn search_empty(#[future] mxm: Musixmatch) {
|
async fn search_empty(#[future] mxm: Musixmatch) {
|
||||||
let artists = mxm
|
let artists = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -721,14 +729,16 @@ mod track {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn genres(#[future] mxm: Musixmatch) {
|
async fn genres(#[future] mxm: Musixmatch) {
|
||||||
let genres = mxm.await.genres().await.unwrap();
|
let genres = mxm.await.genres().await.unwrap();
|
||||||
assert!(genres.len() > 360);
|
assert!(genres.len() > 360);
|
||||||
dbg!(&genres);
|
// dbg!(&genres);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn snippet(#[future] mxm: Musixmatch) {
|
async fn snippet(#[future] mxm: Musixmatch) {
|
||||||
let snippet = mxm
|
let snippet = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -755,6 +765,7 @@ mod lyrics {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_match(#[future] mxm: Musixmatch) {
|
async fn from_match(#[future] mxm: Musixmatch) {
|
||||||
let lyrics = mxm.await.matcher_lyrics("Shine", "Spektrem").await.unwrap();
|
let lyrics = mxm.await.matcher_lyrics("Shine", "Spektrem").await.unwrap();
|
||||||
|
|
||||||
|
|
@ -784,6 +795,7 @@ mod lyrics {
|
||||||
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
|
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
|
||||||
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
|
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
|
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
|
||||||
let lyrics = mxm.await.track_lyrics(track_id).await.unwrap();
|
let lyrics = mxm.await.track_lyrics(track_id).await.unwrap();
|
||||||
|
|
||||||
|
|
@ -803,6 +815,7 @@ mod lyrics {
|
||||||
/// This track has no lyrics
|
/// This track has no lyrics
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn instrumental(#[future] mxm: Musixmatch) {
|
async fn instrumental(#[future] mxm: Musixmatch) {
|
||||||
let lyrics = mxm
|
let lyrics = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -823,6 +836,7 @@ mod lyrics {
|
||||||
/// This track does not exist
|
/// This track does not exist
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn missing(#[future] mxm: Musixmatch) {
|
async fn missing(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -835,6 +849,7 @@ mod lyrics {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn download_testdata(#[future] mxm: Musixmatch) {
|
async fn download_testdata(#[future] mxm: Musixmatch) {
|
||||||
let mxm = mxm.await;
|
let mxm = mxm.await;
|
||||||
let json_path = testfile("lyrics.json");
|
let json_path = testfile("lyrics.json");
|
||||||
|
|
@ -853,6 +868,7 @@ mod lyrics {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn download_testdata_translation(#[future] mxm: Musixmatch) {
|
async fn download_testdata_translation(#[future] mxm: Musixmatch) {
|
||||||
let mxm = mxm.await;
|
let mxm = mxm.await;
|
||||||
let json_path = testfile("translation.json");
|
let json_path = testfile("translation.json");
|
||||||
|
|
@ -871,6 +887,7 @@ mod lyrics {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn concurrency(#[future] mxm: Musixmatch) {
|
async fn concurrency(#[future] mxm: Musixmatch) {
|
||||||
let mxm = mxm.await;
|
let mxm = mxm.await;
|
||||||
|
|
||||||
|
|
@ -883,8 +900,9 @@ mod lyrics {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
assert_eq!(album.len(), 13);
|
||||||
|
|
||||||
let x = stream::iter(album)
|
let lyrics = stream::iter(album)
|
||||||
.map(|track| {
|
.map(|track| {
|
||||||
mxm.track_lyrics(musixmatch_inofficial::models::TrackId::TrackId(
|
mxm.track_lyrics(musixmatch_inofficial::models::TrackId::TrackId(
|
||||||
track.track_id,
|
track.track_id,
|
||||||
|
|
@ -896,8 +914,7 @@ mod lyrics {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Result::unwrap)
|
.map(Result::unwrap)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(lyrics.len(), 13);
|
||||||
dbg!(x);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -909,6 +926,7 @@ mod subtitles {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_match(#[future] mxm: Musixmatch) {
|
async fn from_match(#[future] mxm: Musixmatch) {
|
||||||
let subtitle = mxm
|
let subtitle = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -940,6 +958,7 @@ mod subtitles {
|
||||||
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
|
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
|
||||||
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
|
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
|
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
|
||||||
let subtitle = mxm
|
let subtitle = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -964,6 +983,7 @@ mod subtitles {
|
||||||
/// This track has no lyrics
|
/// This track has no lyrics
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn instrumental(#[future] mxm: Musixmatch) {
|
async fn instrumental(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -983,6 +1003,7 @@ mod subtitles {
|
||||||
/// This track has not been synced
|
/// This track has not been synced
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn unsynced(#[future] mxm: Musixmatch) {
|
async fn unsynced(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -1001,6 +1022,7 @@ mod subtitles {
|
||||||
/// Try to get subtitles with wrong length parameter
|
/// Try to get subtitles with wrong length parameter
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn wrong_length(#[future] mxm: Musixmatch) {
|
async fn wrong_length(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -1018,6 +1040,7 @@ mod subtitles {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn download_testdata(#[future] mxm: Musixmatch) {
|
async fn download_testdata(#[future] mxm: Musixmatch) {
|
||||||
let json_path = testfile("subtitles.json");
|
let json_path = testfile("subtitles.json");
|
||||||
if json_path.exists() {
|
if json_path.exists() {
|
||||||
|
|
@ -1088,6 +1111,7 @@ mod richsync {
|
||||||
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
|
#[case::isrc(TrackId::Isrc("KRA302000590".into()))]
|
||||||
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
|
#[case::spotify(TrackId::Spotify("1t2qYCAjUAoGfeFeoBlK51".into()))]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
|
async fn from_id(#[case] track_id: TrackId<'_>, #[future] mxm: Musixmatch) {
|
||||||
let richsync = mxm
|
let richsync = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -1116,6 +1140,7 @@ mod richsync {
|
||||||
/// This track has no lyrics
|
/// This track has no lyrics
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn instrumental(#[future] mxm: Musixmatch) {
|
async fn instrumental(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -1129,6 +1154,7 @@ mod richsync {
|
||||||
/// This track has not been synced
|
/// This track has not been synced
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn unsynced(#[future] mxm: Musixmatch) {
|
async fn unsynced(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -1146,6 +1172,7 @@ mod richsync {
|
||||||
/// Try to get subtitles with wrong length parameter
|
/// Try to get subtitles with wrong length parameter
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn wrong_length(#[future] mxm: Musixmatch) {
|
async fn wrong_length(#[future] mxm: Musixmatch) {
|
||||||
let err = mxm
|
let err = mxm
|
||||||
.await
|
.await
|
||||||
|
|
@ -1158,6 +1185,7 @@ mod richsync {
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
#[test_log::test]
|
||||||
async fn download_testdata(#[future] mxm: Musixmatch) {
|
async fn download_testdata(#[future] mxm: Musixmatch) {
|
||||||
let json_path = testfile("richsync.json");
|
let json_path = testfile("richsync.json");
|
||||||
if json_path.exists() {
|
if json_path.exists() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue