Add ArtistProperties
This commit is contained in:
parent
bf5bf9d8ae
commit
0040a5599e
68
Cargo.lock
generated
68
Cargo.lock
generated
@ -184,6 +184,15 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "form_urlencoded"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fragile"
|
name = "fragile"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@ -225,6 +234,16 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@ -356,6 +375,7 @@ dependencies = [
|
|||||||
"structopt",
|
"structopt",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -436,6 +456,12 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
@ -801,6 +827,21 @@ dependencies = [
|
|||||||
"syn 2.0.11",
|
"syn 2.0.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.27.0"
|
version = "1.27.0"
|
||||||
@ -859,12 +900,27 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.8"
|
version = "1.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
@ -877,6 +933,18 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
@ -13,6 +13,7 @@ serde = { version = "1.0.159", features = ["derive"] }
|
|||||||
serde_json = { version = "1.0.95", optional = true}
|
serde_json = { version = "1.0.95", optional = true}
|
||||||
structopt = { version = "0.3.26", optional = true}
|
structopt = { version = "0.3.26", optional = true}
|
||||||
tokio = { version = "1.27.0", features = ["rt"], optional = true}
|
tokio = { version = "1.27.0", features = ["rt"], optional = true}
|
||||||
|
url = { version = "2.3.1", features = ["serde"] }
|
||||||
uuid = { version = "1.3.0", features = ["serde"] }
|
uuid = { version = "1.3.0", features = ["serde"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -67,7 +67,22 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::{tests::COLLECTION, Artist, ArtistId, Collection, Format};
|
use crate::{tests::COLLECTION, Artist, ArtistId, Collection, Format, IUrl};
|
||||||
|
|
||||||
|
fn opt_to_url<U: IUrl>(opt: &Option<U>) -> String {
|
||||||
|
match opt {
|
||||||
|
Some(mb) => format!("\"{}\"", mb.url()),
|
||||||
|
None => String::from("null"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vec_to_urls<U: IUrl>(vec: &Vec<U>) -> String {
|
||||||
|
let mut urls: Vec<String> = vec![];
|
||||||
|
for item in vec.iter() {
|
||||||
|
urls.push(format!("\"{}\"", item.url()));
|
||||||
|
}
|
||||||
|
format!("[{}]", urls.join(","))
|
||||||
|
}
|
||||||
|
|
||||||
fn artist_to_json(artist: &Artist) -> String {
|
fn artist_to_json(artist: &Artist) -> String {
|
||||||
let album_artist = &artist.id.name;
|
let album_artist = &artist.id.name;
|
||||||
@ -114,11 +129,25 @@ mod tests {
|
|||||||
}
|
}
|
||||||
let albums = albums.join(",");
|
let albums = albums.join(",");
|
||||||
|
|
||||||
|
let musicbrainz = opt_to_url(&artist.properties.musicbrainz);
|
||||||
|
let musicbutler = vec_to_urls(&artist.properties.musicbutler);
|
||||||
|
let bandcamp = vec_to_urls(&artist.properties.bandcamp);
|
||||||
|
let qobuz = opt_to_url(&artist.properties.qobuz);
|
||||||
|
|
||||||
|
let properties = format!(
|
||||||
|
"{{\
|
||||||
|
\"musicbrainz\":{musicbrainz},\
|
||||||
|
\"musicbutler\":{musicbutler},\
|
||||||
|
\"bandcamp\":{bandcamp},\
|
||||||
|
\"qobuz\":{qobuz}\
|
||||||
|
}}"
|
||||||
|
);
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{{\
|
"{{\
|
||||||
\"id\":{{\
|
\"id\":{{\"name\":\"{album_artist}\"}},\
|
||||||
\"name\":\"{album_artist}\"\
|
\"properties\":{properties},\
|
||||||
}},\"albums\":[{albums}]\
|
\"albums\":[{albums}]\
|
||||||
}}"
|
}}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
296
src/lib.rs
296
src/lib.rs
@ -14,10 +14,182 @@ use std::{
|
|||||||
use database::IDatabase;
|
use database::IDatabase;
|
||||||
use library::{ILibrary, Item, Query};
|
use library::{ILibrary, Item, Query};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
/// [MusicBrainz Identifier](https://musicbrainz.org/doc/MusicBrainz_Identifier) (MBID).
|
/// Object with trait contains a valid URL.
|
||||||
pub type Mbid = Uuid;
|
pub trait IUrl {
|
||||||
|
fn url(&self) -> &str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Object with trait contains a [MusicBrainz
|
||||||
|
/// Identifier](https://musicbrainz.org/doc/MusicBrainz_Identifier) (MBID).
|
||||||
|
pub trait IMbid {
|
||||||
|
fn mbid(&self) -> &str;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum UrlType {
|
||||||
|
MusicBrainz,
|
||||||
|
MusicButler,
|
||||||
|
Bandcamp,
|
||||||
|
Qobuz,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InvalidUrlError {
|
||||||
|
url_type: UrlType,
|
||||||
|
url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InvalidUrlError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "invalid url of type {:?}: {}", self.url_type, self.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MusicBrainz reference.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct MusicBrainz(Url);
|
||||||
|
|
||||||
|
impl MusicBrainz {
|
||||||
|
pub fn new<S: AsRef<str>>(url: S) -> Result<Self, Error> {
|
||||||
|
let url = Url::parse(url.as_ref())?;
|
||||||
|
|
||||||
|
if !url
|
||||||
|
.domain()
|
||||||
|
.map(|u| u.ends_with("musicbrainz.org"))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return Err(Self::invalid_url_error(url).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
match url.path_segments().and_then(|mut ps| ps.nth(1)) {
|
||||||
|
Some(segment) => Uuid::try_parse(segment)?,
|
||||||
|
None => return Err(Self::invalid_url_error(url).into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(MusicBrainz(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalid_url_error<S: Into<String>>(url: S) -> InvalidUrlError {
|
||||||
|
InvalidUrlError {
|
||||||
|
url_type: UrlType::MusicBrainz,
|
||||||
|
url: url.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IUrl for MusicBrainz {
|
||||||
|
fn url(&self) -> &str {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IMbid for MusicBrainz {
|
||||||
|
fn mbid(&self) -> &str {
|
||||||
|
// The URL is assumed to have been validated.
|
||||||
|
self.0.path_segments().and_then(|mut ps| ps.nth(1)).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MusicButler reference.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct MusicButler(Url);
|
||||||
|
|
||||||
|
impl MusicButler {
|
||||||
|
pub fn new<S: AsRef<str>>(url: S) -> Result<Self, Error> {
|
||||||
|
let url = Url::parse(url.as_ref())?;
|
||||||
|
|
||||||
|
if !url
|
||||||
|
.domain()
|
||||||
|
.map(|u| u.ends_with("musicbutler.io"))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return Err(Self::invalid_url_error(url).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(MusicButler(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalid_url_error<S: Into<String>>(url: S) -> InvalidUrlError {
|
||||||
|
InvalidUrlError {
|
||||||
|
url_type: UrlType::MusicButler,
|
||||||
|
url: url.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IUrl for MusicButler {
|
||||||
|
fn url(&self) -> &str {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bandcamp reference.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct Bandcamp(Url);
|
||||||
|
|
||||||
|
impl Bandcamp {
|
||||||
|
pub fn new<S: AsRef<str>>(url: S) -> Result<Self, Error> {
|
||||||
|
let url = Url::parse(url.as_ref())?;
|
||||||
|
|
||||||
|
if !url
|
||||||
|
.domain()
|
||||||
|
.map(|u| u.ends_with("bandcamp.com"))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return Err(Self::invalid_url_error(url).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Bandcamp(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalid_url_error<S: Into<String>>(url: S) -> InvalidUrlError {
|
||||||
|
InvalidUrlError {
|
||||||
|
url_type: UrlType::Bandcamp,
|
||||||
|
url: url.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IUrl for Bandcamp {
|
||||||
|
fn url(&self) -> &str {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Qobuz reference.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct Qobuz(Url);
|
||||||
|
|
||||||
|
impl Qobuz {
|
||||||
|
pub fn new<S: AsRef<str>>(url: S) -> Result<Self, Error> {
|
||||||
|
let url = Url::parse(url.as_ref())?;
|
||||||
|
|
||||||
|
if !url
|
||||||
|
.domain()
|
||||||
|
.map(|u| u.ends_with("qobuz.com"))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return Err(Self::invalid_url_error(url).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Qobuz(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalid_url_error<S: Into<String>>(url: S) -> InvalidUrlError {
|
||||||
|
InvalidUrlError {
|
||||||
|
url_type: UrlType::Qobuz,
|
||||||
|
url: url.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IUrl for Qobuz {
|
||||||
|
fn url(&self) -> &str {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The track file format.
|
/// The track file format.
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
@ -107,10 +279,20 @@ pub struct ArtistId {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The artist properties.
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct ArtistProperties {
|
||||||
|
pub musicbrainz: Option<MusicBrainz>,
|
||||||
|
pub musicbutler: Vec<MusicButler>,
|
||||||
|
pub bandcamp: Vec<Bandcamp>,
|
||||||
|
pub qobuz: Option<Qobuz>,
|
||||||
|
}
|
||||||
|
|
||||||
/// An artist.
|
/// An artist.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
pub struct Artist {
|
pub struct Artist {
|
||||||
pub id: ArtistId,
|
pub id: ArtistId,
|
||||||
|
pub properties: ArtistProperties,
|
||||||
pub albums: Vec<Album>,
|
pub albums: Vec<Album>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,6 +376,10 @@ pub enum Error {
|
|||||||
LibraryError(String),
|
LibraryError(String),
|
||||||
/// The [`MusicHoard`] failed to read/write from/to the database.
|
/// The [`MusicHoard`] failed to read/write from/to the database.
|
||||||
DatabaseError(String),
|
DatabaseError(String),
|
||||||
|
/// The [`MusicHoard`] failed to parse a user-provided URL.
|
||||||
|
UrlParseError(String),
|
||||||
|
/// The user-provided URL is not valid.
|
||||||
|
InvalidUrlError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@ -203,6 +389,8 @@ impl fmt::Display for Error {
|
|||||||
Self::DatabaseError(ref s) => {
|
Self::DatabaseError(ref s) => {
|
||||||
write!(f, "failed to read/write from/to the database: {s}")
|
write!(f, "failed to read/write from/to the database: {s}")
|
||||||
}
|
}
|
||||||
|
Self::UrlParseError(ref s) => write!(f, "failed to parse a user-provided URL: {s}"),
|
||||||
|
Self::InvalidUrlError(ref s) => write!(f, "user-provided URL is invalid: {s}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,6 +413,24 @@ impl From<database::SaveError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<url::ParseError> for Error {
|
||||||
|
fn from(err: url::ParseError) -> Error {
|
||||||
|
Error::UrlParseError(err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<uuid::Error> for Error {
|
||||||
|
fn from(err: uuid::Error) -> Error {
|
||||||
|
Error::UrlParseError(err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<InvalidUrlError> for Error {
|
||||||
|
fn from(err: InvalidUrlError) -> Error {
|
||||||
|
Error::InvalidUrlError(err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The Music Hoard. It is responsible for pulling information from both the library and the
|
/// The Music Hoard. It is responsible for pulling information from both the library and the
|
||||||
/// database, ensuring its consistent and writing back any changes.
|
/// database, ensuring its consistent and writing back any changes.
|
||||||
pub struct MusicHoard<LIB, DB> {
|
pub struct MusicHoard<LIB, DB> {
|
||||||
@ -327,6 +533,7 @@ impl<LIB: ILibrary, DB: IDatabase> MusicHoard<LIB, DB> {
|
|||||||
album_ids.insert(artist_id.clone(), HashSet::<AlbumId>::new());
|
album_ids.insert(artist_id.clone(), HashSet::<AlbumId>::new());
|
||||||
artists.push(Artist {
|
artists.push(Artist {
|
||||||
id: artist_id.clone(),
|
id: artist_id.clone(),
|
||||||
|
properties: ArtistProperties::default(),
|
||||||
albums: vec![],
|
albums: vec![],
|
||||||
});
|
});
|
||||||
artists.last_mut().unwrap()
|
artists.last_mut().unwrap()
|
||||||
@ -403,6 +610,72 @@ mod tests {
|
|||||||
items
|
items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clean_collection(mut collection: Collection) -> Collection {
|
||||||
|
for artist in collection.iter_mut() {
|
||||||
|
artist.properties = ArtistProperties::default();
|
||||||
|
}
|
||||||
|
collection
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn musicbrainz() {
|
||||||
|
let uuid = "d368baa8-21ca-4759-9731-0b2753071ad8";
|
||||||
|
let url = format!("https://musicbrainz.org/artist/{uuid}");
|
||||||
|
let mb = MusicBrainz::new(&url).unwrap();
|
||||||
|
assert_eq!(url, mb.url());
|
||||||
|
assert_eq!(uuid, mb.mbid());
|
||||||
|
|
||||||
|
let url = format!("not a url at all");
|
||||||
|
let expected_error: Error = url::ParseError::RelativeUrlWithoutBase.into();
|
||||||
|
let actual_error = MusicBrainz::new(&url).unwrap_err();
|
||||||
|
assert_eq!(actual_error, expected_error);
|
||||||
|
assert_eq!(actual_error.to_string(), expected_error.to_string());
|
||||||
|
|
||||||
|
let url = format!("https://musicbrainz.org/artist/i-am-not-a-uuid");
|
||||||
|
let expected_error: Error = Uuid::try_parse("i-am-not-a-uuid").unwrap_err().into();
|
||||||
|
let actual_error = MusicBrainz::new(&url).unwrap_err();
|
||||||
|
assert_eq!(actual_error, expected_error);
|
||||||
|
assert_eq!(actual_error.to_string(), expected_error.to_string());
|
||||||
|
|
||||||
|
let url = format!("https://musicbrainz.org/artist");
|
||||||
|
let expected_error: Error = InvalidUrlError {
|
||||||
|
url_type: UrlType::MusicBrainz,
|
||||||
|
url: url.clone(),
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
let actual_error = MusicBrainz::new(&url).unwrap_err();
|
||||||
|
assert_eq!(actual_error, expected_error);
|
||||||
|
assert_eq!(actual_error.to_string(), expected_error.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn urls() {
|
||||||
|
let musicbrainz = "https://musicbrainz.org/artist/d368baa8-21ca-4759-9731-0b2753071ad8";
|
||||||
|
let musicbutler = "https://www.musicbutler.io/artist-page/483340948";
|
||||||
|
let bandcamp = "https://thelasthangmen.bandcamp.com/";
|
||||||
|
let qobuz = "https://www.qobuz.com/nl-nl/interpreter/the-last-hangmen/1244413";
|
||||||
|
|
||||||
|
assert!(MusicBrainz::new(&musicbrainz).is_ok());
|
||||||
|
assert!(MusicBrainz::new(&musicbutler).is_err());
|
||||||
|
assert!(MusicBrainz::new(&bandcamp).is_err());
|
||||||
|
assert!(MusicBrainz::new(&qobuz).is_err());
|
||||||
|
|
||||||
|
assert!(MusicButler::new(&musicbrainz).is_err());
|
||||||
|
assert!(MusicButler::new(&musicbutler).is_ok());
|
||||||
|
assert!(MusicButler::new(&bandcamp).is_err());
|
||||||
|
assert!(MusicButler::new(&qobuz).is_err());
|
||||||
|
|
||||||
|
assert!(Bandcamp::new(&musicbrainz).is_err());
|
||||||
|
assert!(Bandcamp::new(&musicbutler).is_err());
|
||||||
|
assert!(Bandcamp::new(&bandcamp).is_ok());
|
||||||
|
assert!(Bandcamp::new(&qobuz).is_err());
|
||||||
|
|
||||||
|
assert!(Qobuz::new(&musicbrainz).is_err());
|
||||||
|
assert!(Qobuz::new(&musicbutler).is_err());
|
||||||
|
assert!(Qobuz::new(&bandcamp).is_err());
|
||||||
|
assert!(Qobuz::new(&qobuz).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn merge_track() {
|
fn merge_track() {
|
||||||
let left = Track {
|
let left = Track {
|
||||||
@ -536,7 +809,10 @@ mod tests {
|
|||||||
let mut music_hoard = MusicHoard::new(library, database);
|
let mut music_hoard = MusicHoard::new(library, database);
|
||||||
|
|
||||||
music_hoard.rescan_library().unwrap();
|
music_hoard.rescan_library().unwrap();
|
||||||
assert_eq!(music_hoard.get_collection(), &*COLLECTION);
|
assert_eq!(
|
||||||
|
music_hoard.get_collection(),
|
||||||
|
&clean_collection(COLLECTION.to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -560,7 +836,10 @@ mod tests {
|
|||||||
let mut music_hoard = MusicHoard::new(library, database);
|
let mut music_hoard = MusicHoard::new(library, database);
|
||||||
|
|
||||||
music_hoard.rescan_library().unwrap();
|
music_hoard.rescan_library().unwrap();
|
||||||
assert_eq!(music_hoard.get_collection(), &*COLLECTION);
|
assert_eq!(
|
||||||
|
music_hoard.get_collection(),
|
||||||
|
&clean_collection(COLLECTION.to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -568,7 +847,7 @@ mod tests {
|
|||||||
let mut library = MockILibrary::new();
|
let mut library = MockILibrary::new();
|
||||||
let database = MockIDatabase::new();
|
let database = MockIDatabase::new();
|
||||||
|
|
||||||
let mut expected = COLLECTION.to_owned();
|
let mut expected = clean_collection(COLLECTION.to_owned());
|
||||||
expected[0].albums[0].id.year = expected[1].albums[0].id.year;
|
expected[0].albums[0].id.year = expected[1].albums[0].id.year;
|
||||||
expected[0].albums[0].id.title = expected[1].albums[0].id.title.clone();
|
expected[0].albums[0].id.title = expected[1].albums[0].id.title.clone();
|
||||||
|
|
||||||
@ -614,7 +893,7 @@ mod tests {
|
|||||||
let library_input = Query::new();
|
let library_input = Query::new();
|
||||||
let library_result = Ok(artists_to_items(&COLLECTION));
|
let library_result = Ok(artists_to_items(&COLLECTION));
|
||||||
|
|
||||||
let database_input = COLLECTION.to_owned();
|
let database_input = clean_collection(COLLECTION.to_owned());
|
||||||
let database_result = Ok(());
|
let database_result = Ok(());
|
||||||
|
|
||||||
library
|
library
|
||||||
@ -632,7 +911,10 @@ mod tests {
|
|||||||
let mut music_hoard = MusicHoard::new(library, database);
|
let mut music_hoard = MusicHoard::new(library, database);
|
||||||
|
|
||||||
music_hoard.rescan_library().unwrap();
|
music_hoard.rescan_library().unwrap();
|
||||||
assert_eq!(music_hoard.get_collection(), &*COLLECTION);
|
assert_eq!(
|
||||||
|
music_hoard.get_collection(),
|
||||||
|
&clean_collection(COLLECTION.to_owned())
|
||||||
|
);
|
||||||
music_hoard.save_to_database().unwrap();
|
music_hoard.save_to_database().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,20 @@ macro_rules! collection {
|
|||||||
id: ArtistId {
|
id: ArtistId {
|
||||||
name: "album_artist a".to_string(),
|
name: "album_artist a".to_string(),
|
||||||
},
|
},
|
||||||
|
properties: ArtistProperties {
|
||||||
|
musicbrainz: Some(MusicBrainz::new(
|
||||||
|
"https://musicbrainz.org/artist/00000000-0000-0000-0000-000000000000",
|
||||||
|
).unwrap()),
|
||||||
|
musicbutler: vec![
|
||||||
|
MusicButler::new(
|
||||||
|
"https://www.musicbutler.io/artist-page/000000000"
|
||||||
|
).unwrap(),
|
||||||
|
],
|
||||||
|
bandcamp: vec![],
|
||||||
|
qobuz: Some(Qobuz::new(
|
||||||
|
"https://www.qobuz.com/nl-nl/interpreter/artist-a/download-streaming-albums",
|
||||||
|
).unwrap()),
|
||||||
|
},
|
||||||
albums: vec![
|
albums: vec![
|
||||||
Album {
|
Album {
|
||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
@ -86,6 +100,25 @@ macro_rules! collection {
|
|||||||
id: ArtistId {
|
id: ArtistId {
|
||||||
name: "album_artist b".to_string(),
|
name: "album_artist b".to_string(),
|
||||||
},
|
},
|
||||||
|
properties: ArtistProperties {
|
||||||
|
musicbrainz: Some(MusicBrainz::new(
|
||||||
|
"https://musicbrainz.org/artist/11111111-1111-1111-1111-111111111111",
|
||||||
|
).unwrap()),
|
||||||
|
musicbutler: vec![
|
||||||
|
MusicButler::new(
|
||||||
|
"https://www.musicbutler.io/artist-page/111111111"
|
||||||
|
).unwrap(),
|
||||||
|
MusicButler::new(
|
||||||
|
"https://www.musicbutler.io/artist-page/111111112"
|
||||||
|
).unwrap(),
|
||||||
|
],
|
||||||
|
bandcamp: vec![
|
||||||
|
Bandcamp::new("https://artist-b.bandcamp.com/").unwrap(),
|
||||||
|
],
|
||||||
|
qobuz: Some(Qobuz::new(
|
||||||
|
"https://www.qobuz.com/nl-nl/interpreter/artist-b/download-streaming-albums",
|
||||||
|
).unwrap()),
|
||||||
|
},
|
||||||
albums: vec![
|
albums: vec![
|
||||||
Album {
|
Album {
|
||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
@ -159,6 +192,14 @@ macro_rules! collection {
|
|||||||
id: ArtistId {
|
id: ArtistId {
|
||||||
name: "album_artist c".to_string(),
|
name: "album_artist c".to_string(),
|
||||||
},
|
},
|
||||||
|
properties: ArtistProperties {
|
||||||
|
musicbrainz: Some(MusicBrainz::new(
|
||||||
|
"https://musicbrainz.org/artist/11111111-1111-1111-1111-111111111111",
|
||||||
|
).unwrap()),
|
||||||
|
musicbutler: vec![],
|
||||||
|
bandcamp: vec![],
|
||||||
|
qobuz: None,
|
||||||
|
},
|
||||||
albums: vec![
|
albums: vec![
|
||||||
Album {
|
Album {
|
||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
|
File diff suppressed because one or more lines are too long
69
tests/lib.rs
69
tests/lib.rs
@ -1,15 +1,32 @@
|
|||||||
mod database;
|
mod database;
|
||||||
mod library;
|
mod library;
|
||||||
|
|
||||||
use musichoard::{Album, AlbumId, Artist, ArtistId, Format, Quality, Track, TrackId};
|
use musichoard::{
|
||||||
|
Album, AlbumId, Artist, ArtistId, ArtistProperties, Bandcamp, Collection, Format, MusicBrainz,
|
||||||
|
MusicButler, Qobuz, Quality, Track, TrackId,
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| {
|
static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
|
||||||
vec![
|
vec![
|
||||||
Artist {
|
Artist {
|
||||||
id: ArtistId {
|
id: ArtistId {
|
||||||
name: String::from("Аркона"),
|
name: String::from("Аркона"),
|
||||||
},
|
},
|
||||||
|
properties: ArtistProperties {
|
||||||
|
musicbrainz: Some(MusicBrainz::new(
|
||||||
|
"https://musicbrainz.org/artist/baad262d-55ef-427a-83c7-f7530964f212",
|
||||||
|
).unwrap()),
|
||||||
|
musicbutler: vec![
|
||||||
|
MusicButler::new("https://www.musicbutler.io/artist-page/283448581").unwrap(),
|
||||||
|
],
|
||||||
|
bandcamp: vec![
|
||||||
|
Bandcamp::new("https://arkonamoscow.bandcamp.com/").unwrap(),
|
||||||
|
],
|
||||||
|
qobuz: Some(Qobuz::new(
|
||||||
|
"https://www.qobuz.com/nl-nl/interpreter/arkona/download-streaming-albums",
|
||||||
|
).unwrap()),
|
||||||
|
},
|
||||||
albums: vec![Album {
|
albums: vec![Album {
|
||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
year: 2011,
|
year: 2011,
|
||||||
@ -177,6 +194,18 @@ static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| {
|
|||||||
id: ArtistId {
|
id: ArtistId {
|
||||||
name: String::from("Eluveitie"),
|
name: String::from("Eluveitie"),
|
||||||
},
|
},
|
||||||
|
properties: ArtistProperties {
|
||||||
|
musicbrainz: Some(MusicBrainz::new(
|
||||||
|
"https://musicbrainz.org/artist/8000598a-5edb-401c-8e6d-36b167feaf38",
|
||||||
|
).unwrap()),
|
||||||
|
musicbutler: vec![
|
||||||
|
MusicButler::new("https://www.musicbutler.io/artist-page/269358403").unwrap(),
|
||||||
|
],
|
||||||
|
bandcamp: vec![],
|
||||||
|
qobuz: Some(Qobuz::new(
|
||||||
|
"https://www.qobuz.com/nl-nl/interpreter/eluveitie/download-streaming-albums",
|
||||||
|
).unwrap()),
|
||||||
|
},
|
||||||
albums: vec![
|
albums: vec![
|
||||||
Album {
|
Album {
|
||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
@ -398,6 +427,18 @@ static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| {
|
|||||||
id: ArtistId {
|
id: ArtistId {
|
||||||
name: String::from("Frontside"),
|
name: String::from("Frontside"),
|
||||||
},
|
},
|
||||||
|
properties: ArtistProperties {
|
||||||
|
musicbrainz: Some(MusicBrainz::new(
|
||||||
|
"https://musicbrainz.org/artist/3a901353-fccd-4afd-ad01-9c03f451b490",
|
||||||
|
).unwrap()),
|
||||||
|
musicbutler: vec![
|
||||||
|
MusicButler::new("https://www.musicbutler.io/artist-page/826588800").unwrap(),
|
||||||
|
],
|
||||||
|
bandcamp: vec![],
|
||||||
|
qobuz: Some(Qobuz::new(
|
||||||
|
"https://www.qobuz.com/nl-nl/interpreter/frontside/download-streaming-albums",
|
||||||
|
).unwrap()),
|
||||||
|
},
|
||||||
albums: vec![Album {
|
albums: vec![Album {
|
||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
year: 2001,
|
year: 2001,
|
||||||
@ -532,6 +573,18 @@ static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| {
|
|||||||
id: ArtistId {
|
id: ArtistId {
|
||||||
name: String::from("Heaven’s Basement"),
|
name: String::from("Heaven’s Basement"),
|
||||||
},
|
},
|
||||||
|
properties: ArtistProperties {
|
||||||
|
musicbrainz: Some(MusicBrainz::new(
|
||||||
|
"https://musicbrainz.org/artist/c2c4d56a-d599-4a18-bd2f-ae644e2198cc",
|
||||||
|
).unwrap()),
|
||||||
|
musicbutler: vec![
|
||||||
|
MusicButler::new("https://www.musicbutler.io/artist-page/291158685").unwrap(),
|
||||||
|
],
|
||||||
|
bandcamp: vec![],
|
||||||
|
qobuz: Some(Qobuz::new(
|
||||||
|
"https://www.qobuz.com/nl-nl/interpreter/heaven-s-basement/download-streaming-albums",
|
||||||
|
).unwrap()),
|
||||||
|
},
|
||||||
albums: vec![Album {
|
albums: vec![Album {
|
||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
year: 2011,
|
year: 2011,
|
||||||
@ -622,6 +675,18 @@ static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| {
|
|||||||
id: ArtistId {
|
id: ArtistId {
|
||||||
name: String::from("Metallica"),
|
name: String::from("Metallica"),
|
||||||
},
|
},
|
||||||
|
properties: ArtistProperties {
|
||||||
|
musicbrainz: Some(MusicBrainz::new(
|
||||||
|
"https://musicbrainz.org/artist/65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab",
|
||||||
|
).unwrap()),
|
||||||
|
musicbutler: vec![
|
||||||
|
MusicButler::new("https://www.musicbutler.io/artist-page/3996865").unwrap(),
|
||||||
|
],
|
||||||
|
bandcamp: vec![],
|
||||||
|
qobuz: Some(Qobuz::new(
|
||||||
|
"https://www.qobuz.com/nl-nl/interpreter/metallica/download-streaming-albums",
|
||||||
|
).unwrap()),
|
||||||
|
},
|
||||||
albums: vec![
|
albums: vec![
|
||||||
Album {
|
Album {
|
||||||
id: AlbumId {
|
id: AlbumId {
|
||||||
|
Loading…
Reference in New Issue
Block a user