use crate::{
app::{
field::{ArgsTable, Field, Text},
Run,
},
error::Error,
text_data::picture_type::PictureType,
utils::ModifyTags,
};
use clap::{Args, Subcommand};
use id3::{Tag, TagLike};
use std::{mem::replace, path::PathBuf};
#[derive(Debug, Subcommand)]
pub enum Delete {
All(DeleteAllField),
#[clap(flatten)]
Single(DeleteSingleField),
}
impl Run for Delete {
fn run(self) -> Result<(), Error> {
match self {
Delete::All(proc) => proc.run(),
Delete::Single(proc) => proc.run(),
}
}
}
#[derive(Debug, Args)]
#[clap(about = "")]
pub struct DeleteAllField {
#[clap(long)]
pub no_backup: bool,
pub target_audio: PathBuf,
}
impl Run for DeleteAllField {
fn run(self) -> Result<(), Error> {
let DeleteAllField {
no_backup,
target_audio,
} = self;
ModifyTags::builder()
.no_backup(no_backup)
.target_audio(&target_audio)
.build()
.run(|tag| replace(tag, Tag::new()))?;
Ok(())
}
}
pub type DeleteSingleField = Field<DeleteArgsTable>;
impl Run for Text<DeleteArgsTable> {
fn run(self) -> Result<(), Error> {
fn delete_text(args: DeleteText, delete: impl FnOnce(&mut Tag)) -> Result<(), Error> {
let DeleteText {
no_backup,
target_audio,
} = args;
ModifyTags::builder()
.no_backup(no_backup)
.target_audio(&target_audio)
.build()
.run(delete)
}
match self {
Text::Title(args) => delete_text(args, Tag::remove_title),
Text::Artist(args) => delete_text(args, Tag::remove_artist),
Text::Album(args) => delete_text(args, Tag::remove_album),
Text::AlbumArtist(args) => delete_text(args, Tag::remove_album_artist),
Text::Genre(DeleteGenre::Genre(args)) => delete_text(args, Tag::remove_genre),
}
}
}
#[derive(Debug)]
pub struct DeleteArgsTable;
impl ArgsTable for DeleteArgsTable {
type Text = DeleteText;
type Genre = DeleteGenre;
type Comment = DeleteComment;
type Picture = DeletePicture;
}
#[derive(Debug, Args)]
#[clap(about = "")]
pub struct DeleteText {
#[clap(long)]
pub no_backup: bool,
pub target_audio: PathBuf,
}
#[derive(Debug, Subcommand)]
pub enum DeleteGenre {
#[clap(name = "genre")]
Genre(DeleteText),
}
#[derive(Debug, Args)]
#[clap(about = "")]
pub struct DeleteComment {
#[clap(long)]
pub no_backup: bool,
#[clap(long)]
pub description: Option<String>,
#[clap(long)]
pub content: Option<String>,
pub target_audio: PathBuf,
}
impl Run for DeleteComment {
fn run(self) -> Result<(), Error> {
let DeleteComment {
no_backup,
ref description,
ref content,
ref target_audio,
} = self;
let description = description.as_deref();
let content = content.as_deref();
ModifyTags::builder()
.no_backup(no_backup)
.target_audio(target_audio)
.build()
.run(|tag| tag.remove_comment(description, content))
}
}
#[derive(Debug, Args)]
#[clap(about = "")]
pub struct DeletePicture {
#[clap(long)]
pub no_backup: bool,
pub target_audio: PathBuf,
#[clap(subcommand)]
pub command: DeletePictureCmd,
}
impl Run for DeletePicture {
fn run(self) -> Result<(), Error> {
let DeletePicture {
no_backup,
ref target_audio,
command,
} = self;
ModifyTags {
no_backup,
target_audio,
}
.run(|tag| match command {
DeletePictureCmd::All => tag.remove_all_pictures(),
DeletePictureCmd::ByType(picture_type) => {
tag.remove_picture_by_type(picture_type.into())
}
})
}
}
#[derive(Debug, Subcommand)]
#[clap(about = "")]
pub enum DeletePictureCmd {
All,
#[clap(flatten)]
ByType(PictureType),
}