Build custom container images / build (map[base_image:php:8-fpm-alpine build_args:PHP_VERSION=8
context:php8-pgsql fingerprint_command:{ apk info -v | LC_ALL=C sort; find /usr/local/lib/php/extensions /usr/local/etc/php/conf.d -type f -exec sha256sum {} + | LC_ALL=C sort; }
name:ph… (push) Successful in 48s
Build custom container images / build (map[base_image:postgres:18 build_args:PG_VERSION=18
POSTGIS_VERSION=3
VCHORD_VERSION=0.5.3
context:postgres fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; find /usr/lib/postgresql -type f -exec sha256su… (push) Successful in 55s
Build custom container images / build (map[base_image:python:3 build_args:PYTHON_VERSION=3
context:python-tools fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; pip freeze | LC_ALL=C sort; }
name:python-tools oci_labels:org.opencontainers.ima… (push) Successful in 54s
Build custom container images / build (map[base_image:python:3.12-slim build_args:PYTHON_VERSION=3.12-slim
context:linkki-tiedotus fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; pip freeze | LC_ALL=C sort; }
name:linkki-tiedotus oci_labels:… (push) Successful in 39s
111 lines
3.4 KiB
Python
111 lines
3.4 KiB
Python
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
|