Compare commits
22 commits
musixmatch
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
5e5942beb8 |
|||
|
f6fe442e3c |
|||
|
4782f4905e |
|||
|
c6b3382948 |
|||
|
e087752dd0 |
|||
|
80c3c38c41 |
|||
|
39bbd5070a |
|||
|
09c6004ed1 |
|||
|
bfe6fec115 |
|||
|
528c6f7eb1 |
|||
|
74d5359547 |
|||
|
59dee61a2f |
|||
|
f73dcdd134 |
|||
|
04a0544ad5 |
|||
|
4a46e7bb1d |
|||
|
6f90033cf4 |
|||
|
7c325c4af7 |
|||
|
a3f2ffc5d9 |
|||
|
87859e629f |
|||
|
c90bfc647c |
|||
| 0bb886adab | |||
|
bf68f94682 |
15 changed files with 165 additions and 174 deletions
|
|
@ -27,6 +27,25 @@ jobs:
|
|||
run: cargo clippy --all -- -D warnings
|
||||
|
||||
- name: 🧪 Test
|
||||
run: cargo test --workspace
|
||||
run: cargo nextest run --config-file ~/.config/nextest.toml --profile ci --retries 2 -j 1 --workspace
|
||||
env:
|
||||
ALL_PROXY: "http://warpproxy:8124"
|
||||
|
||||
- name: Move test report
|
||||
if: always()
|
||||
run: mv target/nextest/ci/junit.xml junit.xml || true
|
||||
|
||||
- name: 💌 Upload test report
|
||||
if: always()
|
||||
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
||||
with:
|
||||
name: test
|
||||
path: |
|
||||
junit.xml
|
||||
|
||||
- name: 🔗 Artifactview PR comment
|
||||
if: ${{ always() && github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
if [[ "$GITEA_ACTIONS" == "true" ]]; then RUN_NUMBER="$GITHUB_RUN_NUMBER"; else RUN_NUMBER="$GITHUB_RUN_ID"; fi
|
||||
curl -SsL --fail-with-body -w "\n" -X POST https://av.thetadev.de/.well-known/api/prComment -H "Content-Type: application/json" \
|
||||
--data '{"url": "'"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$RUN_NUMBER"'", "pr": ${{ github.event.number }}, "artifact_titles": {"test":"🧪 Test report"}, "artifact_paths": {"test":"/junit.xml?viewer=1"}}'
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
renovate:
|
||||
runs-on: docker
|
||||
container:
|
||||
image: renovate/renovate:latest
|
||||
image: renovate/renovate:39
|
||||
|
||||
steps:
|
||||
- name: Load renovate repo cache
|
||||
31
CHANGELOG.md
31
CHANGELOG.md
|
|
@ -3,6 +3,37 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
|
||||
|
||||
## [v0.3.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-inofficial/v0.2.1..musixmatch-inofficial/v0.3.0) - 2025-12-08
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- [**breaking**] Removed artist_related endpoint (discontinued) - ([74d5359](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/74d5359547e0b3ffa75f5f7384ed3b7ab0e2ea11))
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Update signature secret - ([59dee61](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/59dee61a2fdbda6a7643aa209b9baaf25a6de0f8))
|
||||
- Clippy lints - ([bfe6fec](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/bfe6fec115b9ba3b58f1e949ac7b583a95041f8f))
|
||||
- Clippy lints (2) - ([09c6004](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/09c6004ed13c2f9039490c083b0e6b61dccaa884))
|
||||
- Remove serde::__private::fmt - ([e087752](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/e087752dd0d331093a3434e18b5ff276bf4dc7c1))
|
||||
|
||||
|
||||
## [v0.2.1](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-inofficial/v0.2.0..musixmatch-inofficial/v0.2.1) - 2025-04-04
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Parsing unset has_fan_chant field - ([6f90033](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/6f90033cf4284eff5c12a30aafb21943c1575b92))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Fix docs - ([4a46e7b](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/4a46e7bb1d83c6261660d403c009cdb640b301d7))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(deps)* Update rust crate governor to 0.10.0 - ([87859e6](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/87859e629f3c236ba450872b29beb7876be7ef0b))
|
||||
- *(deps)* Update rust crate rstest to 0.25.0 - ([a3f2ffc](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/a3f2ffc5d99ddddf777b4de306bd215bd3bbf5ce))
|
||||
- *(deps)* Update rust crate rand to 0.9.0 - ([7c325c4](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/7c325c4af779e32059680c1cfb874f83896d7649))
|
||||
|
||||
|
||||
## [v0.2.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-inofficial/v0.1.2..musixmatch-inofficial/v0.2.0) - 2025-01-16
|
||||
|
||||
### 🚀 Features
|
||||
|
|
|
|||
10
Cargo.toml
10
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "musixmatch-inofficial"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
rust-version = "1.70.0"
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
|
|
@ -23,7 +23,7 @@ keywords = ["music", "lyrics"]
|
|||
categories = ["api-bindings", "multimedia"]
|
||||
|
||||
[workspace.dependencies]
|
||||
musixmatch-inofficial = { version = "0.2.0", path = ".", default-features = false }
|
||||
musixmatch-inofficial = { version = "0.3.0", path = ".", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["default-tls"]
|
||||
|
|
@ -54,14 +54,14 @@ time = { version = "0.3.10", features = [
|
|||
] }
|
||||
hmac = "0.12.0"
|
||||
sha1 = "0.10.0"
|
||||
rand = "0.8.0"
|
||||
rand = "0.9.0"
|
||||
base64 = "0.22.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = { version = "0.24.0", default-features = false }
|
||||
rstest = { version = "0.26.0", default-features = false }
|
||||
dotenvy = "0.15.5"
|
||||
tokio = { version = "1.20.4", features = ["macros"] }
|
||||
futures = "0.3.21"
|
||||
path_macro = "1.0.0"
|
||||
governor = "0.8.0"
|
||||
governor = "0.10.0"
|
||||
test-log = "0.2.16"
|
||||
|
|
|
|||
2
Justfile
2
Justfile
|
|
@ -1,5 +1,5 @@
|
|||
test:
|
||||
cargo test
|
||||
cargo nextest run --workspace --no-fail-fast --retries 1 -j 1
|
||||
|
||||
release crate="musixmatch-inofficial":
|
||||
#!/usr/bin/env bash
|
||||
|
|
|
|||
|
|
@ -3,6 +3,21 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
|
||||
|
||||
## [v0.3.1](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-cli/v0.3.0..musixmatch-cli/v0.3.1) - 2025-12-08
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Clippy lints - ([bfe6fec](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/bfe6fec115b9ba3b58f1e949ac7b583a95041f8f))
|
||||
- Clippy lints (3) - ([39bbd50](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/39bbd5070a62d865c0e276904047bb687f1ba8a8))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- *(deps)* Update rust crate governor to 0.10.0 - ([87859e6](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/87859e629f3c236ba450872b29beb7876be7ef0b))
|
||||
- *(deps)* Update rust crate rstest to 0.25.0 - ([a3f2ffc](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/a3f2ffc5d99ddddf777b4de306bd215bd3bbf5ce))
|
||||
- *(deps)* Update rust crate rand to 0.9.0 - ([7c325c4](https://codeberg.org/ThetaDev/musixmatch-inofficial/commit/7c325c4af779e32059680c1cfb874f83896d7649))
|
||||
- *(deps)* Update musixmatch to 0.3.0
|
||||
|
||||
|
||||
## [v0.3.0](https://codeberg.org/ThetaDev/musixmatch-inofficial/compare/musixmatch-cli/v0.2.0..musixmatch-cli/v0.3.0) - 2025-01-16
|
||||
|
||||
### 🚀 Features
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "musixmatch-cli"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
rust-version = "1.70.0"
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ async fn main() {
|
|||
let cli = Cli::parse();
|
||||
|
||||
run(cli).await.unwrap_or_else(|e| {
|
||||
println!("Error: {}", e);
|
||||
eprintln!("Error: {e}");
|
||||
std::process::exit(1);
|
||||
});
|
||||
}
|
||||
|
|
@ -251,7 +251,7 @@ async fn run(cli: Cli) -> Result<()> {
|
|||
}
|
||||
|
||||
eprintln!();
|
||||
println!("{}", lyrics_body);
|
||||
println!("{lyrics_body}");
|
||||
}
|
||||
Commands::Subtitles {
|
||||
ident,
|
||||
|
|
@ -312,7 +312,7 @@ async fn run(cli: Cli) -> Result<()> {
|
|||
bail!("subtitle format {format:?} cant be translated")
|
||||
}
|
||||
};
|
||||
println!("{}", res);
|
||||
println!("{res}");
|
||||
} else {
|
||||
eprintln!();
|
||||
println!("{}", subtitles.subtitle_body);
|
||||
|
|
@ -471,7 +471,7 @@ async fn get_track(
|
|||
}
|
||||
|
||||
fn input(prompt: &str) -> String {
|
||||
print!("{}", prompt);
|
||||
print!("{prompt}");
|
||||
|
||||
stdout().flush().expect("Failed to flush stdout!");
|
||||
|
||||
|
|
@ -483,7 +483,7 @@ fn input(prompt: &str) -> String {
|
|||
}
|
||||
|
||||
fn input_pwd(prompt: &str) -> String {
|
||||
print!("{}", prompt);
|
||||
print!("{prompt}");
|
||||
stdout().flush().expect("Failed to flush stdout!");
|
||||
|
||||
rpassword::read_password().expect("Failed to read password")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:best-practices"
|
||||
],
|
||||
"extends": ["config:best-practices", ":preserveSemverRanges"],
|
||||
"semanticCommits": "enabled",
|
||||
"automerge": true,
|
||||
"automergeStrategy": "squash",
|
||||
|
|
|
|||
|
|
@ -444,10 +444,7 @@ pub mod optional_date {
|
|||
impl Visitor<'_> for OptionalDateVisitor {
|
||||
type Value = Option<Date>;
|
||||
|
||||
fn expecting(
|
||||
&self,
|
||||
formatter: &mut serde::__private::fmt::Formatter,
|
||||
) -> serde::__private::fmt::Result {
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("date or empty string")
|
||||
}
|
||||
|
||||
|
|
@ -504,10 +501,7 @@ pub mod optional_datetime {
|
|||
impl Visitor<'_> for OptionalDateVisitor {
|
||||
type Value = Option<OffsetDateTime>;
|
||||
|
||||
fn expecting(
|
||||
&self,
|
||||
formatter: &mut serde::__private::fmt::Formatter,
|
||||
) -> serde::__private::fmt::Result {
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("timestamp or empty string")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,40 +26,6 @@ impl Musixmatch {
|
|||
Ok(artist_body.artist)
|
||||
}
|
||||
|
||||
/// Get a list of artists somehow related to the one specified by its ID.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `id`: [Artist ID](crate::models::ArtistId)
|
||||
/// - `page_size`: Define the page size for paginated results. Range is 1 to 100.
|
||||
/// - `page`: Define the page number for paginated results, starting from 1.
|
||||
///
|
||||
/// # Reference
|
||||
/// <https://developer.musixmatch.com/documentation/api-reference/artist-related-get>
|
||||
pub async fn artist_related(
|
||||
&self,
|
||||
id: ArtistId<'_>,
|
||||
page_size: u8,
|
||||
page: u32,
|
||||
) -> Result<Vec<Artist>> {
|
||||
let mut url = self.new_url("artist.related.get");
|
||||
{
|
||||
let mut url_query = url.query_pairs_mut();
|
||||
|
||||
let id_param = id.to_param();
|
||||
url_query.append_pair(id_param.0, &id_param.1);
|
||||
url_query.append_pair("page_size", &page_size.to_string());
|
||||
url_query.append_pair("page", &page.to_string());
|
||||
url_query.finish();
|
||||
}
|
||||
|
||||
let artist_list_body = self.execute_get_request::<ArtistListBody>(&url).await?;
|
||||
Ok(artist_list_body
|
||||
.artist_list
|
||||
.into_iter()
|
||||
.map(|a| a.artist)
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Search for artists in the Musixmatch database.
|
||||
///
|
||||
/// # Parameters
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ impl Musixmatch {
|
|||
///
|
||||
/// # Reference
|
||||
/// <https://developer.musixmatch.com/documentation/api-reference/track-search>
|
||||
pub fn track_search(&self) -> TrackSearchQuery {
|
||||
pub fn track_search(&self) -> TrackSearchQuery<'_> {
|
||||
TrackSearchQuery {
|
||||
mxm: self.clone(),
|
||||
q_track: None,
|
||||
|
|
|
|||
32
src/lib.rs
32
src/lib.rs
|
|
@ -36,7 +36,7 @@ const YMD_FORMAT: &[time::format_description::FormatItem] =
|
|||
|
||||
const APP_ID: &str = "android-player-v1.0";
|
||||
const API_URL: &str = "https://apic.musixmatch.com/ws/1.1/";
|
||||
const SIGNATURE_SECRET: &[u8; 20] = b"967Pn4)N3&R_GBg5$b('";
|
||||
const SIGNATURE_SECRET: &[u8; 29] = b"mNdca@6W7TeEcFn6*3.s97sJ*yPMd";
|
||||
|
||||
const DEFAULT_UA: &str = "Dalvik/2.1.0 (Linux; U; Android 13; Pixel 6 Build/T3B2.230316.003)";
|
||||
const DEFAULT_BRAND: &str = "Google";
|
||||
|
|
@ -247,7 +247,7 @@ impl Musixmatch {
|
|||
// Get user token
|
||||
// The get_token endpoint seems to be rate limited for 2 requests per minute
|
||||
let mut url = Url::parse_with_params(
|
||||
&format!("{}{}", API_URL, "token.get"),
|
||||
&format!("{API_URL}token.get"),
|
||||
&[
|
||||
("adv_id", adv_id.as_str()),
|
||||
("root", "0"),
|
||||
|
|
@ -343,7 +343,7 @@ impl Musixmatch {
|
|||
|
||||
match serde_json::to_string(&to_store) {
|
||||
Ok(json) => storage.write(&json),
|
||||
Err(e) => error!("Could not serialize session. Error: {}", e),
|
||||
Err(e) => error!("Could not serialize session. Error: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -355,7 +355,7 @@ impl Musixmatch {
|
|||
.and_then(|json| match serde_json::from_str::<StoredSession>(&json) {
|
||||
Ok(session) => Some(session),
|
||||
Err(e) => {
|
||||
error!("Could not deserialize session. Error: {}", e);
|
||||
error!("Could not deserialize session. Error: {e}");
|
||||
None
|
||||
}
|
||||
})
|
||||
|
|
@ -374,7 +374,7 @@ impl Musixmatch {
|
|||
|
||||
fn new_url(&self, endpoint: &str) -> reqwest::Url {
|
||||
Url::parse_with_params(
|
||||
&format!("{}{}", API_URL, endpoint),
|
||||
&format!("{API_URL}{endpoint}"),
|
||||
&[("app_id", APP_ID), ("format", "json")],
|
||||
)
|
||||
.unwrap()
|
||||
|
|
@ -449,26 +449,26 @@ impl Musixmatch {
|
|||
}
|
||||
|
||||
fn random_guid() -> String {
|
||||
let mut rng = rand::thread_rng();
|
||||
let n = rng.gen::<u64>();
|
||||
format!("{:016x}", n)
|
||||
let mut rng = rand::rng();
|
||||
let n = rng.random::<u64>();
|
||||
format!("{n:016x}")
|
||||
}
|
||||
|
||||
fn random_uuid() -> String {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = rand::rng();
|
||||
format!(
|
||||
"{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
|
||||
rng.gen::<u32>(),
|
||||
rng.gen::<u16>(),
|
||||
rng.gen::<u16>(),
|
||||
rng.gen::<u16>(),
|
||||
rng.gen::<u64>() & 0xffffffffffff,
|
||||
rng.random::<u32>(),
|
||||
rng.random::<u16>(),
|
||||
rng.random::<u16>(),
|
||||
rng.random::<u16>(),
|
||||
rng.random::<u64>() & 0xffffffffffff,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_url_from_token(endpoint: &str, usertoken: &str) -> reqwest::Url {
|
||||
Url::parse_with_params(
|
||||
&format!("{}{}", API_URL, endpoint),
|
||||
&format!("{API_URL}{endpoint}"),
|
||||
&[
|
||||
("app_id", APP_ID),
|
||||
("usertoken", usertoken),
|
||||
|
|
@ -503,6 +503,6 @@ mod tests {
|
|||
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();
|
||||
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=cvXbedVvGneT7o4k8QG6jfk9pAM%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")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,18 +160,20 @@ pub struct TrackLyricsTranslationStatus {
|
|||
|
||||
/// Lyrics parts marked with the performer who is singing them
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct TrackPerformerTagging {
|
||||
/// Musixmatch user ID of the user who added the performer tags
|
||||
///
|
||||
/// Format: `mxm:<16 byte hex>`
|
||||
pub user_id: String,
|
||||
/// True if the lyrics are completely tagged
|
||||
#[serde(default)]
|
||||
pub completed: bool,
|
||||
/// True if the lyrics
|
||||
/// True if the lyrics have unknown performers
|
||||
#[serde(default)]
|
||||
pub has_unknown: bool,
|
||||
/// True if the lyrics contain parts that are intended to be sung by the
|
||||
/// audience during concerts
|
||||
#[serde(default)]
|
||||
pub has_fan_chant: bool,
|
||||
/// List of tagged lyrics parts
|
||||
#[serde(default)]
|
||||
|
|
@ -183,15 +185,14 @@ pub struct TrackPerformerTagging {
|
|||
|
||||
/// Performer-tagged lyrics part
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct PerformerTaggingPart {
|
||||
/// Part of the lyrics text
|
||||
///
|
||||
/// Includes whitespace (spaces and newline characters).
|
||||
pub snippet: String,
|
||||
/// Unbekannt
|
||||
/// Unknown
|
||||
///
|
||||
/// 0-3
|
||||
/// Values: 0-3
|
||||
pub position: u32,
|
||||
/// List of performers singing this part
|
||||
pub performers: Vec<Performer>,
|
||||
|
|
@ -199,7 +200,6 @@ pub struct PerformerTaggingPart {
|
|||
|
||||
/// Lyrics performer
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Performer {
|
||||
/// artist / unknown
|
||||
#[serde(rename = "type")]
|
||||
|
|
@ -219,7 +219,6 @@ pub struct Performer {
|
|||
/// Artists (and possibly other objects) that are referenced by the tagged parts
|
||||
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct PerformerTaggingResources {
|
||||
/// List of artists tagged as performers
|
||||
pub artists: Vec<Artist>,
|
||||
|
|
|
|||
151
tests/tests.rs
151
tests/tests.rs
|
|
@ -1,7 +1,7 @@
|
|||
use std::{
|
||||
num::NonZeroU32,
|
||||
path::{Path, PathBuf},
|
||||
sync::LazyLock,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use governor::{DefaultDirectRateLimiter, Quota, RateLimiter};
|
||||
|
|
@ -23,9 +23,9 @@ async fn mxm() -> Musixmatch {
|
|||
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(std::time::Duration::from_millis(1500)).unwrap()
|
||||
Quota::with_period(Duration::from_millis(2000)).unwrap()
|
||||
} else {
|
||||
Quota::per_second(NonZeroU32::new(4).unwrap())
|
||||
Quota::with_period(Duration::from_millis(500)).unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
|
|
@ -52,19 +52,20 @@ mod album {
|
|||
|
||||
#[rstest]
|
||||
#[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]
|
||||
async fn by_id(#[case] album_id: AlbumId<'_>, #[future] mxm: Musixmatch) {
|
||||
let album = mxm.await.album(album_id).await.unwrap();
|
||||
// dbg!(&album);
|
||||
|
||||
assert_eq!(album.album_id, 14248253);
|
||||
assert_eq!(
|
||||
album.album_mbid.unwrap(),
|
||||
"6c3cf9d8-88a8-43ed-850b-55813f01e451"
|
||||
);
|
||||
// assert_eq!(
|
||||
// album.album_mbid.expect("mbid"),
|
||||
// "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!(album.album_rating > 12);
|
||||
assert_eq!(album.album_track_count, 1);
|
||||
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);
|
||||
|
|
@ -120,7 +121,7 @@ mod album {
|
|||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, Error::NotFound));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -145,7 +146,7 @@ mod album {
|
|||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, Error::NotFound));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -162,7 +163,7 @@ mod artist {
|
|||
|
||||
#[rstest]
|
||||
#[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]
|
||||
async fn by_id(#[case] artist_id: ArtistId<'_>, #[future] mxm: Musixmatch) {
|
||||
let artist = mxm.await.artist(artist_id).await.unwrap();
|
||||
|
|
@ -171,7 +172,7 @@ mod artist {
|
|||
|
||||
assert_eq!(artist.artist_id, 410698);
|
||||
assert_eq!(
|
||||
artist.artist_mbid.unwrap(),
|
||||
artist.artist_mbid.expect("mbid"),
|
||||
"f99b7d67-4e63-4678-aa66-4c6ac0f7d24a"
|
||||
);
|
||||
assert_eq!(artist.artist_name, "PSY");
|
||||
|
|
@ -184,7 +185,11 @@ mod artist {
|
|||
artist.artist_name_translation_list
|
||||
);
|
||||
assert_eq!(artist.artist_country.unwrap(), "KR");
|
||||
assert!(artist.artist_rating > 50);
|
||||
assert!(
|
||||
artist.artist_rating > 10,
|
||||
"rating: {}",
|
||||
artist.artist_rating
|
||||
);
|
||||
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);
|
||||
|
|
@ -231,31 +236,7 @@ mod artist {
|
|||
.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));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -324,9 +305,9 @@ mod track {
|
|||
let track = mxm
|
||||
.await
|
||||
.matcher_track(
|
||||
"Poker Face",
|
||||
"Lady Gaga",
|
||||
"The Fame",
|
||||
"Du fehlst hier",
|
||||
"Silbermond",
|
||||
"Himmel auf",
|
||||
translation_status,
|
||||
lang_3c,
|
||||
false,
|
||||
|
|
@ -336,55 +317,53 @@ mod track {
|
|||
|
||||
// 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_eq!(track.track_id, 17633259);
|
||||
assert_eq!(
|
||||
track.track_mbid.unwrap(),
|
||||
"746af8c4-703e-4461-a40d-74ecdbcd755e"
|
||||
);
|
||||
assert_eq!(track.track_isrc.unwrap(), "DEE861200095");
|
||||
assert!(
|
||||
track.commontrack_isrcs[0]
|
||||
.iter()
|
||||
.any(|isrc| isrc == "USUM70824409"),
|
||||
.any(|isrc| isrc == "DEE861200095"),
|
||||
"commontrack_isrcs: {:?}",
|
||||
&track.commontrack_isrcs[0],
|
||||
);
|
||||
assert_eq!(track.track_spotify_id.unwrap(), "1QV6tiMFM6fSOKOGLMHYYg");
|
||||
assert_eq!(track.track_spotify_id.unwrap(), "3wZwbYSozyMLnJJcT3e51Q");
|
||||
assert!(
|
||||
track
|
||||
.commontrack_spotify_ids
|
||||
.iter()
|
||||
.any(|spid| spid == "1QV6tiMFM6fSOKOGLMHYYg"),
|
||||
.any(|spid| spid == "7lsi0kAFXHUCRjJzKlCZdA"),
|
||||
"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_eq!(track.track_name, "Du fehlst hier");
|
||||
assert!(track.track_rating > 25);
|
||||
assert_eq!(track.commontrack_id, 10514065);
|
||||
assert!(!track.instrumental);
|
||||
assert!(track.explicit);
|
||||
assert!(!track.explicit);
|
||||
assert!(track.has_lyrics);
|
||||
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.lyrics_id.unwrap(), 34727375);
|
||||
assert_eq!(track.subtitle_id.unwrap(), 15014656);
|
||||
assert_eq!(track.album_id, 14122870);
|
||||
assert_eq!(track.album_name, "Himmel auf");
|
||||
assert_eq!(track.artist_id, 84849);
|
||||
assert_eq!(
|
||||
track.artist_mbid.unwrap(),
|
||||
"650e7db6-b795-4eb5-a702-5ea2fc46c848"
|
||||
"34d42823-6b56-4861-a675-1565bf40d557"
|
||||
);
|
||||
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");
|
||||
assert_eq!(track.artist_name, "Silbermond");
|
||||
assert_imgurl(&track.album_coverart_100x100, "/30913494.jpg");
|
||||
assert_imgurl(&track.album_coverart_350x350, "/30913494_350_350.jpg");
|
||||
assert_imgurl(&track.album_coverart_500x500, "/30913494_500_500.jpg");
|
||||
assert_imgurl(&track.album_coverart_800x800, "/30913494_800_800.jpg");
|
||||
assert_eq!(track.commontrack_vanity_id, "Silbermond/Du-fehlst-hier");
|
||||
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));
|
||||
assert_eq!(first_release.date(), date!(2012 - 3 - 23));
|
||||
assert!(track.updated_time > datetime!(2024-2-22 11:00 UTC));
|
||||
|
||||
let first_pri_genre = &track.primary_genres.music_genre_list[0].music_genre;
|
||||
assert_eq!(first_pri_genre.music_genre_id, 14);
|
||||
|
|
@ -393,23 +372,13 @@ mod track {
|
|||
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")
|
||||
tl.from.as_deref() == Some("deu")
|
||||
} else {
|
||||
tl.from.as_deref() == Some("en")
|
||||
tl.from.as_deref() == Some("de")
|
||||
}) && tl.perc >= 0.0
|
||||
&& tl.perc <= 1.0
|
||||
}),
|
||||
|
|
@ -619,7 +588,7 @@ mod track {
|
|||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, Error::NotFound));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -672,7 +641,7 @@ mod track {
|
|||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, Error::NotFound));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -856,7 +825,7 @@ mod lyrics {
|
|||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, Error::NotFound));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
@ -1003,7 +972,7 @@ mod subtitles {
|
|||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, Error::NotFound));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
/// This track has not been synced
|
||||
|
|
@ -1021,7 +990,7 @@ mod subtitles {
|
|||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, Error::NotFound));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
/// Try to get subtitles with wrong length parameter
|
||||
|
|
@ -1039,7 +1008,7 @@ mod subtitles {
|
|||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, Error::NotFound));
|
||||
assert!(matches!(err, Error::NotFound), "got: {err:?}");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue