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")
|
raise ValueError("Speichern der ID3-Tags hat zu lange gedauert")
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
temp.unlink(missing_ok=True)
|
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):
|
def delete_file(kind, filename):
|
||||||
@@ -1013,20 +1080,15 @@ async function saveFinishedMeta() {
|
|||||||
album: document.getElementById('finishedAlbum').value.trim()
|
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', {
|
const response = await fetch('/api/file', {
|
||||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
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();
|
const result = await response.json();
|
||||||
if (!response.ok || !result.success) throw new Error(result.error || `HTTP ${response.status}`);
|
if (!response.ok || !result.success) throw new Error(result.error || `HTTP ${response.status}`);
|
||||||
@@ -1204,6 +1266,13 @@ def api_file():
|
|||||||
if action == "rename":
|
if action == "rename":
|
||||||
path = rename_file(kind, filename, data.get("new_filename"))
|
path = rename_file(kind, filename, data.get("new_filename"))
|
||||||
return jsonify({"success": True, "filename": path.name})
|
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 action == "update_metadata":
|
||||||
if kind != "finished":
|
if kind != "finished":
|
||||||
return jsonify({"success": False, "error": "Metadaten können nur bei bearbeiteten Aufnahmen geändert werden"}), 400
|
return jsonify({"success": False, "error": "Metadaten können nur bei bearbeiteten Aufnahmen geändert werden"}), 400
|
||||||
|
|||||||
Reference in New Issue
Block a user