Use editable INI configuration

This commit is contained in:
Melbar
2026-05-07 18:35:36 +02:00
parent bc6c3e83a7
commit f68d2589df
4 changed files with 159 additions and 99 deletions
+43 -48
View File
@@ -25,7 +25,7 @@ Das Tool erzeugt:
FFmpeg und FFprobe werden automatisch gesucht: FFmpeg und FFprobe werden automatisch gesucht:
1. explizite Pfade aus `config.json` 1. explizite Pfade aus `config.ini`
2. `PATH` 2. `PATH`
3. `C:\Tools\FFMPEG` 3. `C:\Tools\FFMPEG`
4. `C:\Software` 4. `C:\Software`
@@ -62,7 +62,7 @@ Wenn Tkinter nicht verfuegbar ist, oeffnet das Tool einen nativen Windows-Dateid
## Ausgabe ## Ausgabe
Das Zielverzeichnis wird ueber `config.json` bestimmt: Das Zielverzeichnis wird ueber `config.ini` bestimmt:
1. `output.base_dir`, wenn gesetzt 1. `output.base_dir`, wenn gesetzt
2. erstes vorhandenes Verzeichnis aus `output.preferred_dirs` 2. erstes vorhandenes Verzeichnis aus `output.preferred_dirs`
@@ -70,11 +70,8 @@ Das Zielverzeichnis wird ueber `config.json` bestimmt:
Default: Default:
```json ```ini
"preferred_dirs": [ preferred_dirs = F:\VOD, H:\VOD
"F:\\VOD",
"H:\\VOD"
]
``` ```
Damit wird `F:\VOD` bevorzugt, wenn vorhanden. Sonst wird `H:\VOD` verwendet, wenn vorhanden. Damit wird `F:\VOD` bevorzugt, wenn vorhanden. Sonst wird `H:\VOD` verwendet, wenn vorhanden.
@@ -129,8 +126,8 @@ Unterstuetzt werden dreistellige Sprachcodes wie `DEU`, `GER`, `ENG`, `FRA`, `IT
## Video-Regeln ## Video-Regeln
- HD wird mit den HD-Werten aus `config.json` encodiert, standardmaessig `30M`. - HD wird mit den HD-Werten aus `config.ini` encodiert, standardmaessig `30M`.
- SD wird mit den SD-Werten aus `config.json` encodiert, standardmaessig `8M`. - SD wird mit den SD-Werten aus `config.ini` encodiert, standardmaessig `8M`.
- Interlaced-Material wird mit `bwdif=mode=0:parity=auto` deinterlaced. - Interlaced-Material wird mit `bwdif=mode=0:parity=auto` deinterlaced.
- Forced Subtitles werden eingebrannt, wenn neben der Quelle eine Datei mit `_forced.srt` liegt. - Forced Subtitles werden eingebrannt, wenn neben der Quelle eine Datei mit `_forced.srt` liegt.
- Farbraum-Metadaten werden auf den Ziel-Farbraum gesetzt. - Farbraum-Metadaten werden auf den Ziel-Farbraum gesetzt.
@@ -145,52 +142,50 @@ Film_DEU51_ENG20_forced.srt
## Konfiguration ## Konfiguration
Die wichtigsten Parameter stehen in [config.json](config.json). Die wichtigsten Parameter stehen in [config.ini](config.ini). Das Format ist bewusst einfach gehalten:
- `#` beginnt einen Kommentar
- Werte werden als `name = wert` geschrieben
- mehrere Ordner werden mit Komma getrennt
- leere Werte bedeuten automatische Suche bzw. automatische Auswahl
Default: Default:
```json ```ini
{ # Amazon PVD Mezzanine Encoder Konfiguration
"ffmpeg": {
"ffmpeg_exe": "", [ffmpeg]
"ffprobe_exe": "", ffmpeg_exe =
"search_dirs": [ ffprobe_exe =
"C:\\Tools\\FFMPEG", search_dirs = C:\Tools\FFMPEG, C:\Software
"C:\\Software"
] [output]
}, base_dir =
"output": { preferred_dirs = F:\VOD, H:\VOD
"base_dir": "",
"preferred_dirs": [ [video]
"F:\\VOD", hd_bitrate = 30M
"H:\\VOD" hd_maxrate = 35M
] hd_bufsize = 50M
}, hd_level = 4.1
"video": { sd_bitrate = 8M
"hd_bitrate": "30M", sd_maxrate = 10M
"hd_maxrate": "35M", sd_bufsize = 15M
"hd_bufsize": "50M", sd_level = 3.1
"hd_level": "4.1", preset = slow
"sd_bitrate": "8M", tune = film
"sd_maxrate": "10M",
"sd_bufsize": "15M", [audio]
"sd_level": "3.1", mp4_bitrate = 256k
"preset": "slow", sample_rate = 48000
"tune": "film" pcm_codec = pcm_s24le
},
"audio": {
"mp4_bitrate": "256k",
"sample_rate": "48000",
"pcm_codec": "pcm_s24le"
}
}
``` ```
Hinweise: Hinweise:
- `ffmpeg.ffmpeg_exe` und `ffmpeg.ffprobe_exe` koennen leer bleiben, dann wird automatisch gesucht. - `ffmpeg_exe` und `ffprobe_exe` koennen leer bleiben, dann wird automatisch gesucht.
- `output.base_dir` ueberschreibt die automatische Zielverzeichniswahl. - `base_dir` ueberschreibt die automatische Zielverzeichniswahl.
- Wenn `config.json` fehlt, wird sie beim Start mit Default-Werten erzeugt. - Wenn `config.ini` fehlt, wird sie beim Start mit Default-Werten erzeugt.
## Fehlerbilder ## Fehlerbilder
+43
View File
@@ -0,0 +1,43 @@
# Amazon PVD Mezzanine Encoder Konfiguration
# Zeilen mit # sind Kommentare.
# Leere Werte bedeuten: automatisch suchen bzw. automatisch waehlen.
[ffmpeg]
# Optional: feste Pfade setzen. Leer lassen fuer automatische Suche.
ffmpeg_exe =
ffprobe_exe =
# Suchordner nach PATH. Mehrere Ordner mit Komma trennen.
search_dirs = C:\Tools\FFMPEG, C:\Software
[output]
# Optional: festes Zielverzeichnis. Leer lassen fuer preferred_dirs.
base_dir =
# Erstes vorhandenes Verzeichnis wird verwendet.
preferred_dirs = F:\VOD, H:\VOD
[video]
# HD-PVD-MP4
hd_bitrate = 30M
hd_maxrate = 35M
hd_bufsize = 50M
hd_level = 4.1
# SD-PVD-MP4
sd_bitrate = 8M
sd_maxrate = 10M
sd_bufsize = 15M
sd_level = 3.1
# x264
preset = slow
tune = film
[audio]
# Deutscher Stereo-Ton im MP4
mp4_bitrate = 256k
sample_rate = 48000
# Audio-MOVs
pcm_codec = pcm_s24le
-34
View File
@@ -1,34 +0,0 @@
{
"ffmpeg": {
"ffmpeg_exe": "",
"ffprobe_exe": "",
"search_dirs": [
"C:\\Tools\\FFMPEG",
"C:\\Software"
]
},
"output": {
"base_dir": "",
"preferred_dirs": [
"F:\\VOD",
"H:\\VOD"
]
},
"video": {
"hd_bitrate": "30M",
"hd_maxrate": "35M",
"hd_bufsize": "50M",
"hd_level": "4.1",
"sd_bitrate": "8M",
"sd_maxrate": "10M",
"sd_bufsize": "15M",
"sd_level": "3.1",
"preset": "slow",
"tune": "film"
},
"audio": {
"mp4_bitrate": "256k",
"sample_rate": "48000",
"pcm_codec": "pcm_s24le"
}
}
+73 -17
View File
@@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import configparser
import json import json
import math import math
import os import os
@@ -27,7 +28,7 @@ except Exception:
# 1. KONFIGURATION UND PFADE # 1. KONFIGURATION UND PFADE
# ============================================================================= # =============================================================================
APP_DIR = Path(__file__).resolve().parent APP_DIR = Path(__file__).resolve().parent
CONFIG_PATH = APP_DIR / "config.json" CONFIG_PATH = APP_DIR / "config.ini"
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
"ffmpeg": { "ffmpeg": {
"ffmpeg_exe": "", "ffmpeg_exe": "",
@@ -64,29 +65,84 @@ DEFAULT_CONFIG = {
} }
def deep_merge_config(default: dict, override: dict) -> dict:
merged = dict(default)
for key, value in override.items():
if isinstance(value, dict) and isinstance(merged.get(key), dict):
merged[key] = deep_merge_config(merged[key], value)
else:
merged[key] = value
return merged
def write_default_config(path: Path) -> None: def write_default_config(path: Path) -> None:
path.write_text(json.dumps(DEFAULT_CONFIG, indent=2) + "\n", encoding="utf-8") path.write_text(
"""# Amazon PVD Mezzanine Encoder Konfiguration
# Zeilen mit # sind Kommentare.
# Leere Werte bedeuten: automatisch suchen bzw. automatisch waehlen.
[ffmpeg]
# Optional: feste Pfade setzen. Leer lassen fuer automatische Suche.
ffmpeg_exe =
ffprobe_exe =
# Suchordner nach PATH. Mehrere Ordner mit Komma trennen.
search_dirs = C:\\Tools\\FFMPEG, C:\\Software
[output]
# Optional: festes Zielverzeichnis. Leer lassen fuer preferred_dirs.
base_dir =
# Erstes vorhandenes Verzeichnis wird verwendet.
preferred_dirs = F:\\VOD, H:\\VOD
[video]
# HD-PVD-MP4
hd_bitrate = 30M
hd_maxrate = 35M
hd_bufsize = 50M
hd_level = 4.1
# SD-PVD-MP4
sd_bitrate = 8M
sd_maxrate = 10M
sd_bufsize = 15M
sd_level = 3.1
# x264
preset = slow
tune = film
[audio]
# Deutscher Stereo-Ton im MP4
mp4_bitrate = 256k
sample_rate = 48000
# Audio-MOVs
pcm_codec = pcm_s24le
""",
encoding="utf-8",
)
def split_config_list(value: str) -> list[str]:
return [part.strip() for part in value.split(",") if part.strip()]
def load_config() -> dict: def load_config() -> dict:
if not CONFIG_PATH.exists(): if not CONFIG_PATH.exists():
write_default_config(CONFIG_PATH) write_default_config(CONFIG_PATH)
return DEFAULT_CONFIG return DEFAULT_CONFIG
try:
user_config = json.loads(CONFIG_PATH.read_text(encoding="utf-8")) parser = configparser.ConfigParser()
except json.JSONDecodeError as exc: parser.read(CONFIG_PATH, encoding="utf-8")
raise RuntimeError(f"config.json ist ungueltig: {exc}") from exc config = {
return deep_merge_config(DEFAULT_CONFIG, user_config) section: dict(values)
for section, values in DEFAULT_CONFIG.items()
}
for section, defaults in DEFAULT_CONFIG.items():
if not parser.has_section(section):
continue
for key, default_value in defaults.items():
if not parser.has_option(section, key):
continue
raw_value = parser.get(section, key).strip()
if isinstance(default_value, list):
config[section][key] = split_config_list(raw_value)
else:
config[section][key] = raw_value
return config
def find_executable(name: str, configured_path: str, search_dirs: list[str]) -> str: def find_executable(name: str, configured_path: str, search_dirs: list[str]) -> str: