4 Commits
8 changed files with 119 additions and 67 deletions
+25 -47
View File
@@ -1,6 +1,6 @@
# fcco Converter V2
WAV-zu-MP3-Konverter mit grafischer Benutzeroberfläche. Unterstützt automatische Metadaten-Erstellung (Künstler, Album, Titel, Tracknummer), Cover-Bilder und alphabetische Sortierung. Läuft auf **Windows** und **macOS**.
WAV-zu-MP3-Konverter mit grafischer Benutzeroberfläche. Unterstützt automatische Metadaten-Erstellung (Künstler, Album, Titel, Tracknummer), Cover-Bilder und alphabetische Sortierung. Läuft auf Windows und macOS.
---
@@ -13,16 +13,33 @@ WAV-zu-MP3-Konverter mit grafischer Benutzeroberfläche. Unterstützt automatisc
- Einstellungen werden dauerhaft gespeichert
- Fortschrittsanzeige pro Datei und gesamt
- Automatisches Update direkt aus der App
- Moderne, dunkle Benutzeroberfläche (CustomTkinter)
- Moderne, dunkle Benutzeroberfläche
---
## Automatische Titel-Extrahierung (Neu in V2.0.2)
Das Programm erkennt Dateinamen im typischen fcco-Format und erstellt daraus automatisch saubere Songtitel (ID3-Tags).
Das Muster wird nach dem Unterstrich-Format extrahiert. Hier sind Beispiele, wie aus Dateinamen automatisch MP3-Titel gebildet werden:
- 260719So_N_10_Predigt_D Vorname Nachname.wav -> "Predigt Vorname Nachname"
- 260719So_N_07_Vorwort_D Vorname Nachname.wav -> "Vorwort Vorname Nachname"
- 260719So_N_09_Gedicht_D Vorname Nachname.wav -> "Gedicht Vorname Nachname"
- 260719So_N_10_Predigt_D.wav -> "Predigt D"
- 260719So_N_10_Predigt_D Gast.wav -> "Predigt Gast"
- 260719So_N_06_Lied_R О пройденном я подвожу итог.wav -> "О пройденном я подвожу итог"
- 260719So_N_04_Lied_D Zum blauen Himmel.wav -> "Zum blauen Himmel"
- 260719So_N_04_Chor_D Zum blauen Himmel.wav -> "Zum blauen Himmel (Chor)"
- 260719So_N_04_Orchester_D Zum blauen Himmel.wav -> "Zum blauen Himmel (Orchester)"
---
## Installation (Endnutzer)
Lade die neueste Version von der [Releases-Seite](https://git.joelunger.de/public/fcco-Converter/releases) herunter:
Lade die neueste Version von der Releases-Seite (Gitea) herunter:
- **Windows**: `fcco-Converter-windows.zip` entpacken und `fcco-Converter.exe` starten.
- **macOS**: `fcco-Converter-macos.zip` entpacken und `fcco-Converter` starten.
- Windows: fcco-Converter-windows.zip entpacken und fcco-Converter.exe starten.
- macOS: fcco-Converter-macos.zip entpacken und fcco-Converter starten.
FFmpeg wird automatisch beim ersten Start heruntergeladen. Keine weitere Installation nötig.
@@ -30,66 +47,27 @@ FFmpeg wird automatisch beim ersten Start heruntergeladen. Keine weitere Install
## Updates
In der App auf **"Update prüfen"** klicken. Wenn eine neue Version verfügbar ist, wird sie direkt heruntergeladen und installiert. Danach muss die App einmal neu gestartet werden.
In der App auf "Update prüfen" klicken. Wenn eine neue Version verfügbar ist, wird sie direkt heruntergeladen und installiert. Danach muss die App einmal neu gestartet werden.
---
## Entwicklung
### Voraussetzungen
- Python 3.11 oder neuer
- Virtuelle Umgebung empfohlen
### Setup
```bash
python -m venv .venv
source .venv/bin/activate # macOS / Linux
# .venv\Scripts\activate # Windows
pip install -r requirements.txt
```
### Starten
```bash
python main.py
```
### Build (Standalone-Executable)
```bash
### Build (Standalone-Executable & ZIP-Erstellung)
python build.py
```
Die fertige Datei liegt anschließend im `dist/`-Verzeichnis.
---
## Projektstruktur
```
fcco-Converter/
├── main.py # Einstiegspunkt
├── build.py # Build-Skript (PyInstaller)
├── requirements.txt # Abhängigkeiten
├── icon.ico # Programm-Icon
├── fcco_converter/
│ ├── __init__.py
│ ├── config.py # Einstellungen & Konfiguration
│ ├── converter.py # FFmpeg-Konvertierung
│ ├── metadata.py # ID3-Tags & Cover
│ ├── updater.py # Auto-Update von Gitea Releases
│ └── gui.py # CustomTkinter GUI
└── README.md
```
---
## Hinweise
- Nur `.wav`-Dateien werden als Eingabe akzeptiert.
- Cover-Bilder müssen `.jpg`, `.jpeg` oder `.png` sein.
- Export erfolgt im `.mp3`-Format (192 kbit/s).
- Einstellungen werden in `~/.config/fcco-Converter/` (Linux), `~/Library/Application Support/fcco-Converter/` (macOS) bzw. `%APPDATA%/fcco-Converter/` (Windows) gespeichert.
Die fertige App und die Release-ZIP-Datei liegen anschließend im dist/ Verzeichnis.
+17 -1
View File
@@ -70,6 +70,21 @@ def build():
except ImportError:
print("WARNUNG: customtkinter nicht installiert. Bitte 'pip install -r requirements.txt' ausführen.")
# static_ffmpeg-Binaries einbinden (FFmpeg komplett offline bündeln)
try:
import static_ffmpeg
print("Lade FFmpeg-Binaries herunter (falls noch nicht vorhanden)...")
# Zwingt static_ffmpeg dazu, FFmpeg herunterzuladen, falls es noch nicht im venv/bin ist
static_ffmpeg.run.get_or_fetch_platform_executables_else_raise()
sf_path = Path(static_ffmpeg.__file__).parent
if system == "Windows":
args.extend(["--add-data", f"{sf_path};static_ffmpeg"])
else:
args.extend(["--add-data", f"{sf_path}:static_ffmpeg"])
except Exception as e:
print(f"WARNUNG: static_ffmpeg konnte nicht gebündelt werden: {e}")
# Hauptdatei
args.append(str(project_dir / "main.py"))
@@ -86,7 +101,8 @@ def build():
# ZIP-Archiv für das Release erstellen
import tempfile
zip_name = f"fcco-Converter-{system.lower()}"
sys_name = "macos" if system == "Darwin" else system.lower()
zip_name = f"fcco-Converter-{sys_name}"
zip_path = dist_dir / zip_name
with tempfile.TemporaryDirectory() as tmpdir:
+1 -1
View File
@@ -1,6 +1,6 @@
{
"app_name": "fcco Converter",
"app_version": "2.0.1",
"app_version": "2.0.2",
"repo_owner": "public",
"repo_name": "fcco-Converter",
"gitea_api_base": "https://git.joelunger.de/api/v1"
+1 -1
View File
@@ -13,7 +13,7 @@ from pathlib import Path
# ---- Globale App-Informationen (aus config.json) ----
APP_INFO = {
"app_name": "fcco Converter",
"app_version": "2.0.0",
"app_version": "2.0.2",
"repo_owner": "public",
"repo_name": "fcco-Converter",
"gitea_api_base": "https://git.joelunger.de/api/v1"
+24 -1
View File
@@ -16,14 +16,36 @@ import static_ffmpeg
from .metadata import apply_id3_tags
import sys
import io
import shutil
def _ensure_ffmpeg() -> tuple[str, str]:
"""Stellt sicher, dass ffmpeg und ffprobe verfügbar sind.
Returns:
(ffmpeg_path, ffprobe_path)
"""
# 1. Behebe NoneType 'write' Fehler, wenn App im windowed-Modus gestartet wurde
if sys.stdout is None:
sys.stdout = io.StringIO()
if sys.stderr is None:
sys.stderr = io.StringIO()
# 2. Versuch 1: static_ffmpeg (jetzt direkt in der App gebündelt)
try:
ffmpeg_path, ffprobe_path = static_ffmpeg.run.get_or_fetch_platform_executables_else_raise()
return ffmpeg_path, ffprobe_path
except Exception:
pass
# 3. Versuch 2: System-FFmpeg (z.B. über winget, apt, brew) als Fallback
sys_ffmpeg = shutil.which("ffmpeg")
sys_ffprobe = shutil.which("ffprobe")
if sys_ffmpeg and sys_ffprobe:
return sys_ffmpeg, sys_ffprobe
raise RuntimeError("FFmpeg konnte weder im Bundle noch im System gefunden werden.")
def get_duration(file_path: Path, ffprobe_path: str) -> float:
@@ -205,7 +227,8 @@ def convert_file_entry(
audio_settings = {"output_format": "mp3", "bitrate": "192", "encoding_mode": "CBR"}
file_path = Path(entry["full_path"])
title = file_path.stem
from .metadata import extract_title_from_filename
title = extract_title_from_filename(file_path.stem)
output_format = audio_settings.get("output_format", "mp3")
try:
+42
View File
@@ -4,6 +4,7 @@ fcco-Converter V2 Metadaten-Modul
Hilfsfunktionen für ID3-Tags, Cover-Bilder und Albumname-Generierung.
"""
import re
from datetime import datetime
from pathlib import Path
@@ -51,6 +52,47 @@ def extract_event_from_folder(file_path: Path) -> tuple[str, str]:
return "", ""
def extract_title_from_filename(filename: str) -> str:
"""Extrahiert einen sauberen Titel aus dem komplexen Dateinamen-Format.
Format-Erwartung: [Prefix]_[Track]_[Type]_[Lang][ Remainder]
Beispiele:
260719So_N_10_Predigt_D Vorname Nachname -> "Predigt Vorname Nachname"
260719So_N_04_Lied_D Zum blauen Himmel -> "Zum blauen Himmel"
"""
# Regulärer Ausdruck, um die Komponenten zu extrahieren
match = re.match(r"^.*?_\d+_(?P<type>[a-zA-Z]+)_(?P<lang>[a-zA-Z]+)(?: (?P<remainder>.*))?$", filename)
if not match:
return filename
typ = match.group("type")
lang = match.group("lang")
remainder = match.group("remainder") or ""
typ_lower = typ.lower()
if typ_lower in ["predigt", "vorwort", "gedicht"]:
if remainder:
return f"{typ} {remainder}"
return f"{typ} {lang}"
elif typ_lower == "lied":
if remainder:
return remainder
return f"{typ} {lang}"
elif typ_lower in ["chor", "orchester"]:
if remainder:
return f"{remainder} ({typ})"
return f"{typ} {lang}"
else:
# Fallback
if remainder:
return f"{typ} {remainder}"
return f"{typ} {lang}"
from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB, TRCK, TDRC
def apply_id3_tags(
+7
View File
@@ -7,6 +7,13 @@ Startet die grafische Benutzeroberfläche.
import sys
import platform
import io
# Behebe NoneType 'write' Fehler in windowed GUI-Modus (PyInstaller --windowed auf Windows/macOS)
if sys.stdout is None:
sys.stdout = io.StringIO()
if sys.stderr is None:
sys.stderr = io.StringIO()
# DPI-Awareness auf Windows setzen (vor dem GUI-Import)
if platform.system() == "Windows":
-14
View File
@@ -1,14 +0,0 @@
{
"export_paths": {
"Gottesdienst": "D:\\Tonaufnahmen\\3MP3-192kbit Gottesdienste\\2026",
"Hochzeit": "D:\\Tonaufnahmen\\4MP3-192kbit Hochzeiten",
"Weissagung": "D:\\Tonaufnahmen\\5Sonstiges\\Weissagungen",
"Jugend": "D:\\Tonaufnahmen\\3MP3-192kbit Gottesdienste\\2026"
},
"metadata": {
"artist": "FECG Rottweil-Neukirch",
"cover": "D:\\Portable Software\\fcco_Converter\\Cover\\cover_fecg_rottweil.jpg"
},
"last_export_dir": "D:\\Tonaufnahmen\\3MP3-192kbit Gottesdienste\\2026\\260406Mo Ostermontag",
"threads": 0
}