feat: rewrite application as modular fcco-Converter V2 with new GUI, metadata handling, and updater logic

This commit is contained in:
joel
2026-07-19 23:43:11 +02:00
parent 6dece1410c
commit d130dd267b
17 changed files with 2329 additions and 519 deletions
+134
View File
@@ -0,0 +1,134 @@
"""
fcco-Converter V2 Konfigurationsmodul
Lädt und speichert Anwendungseinstellungen plattformübergreifend.
Verwendet pathlib für alle Pfadoperationen.
"""
import json
import platform
from pathlib import Path
# Standardmäßige Export-Kategorien
DEFAULT_EXPORT_PATHS = {
"Gottesdienst": "gottesdienste",
"Hochzeit": "hochzeiten",
"Weissagung": "weissagungen",
"Jugend": "jugend",
}
# Kurze deutsche Wochentagsnamen für Ordnerbenennung
WEEKDAY_SHORT_DE = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
# ---- Audio-Einstellungen: Gültige Werte ----
BITRATE_OPTIONS = ["64", "96", "128", "160", "192", "224", "256", "320"]
SAMPLERATE_OPTIONS = ["Original", "22050", "44100", "48000"]
CHANNEL_OPTIONS = ["Original", "Mono", "Stereo"]
ENCODING_MODE_OPTIONS = ["CBR", "VBR"]
VBR_QUALITY_OPTIONS = [str(i) for i in range(10)] # 0 (beste) bis 9 (schlechteste)
OUTPUT_FORMAT_OPTIONS = ["mp3", "flac", "ogg", "wav"]
def _get_config_dir() -> Path:
"""Gibt das plattformabhängige Konfigurationsverzeichnis zurück."""
system = platform.system()
if system == "Windows":
base = Path.home() / "AppData" / "Roaming"
elif system == "Darwin":
base = Path.home() / "Library" / "Application Support"
else: # Linux / andere
base = Path.home() / ".config"
config_dir = base / "fcco-Converter"
config_dir.mkdir(parents=True, exist_ok=True)
return config_dir
CONFIG_DIR = _get_config_dir()
SETTINGS_FILE = CONFIG_DIR / "settings.json"
HISTORY_FILE = CONFIG_DIR / "history.json"
# ---- Standard-Einstellungen ----
DEFAULT_SETTINGS = {
# Allgemein
"threads": 0, # 0 = auto (alle verfügbaren Kerne)
"appearance_mode": "Dark", # Dark / Light / System
"check_updates_on_start": True,
# Audio & Konvertierung
"audio": {
"output_format": "mp3",
"bitrate": "192", # kbit/s (nur CBR)
"encoding_mode": "CBR", # CBR oder VBR
"vbr_quality": "2", # 0 (beste) bis 9 (schlechteste)
"sample_rate": "Original", # Original, 22050, 44100, 48000
"channels": "Original", # Original, Mono, Stereo
"overwrite_existing": True,
},
# Metadaten
"metadata": {
"artist": "",
"cover": "",
"auto_track_number": True,
"auto_album_from_folder": True,
},
# Export-Pfade
"export_paths": DEFAULT_EXPORT_PATHS.copy(),
}
def _deep_merge(base: dict, override: dict) -> dict:
"""Merged override-Werte in base, ohne fehlende Schlüssel zu verlieren."""
result = base.copy()
for key, value in override.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = _deep_merge(result[key], value)
else:
result[key] = value
return result
def load_settings() -> dict:
"""Lädt die Einstellungen aus der JSON-Datei.
Fehlende Schlüssel werden mit Standardwerten aufgefüllt.
"""
settings = DEFAULT_SETTINGS.copy()
# Deep-copy verschachtelter Dicts
settings["audio"] = DEFAULT_SETTINGS["audio"].copy()
settings["metadata"] = DEFAULT_SETTINGS["metadata"].copy()
settings["export_paths"] = DEFAULT_SETTINGS["export_paths"].copy()
if SETTINGS_FILE.exists():
try:
with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
loaded = json.load(f)
settings = _deep_merge(settings, loaded)
except (json.JSONDecodeError, OSError):
pass # Bei fehlerhafter Datei: Standardwerte nutzen
return settings
def save_settings(settings: dict) -> None:
"""Speichert die Einstellungen in die JSON-Datei."""
with open(SETTINGS_FILE, "w", encoding="utf-8") as f:
json.dump(settings, f, indent=2, ensure_ascii=False)
def save_export_history(entry: dict) -> None:
"""Fügt einen Export-Eintrag zur Historie hinzu."""
history = []
if HISTORY_FILE.exists():
try:
with open(HISTORY_FILE, "r", encoding="utf-8") as f:
history = json.load(f)
except (json.JSONDecodeError, OSError):
history = []
history.append(entry)
with open(HISTORY_FILE, "w", encoding="utf-8") as f:
json.dump(history, f, indent=2, ensure_ascii=False)