Add method to manually add artist metadata #85
@ -30,6 +30,7 @@ jobs:
|
||||
--ignore-not-existing
|
||||
--ignore "tests/*"
|
||||
--ignore "src/main.rs"
|
||||
--ignore "src/bin/mh-edit.rs"
|
||||
--excl-start "GRCOV_EXCL_START|mod tests \{"
|
||||
--excl-stop "GRCOV_EXCL_STOP"
|
||||
--output-path ./target/debug/coverage/
|
||||
|
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -369,6 +369,7 @@ dependencies = [
|
||||
"mockall",
|
||||
"once_cell",
|
||||
"openssh",
|
||||
"paste",
|
||||
"ratatui",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -456,6 +457,12 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
|
10
Cargo.toml
10
Cargo.toml
@ -8,6 +8,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
crossterm = { version = "0.26.1", optional = true}
|
||||
openssh = { version = "0.9.9", features = ["native-mux"], default-features = false, optional = true}
|
||||
paste = { version = "1.0.14" }
|
||||
ratatui = { version = "0.20.1", optional = true}
|
||||
serde = { version = "1.0.159", features = ["derive"] }
|
||||
serde_json = { version = "1.0.95", optional = true}
|
||||
@ -23,14 +24,19 @@ tempfile = "3.5.0"
|
||||
|
||||
[features]
|
||||
default = ["database-json", "library-beets"]
|
||||
bin = ["structopt"]
|
||||
database-json = ["serde_json"]
|
||||
library-beets = []
|
||||
ssh-library = ["openssh", "tokio"]
|
||||
tui = ["structopt", "crossterm", "ratatui"]
|
||||
tui = ["crossterm", "ratatui"]
|
||||
|
||||
[[bin]]
|
||||
name = "musichoard"
|
||||
required-features = ["database-json", "library-beets", "ssh-library", "tui"]
|
||||
required-features = ["bin", "database-json", "library-beets", "ssh-library", "tui"]
|
||||
|
||||
[[bin]]
|
||||
name = "mh-edit"
|
||||
required-features = ["bin", "database-json"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -32,6 +32,7 @@ grcov codecov/debug/profraw \
|
||||
--ignore-not-existing \
|
||||
--ignore "tests/*" \
|
||||
--ignore "src/main.rs" \
|
||||
--ignore "src/bin/mh-edit.rs" \
|
||||
--excl-start "GRCOV_EXCL_START|mod tests \{" \
|
||||
--excl-stop "GRCOV_EXCL_STOP" \
|
||||
--output-path ./codecov/debug/coverage/
|
||||
|
179
src/bin/mh-edit.rs
Normal file
179
src/bin/mh-edit.rs
Normal file
@ -0,0 +1,179 @@
|
||||
use paste::paste;
|
||||
use std::path::PathBuf;
|
||||
use structopt::{clap::AppSettings, StructOpt};
|
||||
|
||||
use musichoard::{
|
||||
database::json::{backend::JsonDatabaseFileBackend, JsonDatabase},
|
||||
library::NoLibrary,
|
||||
ArtistId, MusicHoard,
|
||||
};
|
||||
|
||||
type MH = MusicHoard<NoLibrary, JsonDatabase<JsonDatabaseFileBackend>>;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(about = "mh-edit: edit the MusicHoard database",
|
||||
global_settings=&[AppSettings::DeriveDisplayOrder])]
|
||||
struct Opt {
|
||||
#[structopt(
|
||||
long = "database",
|
||||
name = "database file path",
|
||||
default_value = "database.json"
|
||||
)]
|
||||
database_file_path: PathBuf,
|
||||
|
||||
#[structopt(subcommand)]
|
||||
category: Category,
|
||||
}
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
enum Category {
|
||||
#[structopt(about = "Edit artist information")]
|
||||
Artist(ArtistCommand),
|
||||
}
|
||||
|
||||
impl Category {
|
||||
fn handle(self, music_hoard: &mut MH) {
|
||||
match self {
|
||||
Category::Artist(artist_command) => artist_command.handle(music_hoard),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
enum ArtistCommand {
|
||||
#[structopt(about = "Add a new artist to the collection")]
|
||||
New(ArtistValue),
|
||||
#[structopt(about = "Delete an artist from the collection")]
|
||||
Delete(ArtistValue),
|
||||
#[structopt(name = "musicbrainz", about = "Edit the MusicBrainz URL of an artist")]
|
||||
MusicBrainz(UrlCommand<SingleUrlValue>),
|
||||
#[structopt(
|
||||
name = "musicbutler",
|
||||
about = "Edit the MusicButler URL(s) of an artist"
|
||||
)]
|
||||
MusicButler(UrlCommand<MultiUrlValue>),
|
||||
#[structopt(about = "Edit the Bandcamp URL(s) of an artist")]
|
||||
Bandcamp(UrlCommand<MultiUrlValue>),
|
||||
#[structopt(about = "Edit the Qobuz URL of an artist")]
|
||||
Qobuz(UrlCommand<SingleUrlValue>),
|
||||
}
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
struct ArtistValue {
|
||||
#[structopt(help = "The name of the artist")]
|
||||
artist: String,
|
||||
}
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
enum UrlCommand<T: StructOpt> {
|
||||
#[structopt(about = "Add the provided URL(s) without overwriting existing values")]
|
||||
Add(T),
|
||||
#[structopt(about = "Remove the provided URL(s)")]
|
||||
Remove(T),
|
||||
#[structopt(about = "Set the provided URL(s) overwriting any existing values")]
|
||||
Set(T),
|
||||
#[structopt(about = "Clear all URL(s)")]
|
||||
Clear(ArtistValue),
|
||||
}
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
struct SingleUrlValue {
|
||||
#[structopt(help = "The name of the artist")]
|
||||
artist: String,
|
||||
#[structopt(help = "The URL")]
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
struct MultiUrlValue {
|
||||
#[structopt(help = "The name of the artist")]
|
||||
artist: String,
|
||||
#[structopt(help = "The list of URLs")]
|
||||
urls: Vec<String>,
|
||||
}
|
||||
|
||||
macro_rules! url_command_dispatch {
|
||||
($cmd:ident, $mh:ident, $field:ident, $url:ident) => {
|
||||
paste! {
|
||||
match $cmd {
|
||||
UrlCommand::Add(url_value) => {
|
||||
$mh.[<add_ $field _ $url>](ArtistId::new(url_value.artist), url_value.$url)
|
||||
.expect("failed to add URL(s)");
|
||||
}
|
||||
UrlCommand::Remove(url_value) => {
|
||||
$mh.[<remove_ $field _ $url>](ArtistId::new(url_value.artist), url_value.$url)
|
||||
.expect("failed to remove URL(s)");
|
||||
}
|
||||
UrlCommand::Set(url_value) => {
|
||||
$mh.[<set_ $field _ $url>](ArtistId::new(url_value.artist), url_value.$url)
|
||||
.expect("failed to set URL(s)");
|
||||
}
|
||||
UrlCommand::Clear(artist_value) => {
|
||||
$mh.[<clear_ $field _ $url>](ArtistId::new(artist_value.artist))
|
||||
.expect("failed to clear URL(s)");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! single_url_command_dispatch {
|
||||
($cmd:ident, $mh:ident, $field:ident) => {
|
||||
url_command_dispatch!($cmd, $mh, $field, url)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! multi_url_command_dispatch {
|
||||
($cmd:ident, $mh:ident, $field:ident) => {
|
||||
url_command_dispatch!($cmd, $mh, $field, urls)
|
||||
};
|
||||
}
|
||||
|
||||
impl ArtistCommand {
|
||||
fn handle(self, music_hoard: &mut MH) {
|
||||
match self {
|
||||
ArtistCommand::New(artist_value) => {
|
||||
music_hoard
|
||||
.new_artist(ArtistId::new(artist_value.artist))
|
||||
.expect("failed to add new artist");
|
||||
}
|
||||
ArtistCommand::Delete(artist_value) => {
|
||||
music_hoard
|
||||
.delete_artist(ArtistId::new(artist_value.artist))
|
||||
.expect("failed to delete artist");
|
||||
}
|
||||
ArtistCommand::MusicBrainz(url_command) => {
|
||||
single_url_command_dispatch!(url_command, music_hoard, musicbrainz)
|
||||
}
|
||||
ArtistCommand::MusicButler(url_command) => {
|
||||
multi_url_command_dispatch!(url_command, music_hoard, musicbutler)
|
||||
}
|
||||
ArtistCommand::Bandcamp(url_command) => {
|
||||
multi_url_command_dispatch!(url_command, music_hoard, bandcamp)
|
||||
}
|
||||
ArtistCommand::Qobuz(url_command) => {
|
||||
single_url_command_dispatch!(url_command, music_hoard, qobuz)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let opt = Opt::from_args();
|
||||
|
||||
let lib: Option<NoLibrary> = None;
|
||||
let db = Some(JsonDatabase::new(JsonDatabaseFileBackend::new(
|
||||
&opt.database_file_path,
|
||||
)));
|
||||
|
||||
let mut music_hoard = MusicHoard::new(lib, db);
|
||||
music_hoard
|
||||
.load_from_database()
|
||||
.expect("failed to load database");
|
||||
|
||||
opt.category.handle(&mut music_hoard);
|
||||
|
||||
music_hoard
|
||||
.save_to_database()
|
||||
.expect("failed to save database");
|
||||
}
|
1053
src/lib.rs
1053
src/lib.rs
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user