from __future__ import annotations from dataclasses import dataclass, field from pathlib import Path from typing import Optional, List, Dict AUDIO_EXTENSIONS = { ".mp3", ".flac", ".m4a", ".aac", ".ogg", ".opus", ".wav", ".wma", ".aiff", ".ape", } IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".gif"} TRACKLIST_EXTENSIONS = {".txt", ".htm", ".html", ".nfo"} PLAYLIST_EXTENSIONS = {".m3u", ".m3u8", ".pls"} @dataclass class ScannedFile: path: Path kind: str # "audio" | "image" | "tracklist" | "playlist" | "other" @dataclass class AlbumScan: album_dir: Path audio_files: List[Path] = field(default_factory=list) image_files: List[Path] = field(default_factory=list) tracklist_files: List[Path] = field(default_factory=list) other_files: List[Path] = field(default_factory=list) @dataclass class TrackHints: path: Path track_number: Optional[int] = None disc_number: Optional[int] = None title: Optional[str] = None artist: Optional[str] = None duration: Optional[float] = None existing_tags: Dict[str, str] = field(default_factory=dict) @dataclass class AlbumHints: album_dir: Path dir_artist: Optional[str] = None dir_album: Optional[str] = None dir_year: Optional[str] = None tracklist_text: Optional[str] = None # merged text from all tracklist files cover_images: List[Path] = field(default_factory=list) tracks: List[TrackHints] = field(default_factory=list) @dataclass class TrackProposal: path: Path title: str artist: str track_number: Optional[int] disc_number: Optional[int] new_filename: Optional[str] = None # only set when --rename is active mbid: Optional[str] = None @dataclass class AlbumProposal: album_dir: Path album: str albumartist: str date: Optional[str] genre: Optional[str] label: Optional[str] mbid: Optional[str] # MusicBrainz release ID cover_path: Optional[Path] # resolved local or downloaded cover cover_source: Optional[str] # "local" | "musicbrainz" | "discogs" tracks: List[TrackProposal] confidence: float sources: List[str] = field(default_factory=list) notes: List[str] = field(default_factory=list)