Lint-Fixes, process-Disc-Validierung und Forgejo-CI
- ruff: Import-Sortierung, unused imports, Zeilenlängen behoben - cli.py: _check_disc_counts_or_exit() extrahiert; auch process-Befehl prüft jetzt Disc-Anzahlen vor dem Umbenennen - .forgejo/workflows/ci.yml: ruff + pytest auf push/PR gegen main Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
88b89fbb50
commit
70c096cde4
6 changed files with 73 additions and 40 deletions
27
.forgejo/workflows/ci.yml
Normal file
27
.forgejo/workflows/ci.yml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
pull_request:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.11"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pip install -e ".[dev]"
|
||||||
|
|
||||||
|
- name: Lint (ruff)
|
||||||
|
run: ruff check src/ tests/
|
||||||
|
|
||||||
|
- name: Tests (pytest)
|
||||||
|
run: pytest tests/ -v --tb=short
|
||||||
|
|
@ -7,8 +7,9 @@ import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
from mutagen import File as MutagenFile
|
||||||
|
|
||||||
from musiksammlung.config import AudioFormat
|
from musiksammlung.config import AUDIO_EXTENSIONS, AudioFormat
|
||||||
from musiksammlung.cover import copy_covers, find_cover
|
from musiksammlung.cover import copy_covers, find_cover
|
||||||
from musiksammlung.llm_parser import parse_tracklist
|
from musiksammlung.llm_parser import parse_tracklist
|
||||||
from musiksammlung.models import Album
|
from musiksammlung.models import Album
|
||||||
|
|
@ -16,9 +17,6 @@ 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, check_disc_counts
|
||||||
from musiksammlung.playlist import generate_playlist
|
from musiksammlung.playlist import generate_playlist
|
||||||
from musiksammlung.ripper import RipperConfig, interactive_rip
|
from musiksammlung.ripper import RipperConfig, interactive_rip
|
||||||
from mutagen import File as MutagenFile
|
|
||||||
|
|
||||||
from musiksammlung.config import AUDIO_EXTENSIONS
|
|
||||||
from musiksammlung.tagger import embed_album_cover, tag_album
|
from musiksammlung.tagger import embed_album_cover, tag_album
|
||||||
from musiksammlung.vision_llm import parse_image
|
from musiksammlung.vision_llm import parse_image
|
||||||
|
|
||||||
|
|
@ -62,6 +60,39 @@ def _scan_to_album(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_disc_counts_or_exit(album: Album, input_dir: Path, album_json: Path) -> None:
|
||||||
|
"""Prüft Disc-Zählungen und beendet das Programm bei Abweichungen."""
|
||||||
|
checks = check_disc_counts(album, input_dir)
|
||||||
|
problems = [c for c in checks if not c.ok]
|
||||||
|
if not problems:
|
||||||
|
return
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
def _print_album_summary(album: Album) -> None:
|
def _print_album_summary(album: Album) -> None:
|
||||||
"""Gibt eine kompakte Album-Zusammenfassung aus."""
|
"""Gibt eine kompakte Album-Zusammenfassung aus."""
|
||||||
typer.echo(f" Artist: {album.artist}")
|
typer.echo(f" Artist: {album.artist}")
|
||||||
|
|
@ -167,34 +198,7 @@ def apply(
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
# Prüfe Track-Anzahl pro Disc
|
# Prüfe Track-Anzahl pro Disc
|
||||||
checks = check_disc_counts(album, input_dir)
|
_check_disc_counts_or_exit(album, input_dir, album_json)
|
||||||
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, in_place=in_place)
|
mapping = build_mapping(album, input_dir, output_dir, in_place=in_place)
|
||||||
typer.echo(f"Mapping: {len(mapping)} Dateien")
|
typer.echo(f"Mapping: {len(mapping)} Dateien")
|
||||||
|
|
@ -346,6 +350,9 @@ def process(
|
||||||
json_path = input_dir / "album.json"
|
json_path = input_dir / "album.json"
|
||||||
json_path.write_text(album.model_dump_json(indent=2), encoding="utf-8")
|
json_path.write_text(album.model_dump_json(indent=2), encoding="utf-8")
|
||||||
|
|
||||||
|
# Prüfe Track-Anzahl pro Disc
|
||||||
|
_check_disc_counts_or_exit(album, input_dir, json_path)
|
||||||
|
|
||||||
# 2. Dateien organisieren
|
# 2. Dateien organisieren
|
||||||
typer.echo("Schritt 2/4: Dateien organisieren...")
|
typer.echo("Schritt 2/4: Dateien organisieren...")
|
||||||
mapping = build_mapping(album, input_dir, output_dir)
|
mapping = build_mapping(album, input_dir, output_dir)
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from musiksammlung.cover import find_cover
|
from musiksammlung.cover import find_cover
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from musiksammlung.models import Album, Disc, Track
|
from musiksammlung.models import Album, Disc, Track
|
||||||
from musiksammlung.organizer import (
|
from musiksammlung.organizer import (
|
||||||
_sanitize_filename,
|
_sanitize_filename,
|
||||||
|
|
@ -122,7 +120,10 @@ class TestCheckDiscCounts:
|
||||||
album="B",
|
album="B",
|
||||||
discs=[
|
discs=[
|
||||||
Disc(disc_number=1, tracks=[Track(track_number=1, title="T1")]),
|
Disc(disc_number=1, tracks=[Track(track_number=1, title="T1")]),
|
||||||
Disc(disc_number=2, tracks=[Track(track_number=1, title="T2"), Track(track_number=2, title="T3")]),
|
Disc(
|
||||||
|
disc_number=2,
|
||||||
|
tracks=[Track(track_number=1, title="T2"), Track(track_number=2, title="T3")],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
results = check_disc_counts(album, tmp_path)
|
results = check_disc_counts(album, tmp_path)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ def _make_album(n_tracks: int = 2, n_discs: int = 1) -> Album:
|
||||||
discs = [
|
discs = [
|
||||||
Disc(
|
Disc(
|
||||||
disc_number=d,
|
disc_number=d,
|
||||||
tracks=[Track(track_number=i, title=f"Disc{d} Song {i}") for i in range(1, n_tracks + 1)],
|
tracks=[
|
||||||
|
Track(track_number=i, title=f"Disc{d} Song {i}") for i in range(1, n_tracks + 1)
|
||||||
|
],
|
||||||
)
|
)
|
||||||
for d in range(1, n_discs + 1)
|
for d in range(1, n_discs + 1)
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from musiksammlung.config import AudioFormat
|
from musiksammlung.config import AudioFormat
|
||||||
from musiksammlung.ripper import (
|
from musiksammlung.ripper import (
|
||||||
RipperConfig,
|
RipperConfig,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue