Compare commits

..

No commits in common. "f4e49a3df6e2fc5be4b980aa783e60dd3f1ec9f2" and "8765e991b0e3334f745ac04b04e57dfa7f692dcb" have entirely different histories.

4 changed files with 5 additions and 87 deletions

View file

@ -13,7 +13,7 @@ from musiksammlung.cover import copy_covers
from musiksammlung.llm_parser import parse_tracklist
from musiksammlung.models import Album
from musiksammlung.ocr import ocr_images
from musiksammlung.organizer import apply_mapping, build_mapping, check_disc_counts
from musiksammlung.organizer import apply_mapping, build_mapping
from musiksammlung.playlist import generate_playlist
from musiksammlung.ripper import RipperConfig, interactive_rip
from musiksammlung.tagger import tag_album
@ -90,7 +90,7 @@ def scan(
),
languages: str = typer.Option("deu+eng", "--lang", "-l", help="OCR-Sprachen"),
backend: str = typer.Option("ollama", "--backend", "-b", help="LLM-Backend"),
model: str = typer.Option("gemma3:12b", "--model", "-m", help="Text-LLM-Modell"),
model: str = typer.Option("llama3", "--model", "-m", help="Text-LLM-Modell"),
base_url: str = typer.Option(
"http://localhost:11434", "--url", help="LLM-API-URL"
),
@ -146,36 +146,6 @@ def apply(
raw = json.loads(album_json.read_text(encoding="utf-8"))
album = Album.model_validate(raw)
# Prüfe Track-Anzahl pro Disc
checks = check_disc_counts(album, input_dir)
problems = [c for c in checks if not c.ok]
if problems:
typer.echo(
"\nFEHLER: Track-Diskrepanz zwischen gerippten Dateien und album.json:\n",
err=True,
)
for c in checks:
status = "OK" if c.ok else "!!"
typer.echo(
f" [{status}] Disc {c.disc_number}: "
f"{c.audio_file_count} Datei(en), {c.json_track_count} JSON-Track(s)",
err=True,
)
if c.surplus_files:
typer.echo(
f"{c.surplus_files} Track(s) fehlen im JSON "
f"(Tracks {c.json_track_count + 1}{c.audio_file_count} eintragen)",
err=True,
)
elif c.surplus_json:
typer.echo(
f"{c.surplus_json} JSON-Eintrag/Einträge ohne Audiodatei "
f"(Tracks {c.audio_file_count + 1}{c.json_track_count} prüfen)",
err=True,
)
typer.echo(f"\nBitte {album_json} korrigieren und erneut aufrufen.", err=True)
raise typer.Exit(1)
mapping = build_mapping(album, input_dir, output_dir)
typer.echo(f"Mapping: {len(mapping)} Dateien")
for src, dst in mapping.items():
@ -292,7 +262,7 @@ def process(
),
languages: str = typer.Option("deu+eng", "--lang", "-l"),
backend: str = typer.Option("ollama", "--backend", "-b"),
model: str = typer.Option("gemma3:12b", "--model", "-m"),
model: str = typer.Option("llama3", "--model", "-m"),
base_url: str = typer.Option("http://localhost:11434", "--url"),
dry_run: bool = typer.Option(False, "--dry-run"),
) -> None:

View file

@ -47,7 +47,7 @@ def _call_ollama(text: str, model: str, base_url: str) -> str:
],
"stream": False,
},
timeout=300.0,
timeout=120.0,
)
response.raise_for_status()
return response.json()["message"]["content"]
@ -71,7 +71,7 @@ def _call_openai_compatible(
{"role": "user", "content": text},
],
},
timeout=300.0,
timeout=120.0,
)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]

View file

@ -5,7 +5,6 @@ from __future__ import annotations
import logging
import re
import shutil
from dataclasses import dataclass
from pathlib import Path
from musiksammlung.config import AUDIO_EXTENSIONS
@ -14,29 +13,6 @@ from musiksammlung.models import Album
logger = logging.getLogger(__name__)
@dataclass
class DiscCheck:
"""Ergebnis der Track-Zählung für eine einzelne Disc."""
disc_number: int
audio_file_count: int
json_track_count: int
@property
def ok(self) -> bool:
return self.audio_file_count == self.json_track_count
@property
def surplus_files(self) -> int:
"""Dateien ohne JSON-Eintrag (Tracks fehlen im JSON)."""
return max(0, self.audio_file_count - self.json_track_count)
@property
def surplus_json(self) -> int:
"""JSON-Einträge ohne Datei (Dateien fehlen im Verzeichnis)."""
return max(0, self.json_track_count - self.audio_file_count)
def _sanitize_filename(name: str) -> str:
"""Entfernt problematische Zeichen aus Dateinamen."""
return re.sub(r'[<>:"/\\|?*]', "_", name).strip()
@ -52,31 +28,6 @@ def discover_audio_files(directory: Path) -> list[Path]:
return sorted(files, key=extract_number)
def check_disc_counts(album: Album, input_dir: Path) -> list[DiscCheck]:
"""Vergleicht Dateianzahl und JSON-Track-Anzahl pro Disc.
Args:
album: Validiertes Album-Modell
input_dir: Verzeichnis mit gerippten Dateien (enthält CD1/, CD2/, ... bei Multi-Disc)
Returns:
Liste von DiscCheck-Objekten auch für korrekte Discs (ok=True).
"""
multi_disc = len(album.discs) > 1
results: list[DiscCheck] = []
for disc in album.discs:
source_dir = input_dir / f"CD{disc.disc_number}" if multi_disc else input_dir
file_count = len(discover_audio_files(source_dir)) if source_dir.exists() else 0
results.append(DiscCheck(
disc_number=disc.disc_number,
audio_file_count=file_count,
json_track_count=len(disc.tracks),
))
return results
def build_mapping(
album: Album,
input_dir: Path,

View file

@ -28,9 +28,6 @@ WICHTIG:
- Wenn "CD 1", "CD 2", "Disc 1" etc. sichtbar sind, erstelle mehrere Einträge in "discs".
- Ohne Disc-Angabe: eine Disc mit disc_number=1.
- Lasse Zeitangaben (z.B. "3:12") und Interpretenangaben pro Track weg.
- MEHRSPALTIGE LAYOUTS: CD-Rückseiten haben oft 2, 3 oder 4 Spalten nebeneinander.
Lies ALLE Spalten vollständig von oben nach unten, bevor du zur nächsten Spalte gehst.
Überspringen oder Auslassen von Spalten ist ein häufiger Fehler lies jede Spalte komplett.
Antworte NUR mit dem JSON, ohne Erklärung. Beispiel: