Add ArtistProperties

This commit is contained in:
Wojciech Kozlowski 2023-05-21 00:33:22 +02:00
parent bf5bf9d8ae
commit e3817b3c28
3 changed files with 212 additions and 1 deletions

68
Cargo.lock generated
View File

@ -184,6 +184,15 @@ dependencies = [
"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]]
name = "fragile"
version = "2.0.0"
@ -225,6 +234,16 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "instant"
version = "0.1.12"
@ -356,6 +375,7 @@ dependencies = [
"structopt",
"tempfile",
"tokio",
"url",
"uuid",
]
@ -436,6 +456,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "percent-encoding"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
@ -801,6 +827,21 @@ dependencies = [
"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]]
name = "tokio"
version = "1.27.0"
@ -859,12 +900,27 @@ dependencies = [
"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]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "unicode-segmentation"
version = "1.10.1"
@ -877,6 +933,18 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "uuid"
version = "1.3.0"

View File

@ -13,6 +13,7 @@ serde = { version = "1.0.159", features = ["derive"] }
serde_json = { version = "1.0.95", optional = true}
structopt = { version = "0.3.26", 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"] }
[dev-dependencies]

View File

@ -14,10 +14,128 @@ use std::{
use database::IDatabase;
use library::{ILibrary, Item, Query};
use serde::{Deserialize, Serialize};
use url::Url;
use uuid::Uuid;
/// [MusicBrainz Identifier](https://musicbrainz.org/doc/MusicBrainz_Identifier) (MBID).
pub type Mbid = Uuid;
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Mbid {
string: String,
uuid: Uuid,
}
impl Mbid {
pub fn new<S: Into<String>>(uuid: S) -> Result<Self, Error> {
let string: String = uuid.into();
let uuid = Uuid::try_parse(&string)?;
Ok(Mbid { string, uuid })
}
pub fn as_str(&self) -> &str {
self.string.as_str()
}
}
pub trait IUrl {
fn url(&self) -> &str;
}
pub trait IUuid {
fn uuid(&self) -> &str;
}
/// MusicBrainz reference.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct MusicBrainz {
url: Url,
mbid: Mbid,
}
impl MusicBrainz {
pub fn new<S: AsRef<str>>(url: S) -> Result<Self, Error> {
let url = Url::parse(url.as_ref())?;
let mbid: Mbid = match url.path_segments().and_then(|mut ps| ps.nth(2)) {
Some(segment) => Mbid::new(segment)?,
None => {
return Err(Error::UrlParseError(String::from(format!(
"invalid MusicBrainz URL: {}",
url.as_str()
))))
}
};
Ok(MusicBrainz { url, mbid })
}
}
impl IUrl for MusicBrainz {
fn url(&self) -> &str {
self.url.as_str()
}
}
impl IUuid for MusicBrainz {
fn uuid(&self) -> &str {
self.mbid.as_str()
}
}
/// MusicButler reference.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct MusicButler {
url: Url,
}
impl MusicButler {
pub fn new<S: AsRef<str>>(url: S) -> Result<Self, Error> {
let url = Url::parse(url.as_ref())?;
Ok(MusicButler { url })
}
}
impl IUrl for MusicButler {
fn url(&self) -> &str {
self.url.as_str()
}
}
/// Bandcamp reference.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Bandcamp {
url: Url,
}
impl Bandcamp {
pub fn new<S: AsRef<str>>(url: S) -> Result<Self, Error> {
let url = Url::parse(url.as_ref())?;
Ok(Bandcamp { url })
}
}
impl IUrl for Bandcamp {
fn url(&self) -> &str {
self.url.as_str()
}
}
/// Qobuz reference.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Qobuz {
url: Url,
}
impl Qobuz {
pub fn new<S: AsRef<str>>(url: S) -> Result<Self, Error> {
let url = Url::parse(url.as_ref())?;
Ok(Qobuz { url })
}
}
impl IUrl for Qobuz {
fn url(&self) -> &str {
self.url.as_str()
}
}
/// The track file format.
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
@ -107,6 +225,15 @@ pub struct ArtistId {
pub name: String,
}
/// The artist properties.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ArtistProperties {
pub musicbrainz: Option<MusicBrainz>,
pub musicbutler: Vec<MusicButler>,
pub bandcamp: Vec<Bandcamp>,
pub qobuz: Option<Qobuz>,
}
/// An artist.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Artist {
@ -194,6 +321,8 @@ pub enum Error {
LibraryError(String),
/// The [`MusicHoard`] failed to read/write from/to the database.
DatabaseError(String),
/// The [`MusicHoard`] failed to parse a user-provided URL.
UrlParseError(String),
}
impl fmt::Display for Error {
@ -203,6 +332,7 @@ impl fmt::Display for Error {
Self::DatabaseError(ref 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}"),
}
}
}
@ -225,6 +355,18 @@ 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())
}
}
/// The Music Hoard. It is responsible for pulling information from both the library and the
/// database, ensuring its consistent and writing back any changes.
pub struct MusicHoard<LIB, DB> {