add get-tags and set-tags commands and fix error on no extension
This commit is contained in:
parent
3eb010b21c
commit
e57ea88b22
18
flake.lock
18
flake.lock
|
@ -3,11 +3,11 @@
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1650374568,
|
"lastModified": 1668681692,
|
||||||
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
|
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
|
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -18,11 +18,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1666401273,
|
"lastModified": 1670980281,
|
||||||
"narHash": "sha256-AG3MoIjcWwz1SPjJ2nymWu4NmeVj9P40OpB1lsmxFtg=",
|
"narHash": "sha256-g0t/SmQca/JBEd+3Ry1qFgDfDK8ME9AM6EP4YUl8/lo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "3933d8bb9120573c0d8d49dc5e890cb211681490",
|
"rev": "5cb48ea3c19ce2e5746a44d6b91847396bd28c1f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -41,11 +41,11 @@
|
||||||
},
|
},
|
||||||
"utils": {
|
"utils": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1659877975,
|
"lastModified": 1667395993,
|
||||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
18
src/args.rs
18
src/args.rs
|
@ -13,6 +13,8 @@ pub enum Commands {
|
||||||
Genhtml(GenHTMLCommandArgs),
|
Genhtml(GenHTMLCommandArgs),
|
||||||
Transcode(TranscodeCommandArgs),
|
Transcode(TranscodeCommandArgs),
|
||||||
Copy(CopyCommandArgs),
|
Copy(CopyCommandArgs),
|
||||||
|
SetTags(SetTagsCommandArgs),
|
||||||
|
GetTags(GetTagsCommandArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
|
@ -65,3 +67,19 @@ pub struct CopyCommandArgs {
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
pub single_directory: bool,
|
pub single_directory: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Args)]
|
||||||
|
pub struct SetTagsCommandArgs {
|
||||||
|
pub files: Vec<String>,
|
||||||
|
#[clap(long)]
|
||||||
|
pub title: Option<String>,
|
||||||
|
#[clap(long)]
|
||||||
|
pub artist: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Args)]
|
||||||
|
pub struct GetTagsCommandArgs {
|
||||||
|
pub files: Vec<String>,
|
||||||
|
#[clap(long)]
|
||||||
|
pub json: bool,
|
||||||
|
}
|
||||||
|
|
70
src/commands/get_tags.rs
Normal file
70
src/commands/get_tags.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::args::CLIArgs;
|
||||||
|
use crate::args::GetTagsCommandArgs;
|
||||||
|
use crate::types::File;
|
||||||
|
use crate::utils::extract_tags_from_file;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
struct Tags {
|
||||||
|
title: String,
|
||||||
|
artist: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_main_tags(tags: &crate::types::Tags) -> Tags {
|
||||||
|
Tags {
|
||||||
|
title: tags.title.clone(),
|
||||||
|
artist: tags.artist.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_tags_command(
|
||||||
|
_args: &CLIArgs,
|
||||||
|
get_tags_args: &GetTagsCommandArgs,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut files: Vec<File> = Vec::new();
|
||||||
|
|
||||||
|
for file in get_tags_args.files.iter() {
|
||||||
|
files.push(File::from_path("".to_string(), PathBuf::from(file)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in files.iter_mut() {
|
||||||
|
let tags = extract_tags_from_file(file.clone())?;
|
||||||
|
file.tags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if files.len() == 1 {
|
||||||
|
let file = files.first().unwrap();
|
||||||
|
|
||||||
|
if get_tags_args.json {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string_pretty(&from_main_tags(&file.tags)).unwrap()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("{:#?}", from_main_tags(&file.tags));
|
||||||
|
}
|
||||||
|
} else if get_tags_args.json {
|
||||||
|
let mut result: HashMap<String, Tags> = HashMap::new();
|
||||||
|
for file in files.iter() {
|
||||||
|
result.insert(
|
||||||
|
file.join_path_to().to_string_lossy().to_string(),
|
||||||
|
from_main_tags(&file.tags),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("{}", serde_json::to_string_pretty(&result)?);
|
||||||
|
} else {
|
||||||
|
for file in files.iter() {
|
||||||
|
println!(
|
||||||
|
"{}: {:#?}",
|
||||||
|
file.join_path_to().to_string_lossy(),
|
||||||
|
from_main_tags(&file.tags)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
pub mod copy;
|
pub mod copy;
|
||||||
pub mod genhtml;
|
pub mod genhtml;
|
||||||
|
pub mod get_tags;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
|
pub mod set_tags;
|
||||||
pub mod transcode;
|
pub mod transcode;
|
||||||
|
|
71
src/commands/set_tags.rs
Normal file
71
src/commands/set_tags.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use id3::TagLike;
|
||||||
|
|
||||||
|
use crate::args::CLIArgs;
|
||||||
|
use crate::args::SetTagsCommandArgs;
|
||||||
|
use crate::types::File;
|
||||||
|
|
||||||
|
pub fn tag_mp3(
|
||||||
|
file: &File,
|
||||||
|
add_tags_args: &SetTagsCommandArgs,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut tag = id3::Tag::read_from_path(file.join_path_to())?;
|
||||||
|
|
||||||
|
if let Some(title) = &add_tags_args.title {
|
||||||
|
tag.set_title(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(artist) = &add_tags_args.artist {
|
||||||
|
tag.set_artist(artist);
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.write_to_path(file.join_path_to(), id3::Version::Id3v24)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tag_flac(
|
||||||
|
file: &File,
|
||||||
|
add_tags_args: &SetTagsCommandArgs,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut tag = metaflac::Tag::read_from_path(file.join_path_to())?;
|
||||||
|
|
||||||
|
if let Some(title) = &add_tags_args.title {
|
||||||
|
tag.remove_vorbis("TITLE");
|
||||||
|
tag.set_vorbis("TITLE", vec![title]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(artist) = &add_tags_args.artist {
|
||||||
|
tag.remove_vorbis("ARTIST");
|
||||||
|
tag.set_vorbis("ARTIST", vec![artist]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.write_to_path(file.join_path_to())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tags_command(
|
||||||
|
_args: &CLIArgs,
|
||||||
|
add_tags_args: &SetTagsCommandArgs,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut files: Vec<File> = Vec::new();
|
||||||
|
|
||||||
|
for file in add_tags_args.files.iter() {
|
||||||
|
files.push(File::from_path("".to_string(), PathBuf::from(file)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in files.iter() {
|
||||||
|
match file.extension.as_str() {
|
||||||
|
"mp3" => tag_mp3(file, add_tags_args)?,
|
||||||
|
"flac" => tag_flac(file, add_tags_args)?,
|
||||||
|
_ => panic!(
|
||||||
|
"Invalid File Extension for {}",
|
||||||
|
file.join_path_to().to_string_lossy()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -9,7 +9,9 @@ use clap::Parser;
|
||||||
|
|
||||||
use commands::copy::copy_command;
|
use commands::copy::copy_command;
|
||||||
use commands::genhtml::genhtml_command;
|
use commands::genhtml::genhtml_command;
|
||||||
|
use commands::get_tags::get_tags_command;
|
||||||
use commands::process::process_command;
|
use commands::process::process_command;
|
||||||
|
use commands::set_tags::set_tags_command;
|
||||||
use commands::transcode::transcode_command;
|
use commands::transcode::transcode_command;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -28,6 +30,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
Some(Commands::Copy(copy_args)) => {
|
Some(Commands::Copy(copy_args)) => {
|
||||||
copy_command(&cli, copy_args)?;
|
copy_command(&cli, copy_args)?;
|
||||||
}
|
}
|
||||||
|
Some(Commands::SetTags(set_tags_args)) => {
|
||||||
|
set_tags_command(&cli, set_tags_args)?;
|
||||||
|
}
|
||||||
|
Some(Commands::GetTags(get_tags_args)) => {
|
||||||
|
get_tags_command(&cli, get_tags_args)?;
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
panic!("please provide a subcommand");
|
panic!("please provide a subcommand");
|
||||||
}
|
}
|
||||||
|
|
14
src/types.rs
14
src/types.rs
|
@ -30,12 +30,14 @@ impl File {
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
let extension = full_file_path
|
|
||||||
.extension()
|
let extension = full_file_path.extension();
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
let extension = if let Some(extension) = extension {
|
||||||
.unwrap()
|
extension.to_str().unwrap().to_string()
|
||||||
.to_string();
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
let path_from_src = full_file_path.strip_prefix(&source_dir).unwrap();
|
let path_from_src = full_file_path.strip_prefix(&source_dir).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,11 @@ pub use music_scanner::scan_for_music;
|
||||||
pub use tag_extractor::extract_tags_from_file;
|
pub use tag_extractor::extract_tags_from_file;
|
||||||
|
|
||||||
pub fn is_supported_file_extension(file_path: &Path) -> bool {
|
pub fn is_supported_file_extension(file_path: &Path) -> bool {
|
||||||
let ext = file_path.extension().unwrap().to_str().unwrap();
|
let ext = file_path.extension();
|
||||||
|
if ext.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let ext = ext.unwrap().to_str().unwrap();
|
||||||
|
|
||||||
matches!(ext, "mp3" | "flac")
|
matches!(ext, "mp3" | "flac")
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,14 @@ pub fn find_extra_files(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let entry_path = entry.path();
|
let entry_path = entry.path();
|
||||||
|
|
||||||
|
let extension = entry_path.extension();
|
||||||
|
if extension.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if entry_path.file_stem().unwrap().to_string_lossy() == file.filename
|
if entry_path.file_stem().unwrap().to_string_lossy() == file.filename
|
||||||
&& entry_path.extension().unwrap().to_string_lossy() != file.extension
|
&& extension.unwrap().to_string_lossy() != file.extension
|
||||||
{
|
{
|
||||||
extra_files.push(File::from_path(src_dir.clone(), entry_path.clone()));
|
extra_files.push(File::from_path(src_dir.clone(), entry_path.clone()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue