Add code for remaining urls
This commit is contained in:
parent
3ea68d2935
commit
326b876d9c
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -273,6 +273,15 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.6"
|
||||
@ -366,6 +375,7 @@ name = "musichoard"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crossterm",
|
||||
"itertools 0.12.0",
|
||||
"mockall",
|
||||
"once_cell",
|
||||
"openssh",
|
||||
@ -476,7 +486,7 @@ checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
|
||||
dependencies = [
|
||||
"difflib",
|
||||
"float-cmp",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"normalize-line-endings",
|
||||
"predicates-core",
|
||||
"regex",
|
||||
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
crossterm = { version = "0.26.1", optional = true}
|
||||
itertools = { version = "0.12.0" }
|
||||
openssh = { version = "0.9.9", features = ["native-mux"], default-features = false, optional = true}
|
||||
ratatui = { version = "0.20.1", optional = true}
|
||||
serde = { version = "1.0.159", features = ["derive"] }
|
||||
|
@ -126,38 +126,24 @@ impl ArtistCommand {
|
||||
clear_musicbutler_urls,
|
||||
urls
|
||||
),
|
||||
ArtistCommand::Bandcamp(url_command) => {
|
||||
match url_command {
|
||||
UrlCommand::Add(_) => {
|
||||
// Add URL.
|
||||
}
|
||||
UrlCommand::Remove(_) => {
|
||||
// Remove URL if it exists.
|
||||
}
|
||||
UrlCommand::Set(_) => {
|
||||
// Set the URLs regardless of previous (if any) value.
|
||||
}
|
||||
UrlCommand::Clear(_) => {
|
||||
// Remove the URLs.
|
||||
}
|
||||
}
|
||||
}
|
||||
ArtistCommand::Qobuz(url_command) => {
|
||||
match url_command {
|
||||
UrlCommand::Add(_) => {
|
||||
// Add URL or return error if one already existss.
|
||||
}
|
||||
UrlCommand::Remove(_) => {
|
||||
// Remove URL if it exists.
|
||||
}
|
||||
UrlCommand::Set(_) => {
|
||||
// Set the URL regardless of previous (if any) value.
|
||||
}
|
||||
UrlCommand::Clear(_) => {
|
||||
// Remove the URL.
|
||||
}
|
||||
}
|
||||
}
|
||||
ArtistCommand::Bandcamp(url_command) => url_command_dispatch!(
|
||||
url_command,
|
||||
music_hoard,
|
||||
add_bandcamp_urls,
|
||||
remove_bandcamp_urls,
|
||||
set_bandcamp_urls,
|
||||
clear_bandcamp_urls,
|
||||
urls
|
||||
),
|
||||
ArtistCommand::Qobuz(url_command) => url_command_dispatch!(
|
||||
url_command,
|
||||
music_hoard,
|
||||
add_qobuz_url,
|
||||
remove_qobuz_url,
|
||||
set_qobuz_url,
|
||||
clear_qobuz_url,
|
||||
url
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
434
src/lib.rs
434
src/lib.rs
@ -6,12 +6,13 @@ pub mod library;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{HashMap, HashSet},
|
||||
fmt,
|
||||
fmt::{self, Debug},
|
||||
iter::Peekable,
|
||||
mem,
|
||||
};
|
||||
|
||||
use database::IDatabase;
|
||||
use itertools::Itertools;
|
||||
use library::{ILibrary, Item, Query};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
@ -79,6 +80,20 @@ impl MusicBrainz {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for MusicBrainz {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
MusicBrainz::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for MusicBrainz {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl IUrl for MusicBrainz {
|
||||
fn url(&self) -> &str {
|
||||
self.0.as_str()
|
||||
@ -119,6 +134,20 @@ impl MusicButler {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for MusicButler {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
MusicButler::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for MusicButler {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl IUrl for MusicButler {
|
||||
fn url(&self) -> &str {
|
||||
self.0.as_str()
|
||||
@ -152,6 +181,20 @@ impl Bandcamp {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Bandcamp {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
Bandcamp::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Bandcamp {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl IUrl for Bandcamp {
|
||||
fn url(&self) -> &str {
|
||||
self.0.as_str()
|
||||
@ -185,6 +228,20 @@ impl Qobuz {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Qobuz {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
Qobuz::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Qobuz {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl IUrl for Qobuz {
|
||||
fn url(&self) -> &str {
|
||||
self.0.as_str()
|
||||
@ -325,6 +382,46 @@ pub struct Artist {
|
||||
pub albums: Vec<Album>,
|
||||
}
|
||||
|
||||
macro_rules! artist_unique_url_dispatch {
|
||||
($add:ident, $remove:ident, $set:ident, $clear:ident, $label:literal, $field:ident) => {
|
||||
fn $add<S: AsRef<str>>(&mut self, url: S) -> Result<(), Error> {
|
||||
Self::add_unique_url(&self.id, $label, &mut self.properties.$field, url)
|
||||
}
|
||||
|
||||
fn $remove<S: AsRef<str>>(&mut self, url: S) -> Result<(), Error> {
|
||||
Self::remove_unique_url(&self.id, $label, &mut self.properties.$field, url)
|
||||
}
|
||||
|
||||
fn $set<S: AsRef<str>>(&mut self, url: S) -> Result<(), Error> {
|
||||
Self::set_unique_url(&mut self.properties.$field, url)
|
||||
}
|
||||
|
||||
fn $clear(&mut self) {
|
||||
Self::clear_unique_url(&mut self.properties.$field);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! artist_multi_url_dispatch {
|
||||
($add:ident, $remove:ident, $set:ident, $clear:ident, $label:literal, $field:ident) => {
|
||||
fn $add<S: AsRef<str>>(&mut self, urls: Vec<S>) -> Result<(), Error> {
|
||||
Self::add_multi_urls(&self.id, $label, &mut self.properties.$field, urls)
|
||||
}
|
||||
|
||||
fn $remove<S: AsRef<str>>(&mut self, urls: Vec<S>) -> Result<(), Error> {
|
||||
Self::remove_multi_urls(&self.id, $label, &mut self.properties.$field, urls)
|
||||
}
|
||||
|
||||
fn $set<S: AsRef<str>>(&mut self, urls: Vec<S>) -> Result<(), Error> {
|
||||
Self::set_multi_urls(&mut self.properties.$field, urls)
|
||||
}
|
||||
|
||||
fn $clear(&mut self) {
|
||||
Self::clear_multi_urls(&mut self.properties.$field);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Artist {
|
||||
pub fn new(id: ArtistId) -> Self {
|
||||
Artist {
|
||||
@ -334,106 +431,189 @@ impl Artist {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_musicbrainz_url<S: AsRef<str>>(&mut self, url: S) -> Result<(), Error> {
|
||||
if self.properties.musicbrainz.is_some() {
|
||||
return Err(Error::CollectionError(format!(
|
||||
"artist '{}' already has a MusicBrainz URL",
|
||||
self.id
|
||||
)));
|
||||
fn add_unique_url<
|
||||
S: AsRef<str>,
|
||||
T: for<'a> TryFrom<&'a str, Error = Error> + Eq + AsRef<str>,
|
||||
>(
|
||||
artist_id: &ArtistId,
|
||||
label: &'static str,
|
||||
container: &mut Option<T>,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
let url: T = url.as_ref().try_into()?;
|
||||
|
||||
if let Some(current) = container {
|
||||
if current == &url {
|
||||
return Err(Error::CollectionError(format!(
|
||||
"artist '{}' already has this {} URL: {}",
|
||||
artist_id,
|
||||
label,
|
||||
current.as_ref()
|
||||
)));
|
||||
} else {
|
||||
return Err(Error::CollectionError(format!(
|
||||
"artist '{}' already has a different {} URL: {}",
|
||||
artist_id,
|
||||
label,
|
||||
current.as_ref()
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
self.properties.musicbrainz = Some(MusicBrainz::new(url)?);
|
||||
_ = container.insert(url);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_musicbrainz_url<S: AsRef<str>>(&mut self, url: S) -> Result<(), Error> {
|
||||
if self.properties.musicbrainz.is_none() {
|
||||
fn remove_unique_url<
|
||||
S: AsRef<str>,
|
||||
T: for<'a> TryFrom<&'a str, Error = Error> + Eq + AsRef<str>,
|
||||
>(
|
||||
artist_id: &ArtistId,
|
||||
label: &'static str,
|
||||
container: &mut Option<T>,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
if container.is_none() {
|
||||
return Err(Error::CollectionError(format!(
|
||||
"artist '{}' does not have a MusicBrainz URL",
|
||||
self.id
|
||||
"artist '{}' does not have a {} URL",
|
||||
artist_id, label
|
||||
)));
|
||||
}
|
||||
|
||||
if self.properties.musicbrainz.as_ref().unwrap().0.as_str() == url.as_ref() {
|
||||
self.properties.musicbrainz = None;
|
||||
let url: T = url.as_ref().try_into()?;
|
||||
if container.as_ref().unwrap() == &url {
|
||||
_ = container.take();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::CollectionError(format!(
|
||||
"artist '{}' does not have this MusicBrainz URL {}",
|
||||
self.id,
|
||||
"artist '{}' does not have this {} URL: {}",
|
||||
artist_id,
|
||||
label,
|
||||
url.as_ref(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn set_musicbrainz_url<S: AsRef<str>>(&mut self, url: S) -> Result<(), Error> {
|
||||
self.properties.musicbrainz = Some(MusicBrainz::new(url)?);
|
||||
fn set_unique_url<S: AsRef<str>, T: for<'a> TryFrom<&'a str, Error = Error>>(
|
||||
container: &mut Option<T>,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
_ = container.insert(url.as_ref().try_into()?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_musicbrainz_url(&mut self) -> Result<(), Error> {
|
||||
self.properties.musicbrainz = None;
|
||||
Ok(())
|
||||
fn clear_unique_url<T>(container: &mut Option<T>) {
|
||||
_ = container.take();
|
||||
}
|
||||
|
||||
fn add_musicbutler_urls<S: AsRef<str>>(&mut self, urls: Vec<S>) -> Result<(), Error> {
|
||||
fn add_multi_urls<
|
||||
S: AsRef<str>,
|
||||
T: for<'a> TryFrom<&'a str, Error = Error> + Eq + AsRef<str>,
|
||||
>(
|
||||
artist_id: &ArtistId,
|
||||
label: &'static str,
|
||||
container: &mut Vec<T>,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
// Convert into URLs first to facilitate later comparison.
|
||||
let urls: Result<Vec<MusicButler>, Error> = urls.iter().map(MusicButler::new).collect();
|
||||
let urls: Result<Vec<T>, Error> = urls.iter().map(|url| url.as_ref().try_into()).collect();
|
||||
let mut urls = urls?;
|
||||
|
||||
// Do not check and insert. First check if any of the provided URLs already exist so that
|
||||
// the vector remains unchanged in case of failure.
|
||||
let overlap: Vec<&MusicButler> = urls
|
||||
.iter()
|
||||
.filter(|url| self.properties.musicbutler.contains(url))
|
||||
.collect();
|
||||
let overlap: Vec<&T> = urls.iter().filter(|url| container.contains(url)).collect();
|
||||
if !overlap.is_empty() {
|
||||
return Err(Error::CollectionError(format!(
|
||||
"artist '{}' already has these MusicButler URL(s): {:?}",
|
||||
self.id, overlap
|
||||
"artist '{}' already has these {} URL(s): {}",
|
||||
artist_id,
|
||||
label,
|
||||
overlap.iter().map(|url| url.as_ref()).format(", ")
|
||||
)));
|
||||
}
|
||||
|
||||
self.properties.musicbutler.append(&mut urls);
|
||||
container.append(&mut urls);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_musicbutler_urls<S: AsRef<str>>(&mut self, urls: Vec<S>) -> Result<(), Error> {
|
||||
fn remove_multi_urls<
|
||||
S: AsRef<str>,
|
||||
T: for<'a> TryFrom<&'a str, Error = Error> + Eq + AsRef<str>,
|
||||
>(
|
||||
artist_id: &ArtistId,
|
||||
label: &'static str,
|
||||
container: &mut Vec<T>,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
// Convert into URLs first to facilitate later comparison.
|
||||
let urls: Result<Vec<MusicButler>, Error> = urls.iter().map(MusicButler::new).collect();
|
||||
let urls: Result<Vec<T>, Error> = urls.iter().map(|url| url.as_ref().try_into()).collect();
|
||||
let urls = urls?;
|
||||
|
||||
// Do not check and insert. First check if any of the provided URLs already exist so that
|
||||
// the vector remains unchanged in case of failure.
|
||||
let difference: Vec<&MusicButler> = urls
|
||||
.iter()
|
||||
.filter(|url| !self.properties.musicbutler.contains(url))
|
||||
.collect();
|
||||
let difference: Vec<&T> = urls.iter().filter(|url| !container.contains(url)).collect();
|
||||
if !difference.is_empty() {
|
||||
return Err(Error::CollectionError(format!(
|
||||
"artist '{}' does not have these MusicButler URL(s): {:?}",
|
||||
self.id, difference
|
||||
"artist '{}' does not have these {} URL(s): {}",
|
||||
artist_id,
|
||||
label,
|
||||
difference.iter().map(|url| url.as_ref()).format(", ")
|
||||
)));
|
||||
}
|
||||
|
||||
let musicbutler = mem::take(&mut self.properties.musicbutler);
|
||||
self.properties.musicbutler = musicbutler
|
||||
.into_iter()
|
||||
.filter(|url| !urls.contains(url))
|
||||
.collect();
|
||||
container.retain(|url| !urls.contains(url));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_musicbutler_urls<S: AsRef<str>>(&mut self, urls: Vec<S>) -> Result<(), Error> {
|
||||
let urls: Result<Vec<MusicButler>, Error> = urls.iter().map(MusicButler::new).collect();
|
||||
self.properties.musicbutler = urls?;
|
||||
fn set_multi_urls<S: AsRef<str>, T: for<'a> TryFrom<&'a str, Error = Error>>(
|
||||
container: &mut Vec<T>,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
let urls: Result<Vec<T>, Error> = urls.iter().map(|url| url.as_ref().try_into()).collect();
|
||||
let mut urls = urls?;
|
||||
container.clear();
|
||||
container.append(&mut urls);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_musicbutler_urls(&mut self) -> Result<(), Error> {
|
||||
self.properties.musicbutler.clear();
|
||||
Ok(())
|
||||
fn clear_multi_urls<T>(container: &mut Vec<T>) {
|
||||
container.clear();
|
||||
}
|
||||
|
||||
artist_unique_url_dispatch!(
|
||||
add_musicbrainz_url,
|
||||
remove_musicbrainz_url,
|
||||
set_musicbrainz_url,
|
||||
clear_musicbrainz_url,
|
||||
"MusicBrainz",
|
||||
musicbrainz
|
||||
);
|
||||
|
||||
artist_multi_url_dispatch!(
|
||||
add_musicbutler_urls,
|
||||
remove_musicbutler_urls,
|
||||
set_musicbutler_urls,
|
||||
clear_musicbutler_urls,
|
||||
"MusicButler",
|
||||
musicbutler
|
||||
);
|
||||
|
||||
artist_multi_url_dispatch!(
|
||||
add_bandcamp_urls,
|
||||
remove_bandcamp_urls,
|
||||
set_bandcamp_urls,
|
||||
clear_bandcamp_urls,
|
||||
"Bandcamp",
|
||||
bandcamp
|
||||
);
|
||||
|
||||
artist_unique_url_dispatch!(
|
||||
add_qobuz_url,
|
||||
remove_qobuz_url,
|
||||
set_qobuz_url,
|
||||
clear_qobuz_url,
|
||||
"Qobuz",
|
||||
qobuz
|
||||
);
|
||||
}
|
||||
|
||||
impl PartialOrd for Artist {
|
||||
@ -597,6 +777,72 @@ pub struct MusicHoard<LIB, DB> {
|
||||
collection: Collection,
|
||||
}
|
||||
|
||||
macro_rules! music_hoard_unique_url_dispatch {
|
||||
($add:ident, $remove:ident, $set:ident, $clear:ident) => {
|
||||
pub fn $add<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?.$add(url)
|
||||
}
|
||||
|
||||
pub fn $remove<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?.$remove(url)
|
||||
}
|
||||
|
||||
pub fn $set<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?.$set(url)
|
||||
}
|
||||
|
||||
pub fn $clear<ID: AsRef<ArtistId>>(&mut self, artist_id: ID) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?.$clear();
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! music_hoard_multi_url_dispatch {
|
||||
($add:ident, $remove:ident, $set:ident, $clear:ident) => {
|
||||
pub fn $add<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?.$add(urls)
|
||||
}
|
||||
|
||||
pub fn $remove<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?.$remove(urls)
|
||||
}
|
||||
|
||||
pub fn $set<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?.$set(urls)
|
||||
}
|
||||
|
||||
pub fn $clear<ID: AsRef<ArtistId>>(&mut self, artist_id: ID) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?.$clear();
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<LIB: ILibrary, DB: IDatabase> MusicHoard<LIB, DB> {
|
||||
/// Create a new [`MusicHoard`] with the provided [`ILibrary`] and [`IDatabase`].
|
||||
pub fn new(library: Option<LIB>, database: Option<DB>) -> Self {
|
||||
@ -687,75 +933,33 @@ impl<LIB: ILibrary, DB: IDatabase> MusicHoard<LIB, DB> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_musicbrainz_url<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?
|
||||
.add_musicbrainz_url(url)
|
||||
}
|
||||
music_hoard_unique_url_dispatch!(
|
||||
add_musicbrainz_url,
|
||||
remove_musicbrainz_url,
|
||||
set_musicbrainz_url,
|
||||
clear_musicbrainz_url
|
||||
);
|
||||
|
||||
pub fn remove_musicbrainz_url<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?
|
||||
.remove_musicbrainz_url(url)
|
||||
}
|
||||
music_hoard_multi_url_dispatch!(
|
||||
add_musicbutler_urls,
|
||||
remove_musicbutler_urls,
|
||||
set_musicbutler_urls,
|
||||
clear_musicbutler_urls
|
||||
);
|
||||
|
||||
pub fn set_musicbrainz_url<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
url: S,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?
|
||||
.set_musicbrainz_url(url)
|
||||
}
|
||||
music_hoard_multi_url_dispatch!(
|
||||
add_bandcamp_urls,
|
||||
remove_bandcamp_urls,
|
||||
set_bandcamp_urls,
|
||||
clear_bandcamp_urls
|
||||
);
|
||||
|
||||
pub fn clear_musicbrainz_url<ID: AsRef<ArtistId>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?
|
||||
.clear_musicbrainz_url()
|
||||
}
|
||||
|
||||
pub fn add_musicbutler_urls<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?
|
||||
.add_musicbutler_urls(urls)
|
||||
}
|
||||
|
||||
pub fn remove_musicbutler_urls<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?
|
||||
.remove_musicbutler_urls(urls)
|
||||
}
|
||||
|
||||
pub fn set_musicbutler_urls<ID: AsRef<ArtistId>, S: AsRef<str>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
urls: Vec<S>,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?
|
||||
.set_musicbutler_urls(urls)
|
||||
}
|
||||
|
||||
pub fn clear_musicbutler_urls<ID: AsRef<ArtistId>>(
|
||||
&mut self,
|
||||
artist_id: ID,
|
||||
) -> Result<(), Error> {
|
||||
self.get_artist_or_err(artist_id.as_ref())?
|
||||
.clear_musicbutler_urls()
|
||||
}
|
||||
music_hoard_unique_url_dispatch!(
|
||||
add_qobuz_url,
|
||||
remove_qobuz_url,
|
||||
set_qobuz_url,
|
||||
clear_qobuz_url
|
||||
);
|
||||
|
||||
fn sort(collection: &mut [Artist]) {
|
||||
collection.sort_unstable();
|
||||
|
Loading…
Reference in New Issue
Block a user