import re from pathlib import Path from linkki_poster.models import Language, LanguageAssets, ScanResult KNOWN_IMAGE_EXTENSIONS = { "jpg", "jpeg", "png", "webp", "gif", } GLOBAL_IMAGE_PREFIXES = ["Kuva"] LANGUAGE_TEXT_CANDIDATES: dict[Language, list[str]] = { Language.FI: ["Suomi.md"], Language.SV: ["Svenska.md"], Language.EN: ["English.md"], } LANGUAGE_IMAGE_PREFIXES: dict[Language, list[str]] = { Language.FI: ["Suomi"], Language.SV: ["Svenska"], Language.EN: ["English"], } def scan_directory(directory: Path) -> ScanResult: files = sorted((entry for entry in directory.iterdir() if entry.is_file()), key=lambda path: path.name.lower()) casefold_name_index = _build_casefold_name_index(files) global_images = select_first_matching_image_family(files, GLOBAL_IMAGE_PREFIXES) language_assets: list[LanguageAssets] = [] for language in (Language.FI, Language.SV, Language.EN): text_file = select_first_matching_text_file(casefold_name_index, LANGUAGE_TEXT_CANDIDATES[language]) if text_file is None: continue text_raw = text_file.read_text(encoding="utf-8") if text_raw.strip() == "": continue language_images = select_first_matching_image_family(files, LANGUAGE_IMAGE_PREFIXES[language]) language_assets.append( LanguageAssets( language=language, text_file=text_file, text_raw=text_raw, images=language_images, ) ) return ScanResult(global_images=global_images, languages=language_assets) def select_first_matching_text_file(casefold_name_index: dict[str, Path], candidate_names: list[str]) -> Path | None: for candidate_name in candidate_names: match = casefold_name_index.get(candidate_name.lower()) if match is not None: return match return None def select_first_matching_image_family(files: list[Path], prefixes: list[str]) -> list[Path]: for prefix in prefixes: matches = collect_image_matches_for_prefix(files, prefix) if matches: return [match[0] for match in sorted(matches, key=image_sort_key)] return [] def collect_image_matches_for_prefix(files: list[Path], prefix: str) -> list[tuple[Path, str, str]]: pattern = re.compile(rf"^{re.escape(prefix)}(\d*)\.([^.]+)$", re.IGNORECASE) matches: list[tuple[Path, str, str]] = [] for file_path in files: match = pattern.match(file_path.name) if match is None: continue extension = match.group(2).lower() if extension not in KNOWN_IMAGE_EXTENSIONS: continue numeric_suffix = match.group(1) matches.append((file_path, numeric_suffix, extension)) return matches def image_sort_key(match_item: tuple[Path, str, str]) -> tuple[int, int, str, str]: file_path, numeric_suffix, extension = match_item has_numeric_suffix = numeric_suffix != "" numeric_value = int(numeric_suffix) if has_numeric_suffix else -1 return ( 1 if has_numeric_suffix else 0, numeric_value, extension.lower(), file_path.name.lower(), ) def _build_casefold_name_index(files: list[Path]) -> dict[str, Path]: index: dict[str, Path] = {} for file_path in files: lowered = file_path.name.lower() if lowered not in index: index[lowered] = file_path return index