editor.py aktualisiert
This commit is contained in:
@@ -165,7 +165,74 @@ def write_metadata(path, metadata):
|
||||
raise ValueError("Speichern der ID3-Tags hat zu lange gedauert")
|
||||
except OSError as exc:
|
||||
temp.unlink(missing_ok=True)
|
||||
raise ValueError(f"ID3-Tags konnten nicht gespeichert werden: {exc}")
|
||||
raise ValueError(f"Speichern der ID3-Tags fehlgeschlagen: {exc}")
|
||||
|
||||
|
||||
def update_finished_file(old_filename, new_filename, metadata):
|
||||
"""Update metadata and optionally rename a finished file in one operation."""
|
||||
old_path = finished_path(old_filename)
|
||||
new_filename = clean_new_filename(new_filename)
|
||||
if old_path is None or not old_path.is_file():
|
||||
raise ValueError("Datei nicht gefunden")
|
||||
if new_filename is None:
|
||||
raise ValueError("Ungültiger Dateiname")
|
||||
|
||||
new_path = FINISHED_DIR / new_filename
|
||||
if new_path != old_path and new_path.exists():
|
||||
raise ValueError("Eine Datei mit diesem Namen existiert bereits")
|
||||
|
||||
date = str(metadata.get("date", "")).strip()
|
||||
if not date:
|
||||
raise ValueError("Zeitpunkt fehlt")
|
||||
try:
|
||||
dt = datetime.fromisoformat(date)
|
||||
if dt.tzinfo is None:
|
||||
dt = dt.replace(tzinfo=ZoneInfo("Europe/Berlin"))
|
||||
date = dt.isoformat()
|
||||
except ValueError:
|
||||
raise ValueError("Ungültiger Zeitpunkt")
|
||||
|
||||
values = {
|
||||
"date": date,
|
||||
"artist": str(metadata.get("artist", "")).strip(),
|
||||
"title": str(metadata.get("title", "")).strip(),
|
||||
"album": str(metadata.get("album", "")).strip(),
|
||||
}
|
||||
|
||||
# Build the complete new MP3 first. The original remains untouched until
|
||||
# FFmpeg has successfully written the new file.
|
||||
temp = FINISHED_DIR / f".{new_path.name}.update.tmp.mp3"
|
||||
temp.unlink(missing_ok=True)
|
||||
cmd = [
|
||||
"ffmpeg", "-hide_banner", "-loglevel", "error", "-y",
|
||||
"-i", str(old_path),
|
||||
"-map", "0",
|
||||
"-c", "copy",
|
||||
"-map_metadata", "-1",
|
||||
]
|
||||
for key, value in values.items():
|
||||
cmd += ["-metadata", f"{key}={value}"]
|
||||
cmd.append(str(temp))
|
||||
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
||||
if result.returncode != 0 or not temp.is_file() or temp.stat().st_size == 0:
|
||||
raise ValueError("ID3-Tags konnten nicht gespeichert werden")
|
||||
|
||||
temp.replace(new_path)
|
||||
if new_path != old_path:
|
||||
old_path.unlink()
|
||||
|
||||
return new_path
|
||||
except subprocess.TimeoutExpired:
|
||||
temp.unlink(missing_ok=True)
|
||||
raise ValueError("Speichern der Datei hat zu lange gedauert")
|
||||
except OSError as exc:
|
||||
temp.unlink(missing_ok=True)
|
||||
raise ValueError(f"Datei konnte nicht gespeichert werden: {exc}")
|
||||
except ValueError:
|
||||
temp.unlink(missing_ok=True)
|
||||
raise
|
||||
|
||||
|
||||
def delete_file(kind, filename):
|
||||
@@ -1013,20 +1080,15 @@ async function saveFinishedMeta() {
|
||||
album: document.getElementById('finishedAlbum').value.trim()
|
||||
};
|
||||
|
||||
let targetFilename = filename;
|
||||
if (newFilename.replace(/\.mp3$/i, '') !== filename.replace(/\.mp3$/i, '')) {
|
||||
const renameResponse = await fetch('/api/file', {
|
||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({action:'rename', kind:'finished', filename, new_filename:newFilename})
|
||||
});
|
||||
const renameResult = await renameResponse.json();
|
||||
if (!renameResponse.ok || !renameResult.success) throw new Error(renameResult.error || `HTTP ${renameResponse.status}`);
|
||||
targetFilename = renameResult.filename;
|
||||
}
|
||||
|
||||
const response = await fetch('/api/file', {
|
||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({action:'update_metadata', kind:'finished', filename:targetFilename, metadata})
|
||||
body: JSON.stringify({
|
||||
action: 'update_finished',
|
||||
kind: 'finished',
|
||||
filename,
|
||||
new_filename: newFilename,
|
||||
metadata
|
||||
})
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result.success) throw new Error(result.error || `HTTP ${response.status}`);
|
||||
@@ -1204,6 +1266,13 @@ def api_file():
|
||||
if action == "rename":
|
||||
path = rename_file(kind, filename, data.get("new_filename"))
|
||||
return jsonify({"success": True, "filename": path.name})
|
||||
if action == "update_finished":
|
||||
if kind != "finished":
|
||||
return jsonify({"success": False, "error": "Metadaten können nur bei bearbeiteten Aufnahmen geändert werden"}), 400
|
||||
metadata = data.get("metadata") or {}
|
||||
path = update_finished_file(filename, data.get("new_filename"), metadata)
|
||||
return jsonify({"success": True, "filename": path.name})
|
||||
|
||||
if action == "update_metadata":
|
||||
if kind != "finished":
|
||||
return jsonify({"success": False, "error": "Metadaten können nur bei bearbeiteten Aufnahmen geändert werden"}), 400
|
||||
|
||||
Reference in New Issue
Block a user