fix: properly handle editing multiple files

fixed wrong parsing causing to overwrite all files with wrong metadata

fixed wrong file header in editor buffer
This commit is contained in:
2026-09-06 00:16:07 +02:00
parent 6c5b0e1c5f
commit 96947f625a
4 changed files with 107 additions and 30 deletions
+58 -28
View File
@@ -1,25 +1,30 @@
use lofty::config::WriteOptions;
use lofty::tag::TagItem;
use lofty::tag::TagType::VorbisComments;
use lofty::tag::{Accessor, TagItem};
use lofty::tag::{ItemKey, ItemValue};
use lofty::tag::{Tag, TagExt};
use regex::Regex;
use std::collections::HashMap;
use std::env::var;
use std::io::Write;
use std::path::PathBuf;
use std::{fs::File, fs::read_dir, io::Read, process::Command};
use std::{fs::read_dir, fs::File, io::Read, process::Command};
pub fn edit(file_path: PathBuf, extra_files: [String; 8]) -> std::io::Result<()> {
let tmp_file = PathBuf::from("/tmp/keks-sort-metadata");
let tmp_file_path = PathBuf::from("/tmp/keks-sort-metadata");
let mut tmp_file = File::create(&tmp_file_path)?;
let editor = var("EDITOR").unwrap();
let mut file = File::create(&tmp_file)?;
let mut tags: Vec<Tag> = Vec::new();
let mut path: PathBuf = file_path.clone();
let mut files = Vec::new();
struct FileMetadata {
path: PathBuf,
tag: Tag,
}
if file_path.is_dir() {
for music_file in read_dir(&file_path)? {
path = music_file?.path();
println!("{:?}", path);
if path
.extension()
@@ -30,57 +35,82 @@ pub fn edit(file_path: PathBuf, extra_files: [String; 8]) -> std::io::Result<()>
}
let tag = crate::get_metadata(&path);
tags.push(tag);
files.push(FileMetadata { path, tag });
}
} else {
let tag = &crate::get_metadata(&file_path);
tags.push(tag.clone());
let tag = &crate::get_metadata(file_path);
files.push(FileMetadata {
path,
tag: tag.clone(),
});
}
for tag in &tags {
println!("{:?}", tag.title());
writeln!(file.try_clone()?, "------------ {:?} ------------", path)?;
for item in tag.items() {
for file in &files {
writeln!(
tmp_file.try_clone()?,
"------------ {:?} ------------",
file.path
)?;
for item in file.tag.items() {
writeln!(
file,
tmp_file,
"{} = {}",
item.key().map_key(VorbisComments).unwrap(),
item.value().text().unwrap()
)?;
}
writeln!(file.try_clone()?)?; // writes empty line
writeln!(tmp_file.try_clone()?)?; // writes empty line
}
Command::new(editor)
.arg(&tmp_file)
.arg(&tmp_file_path)
.status()
.expect("Something went wrong");
let mut editable = String::new();
File::open(&tmp_file)
File::open(&tmp_file_path)
.expect("Could not open file")
.read_to_string(&mut editable)?;
let parsed = parse(&editable);
for mut tag in tags {
for (key, value) in &parsed {
for (mut file, parse) in files.into_iter().zip(parsed) {
for (key, value) in &parse {
let item_key =
ItemKey::from_key(VorbisComments, key).expect("ERROR: Failed to get item key");
let item = TagItem::new(item_key, ItemValue::Text(value.to_string()));
tag.insert(item.clone());
file.tag.insert(item);
}
tag.save_to_path(&file_path, WriteOptions::default())
file.tag
.save_to_path(&file.path, WriteOptions::default())
.expect("ERROR: Failed to write tag");
}
Ok(())
}
fn parse(input: &str) -> HashMap<String, String> {
input
.lines()
.filter_map(|line| {
let (key, value) = line.split_once('=')?;
Some((key.trim().to_string(), value.trim().to_string()))
fn parse(input: &str) -> Vec<HashMap<String, String>> {
let re = Regex::new(r#"(?m)^------------ ".*?" ------------\r?\n"#).unwrap();
let parts: Vec<&str> = re
.split(input)
.filter(|part| !part.trim().is_empty())
.collect();
let result: Vec<HashMap<String, String>> = parts
.into_iter()
.filter_map(|part| {
let part = part.trim();
if part.is_empty() {
return None;
}
Some(
part.lines()
.filter_map(|line| {
let (key, value) = line.split_once('=')?;
Some((key.trim().to_string(), value.trim().to_string()))
})
.collect(),
)
})
.collect()
.collect();
result
}