from pathlib import Path from app.settings import settings # Instance state, not baked into the image -- seeded from # pipeline/configs/artist-canonical.list.example on first boot (see # entrypoint.sh) and edited from here after that. Read directly by # normalize-artist-casing.py at run time, same file, no caching. def _path() -> Path: return settings.pipeline_config_dir / "artist-canonical.list" def _is_entry_line(line: str) -> bool: stripped = line.strip() return bool(stripped) and not stripped.startswith("#") def list_entries() -> list[str]: path = _path() if not path.exists(): return [] return [line.strip() for line in path.read_text(encoding="utf-8").splitlines() if _is_entry_line(line)] def add_entry(name: str) -> None: """Append a canonical name, or if one already matches case-insensitively (the whole point of this list is one canonical casing per artist), replace that line's casing instead of adding a duplicate.""" name = name.strip() if not name: raise ValueError("artist name cannot be empty") path = _path() path.parent.mkdir(parents=True, exist_ok=True) lines = path.read_text(encoding="utf-8").splitlines() if path.exists() else [] for i, line in enumerate(lines): if _is_entry_line(line) and line.strip().lower() == name.lower(): lines[i] = name path.write_text("\n".join(lines) + "\n", encoding="utf-8") return lines.append(name) path.write_text("\n".join(lines) + "\n", encoding="utf-8") def remove_entry(name: str) -> None: path = _path() if not path.exists(): return lines = path.read_text(encoding="utf-8").splitlines() lines = [line for line in lines if not (_is_entry_line(line) and line.strip() == name)] path.write_text("\n".join(lines) + "\n", encoding="utf-8")