rename project to fhdhview

This commit is contained in:
dreamer committed 2026-10-19 16:01:27 +02:00
1 parent c4d3b6b292
commit 6755875938
51 files changed
+39 -39

No files matched your search

View File
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,99 @@
# SPDX-FileCopyrightText: 2026 Filmhuis Den Haag
# SPDX-License-Identifier: AGPL-3.0-or-later
from sqlmodel import delete
from sqlmodel.ext.asyncio.session import AsyncSession
from fhdhview.models.enums import Screen
from fhdhview.models.screening import KijkWijzer, Screening
from fhdhview.models.tags import kijkwijzer, screens
from fhdhview.services.screenwriter.schema import AAMPos
# Delimiters used to attach notes to titles
DASH_DELIMITERS = (" - ", " – ", " — ", "- ")
# Explicit list of known screening notes (exact matches only)
KNOWN_SCREENING_NOTES = frozenset({
# Subtitles
"en subs",
"en sub",
"nl subs",
"nl sub",
# Events & talks
"met inleiding",
"met nagesprek",
"met inleiding en nagesprek",
"met voorfilms en nagesprek",
# Combined notes
"en subs met inleiding",
"en subs en nagesprek",
})
def _clean_title(title: str) -> str:
"""Peel off trailing presentation notes using an explicit blacklist."""
for dash in DASH_DELIMITERS:
while dash in title:
prefix, _, suffix = title.rpartition(dash)
# Exact string check (case-insensitive and trimmed)
if suffix.strip().lower() in KNOWN_SCREENING_NOTES:
title = prefix.strip()
else:
break
return title.strip()
async def import_sessions(data: AAMPos, session: AsyncSession):
# purge old rows
await session.exec(delete(Screening))
# add new screenings from data
for screening in data.sessions.root:
kijk: list[KijkWijzer] = []
for k in kijkwijzer:
if k in screening.attributes:
kijk.append(kijkwijzer[k])
screening.attributes.remove(k)
if "EN subs" in screening.attributes:
en_subs = True
screening.attributes.remove("EN subs")
else:
en_subs = False
if "with introduction" in screening.attributes:
intro = True
screening.attributes.remove("with introduction")
else:
intro = False
if "with after talk" in screening.attributes:
outro = True
screening.attributes.remove("with after talk")
else:
outro = False
new_screening = Screening(
session=screening.session_id,
screen=screens.get(screening.screen_identifier, Screen.ONE),
complex_ident=screening.complex_identifier,
start=screening.start,
end=screening.end,
duration=screening.feature_duration,
title=_clean_title(screening.title),
rating=screening.rating,
seats_total=screening.seats_available,
seats_sold=screening.seats_sold,
en_subs=en_subs,
intro=intro,
outro=outro,
kijkwijzer=kijk,
tags=screening.attributes
)
session.add(new_screening)
await session.commit()
+20
View File
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2026 Filmhuis Den Haag
# SPDX-License-Identifier: AGPL-3.0-or-later
from xml.etree import ElementTree as ET
from pydantic import ValidationError
from fhdhview.services.screenwriter.schema import AAMPos
class XmlParseError(Exception):
"""Raised when an XML is malformed or violates the ScreenWriter schema."""
def parse_screenwriter_xml(content: bytes | str) -> AAMPos:
"""Parser raw ScreenWriter XML into validated Pydantic models."""
try:
return AAMPos.from_xml(content)
except (ValidationError, ET.ParseError) as e:
raise XmlParseError(f"Failed to parse ScreenWriter XML: {e}") from e
+37
View File
@@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: 2026 Filmhuis Den Haag
# SPDX-License-Identifier: AGPL-3.0-or-later
from datetime import datetime
from typing import Annotated
from zoneinfo import ZoneInfo
from pydantic import BeforeValidator
from pydantic_xml import BaseXmlModel, RootXmlModel, element, wrapped
from fhdhview.core.config import settings
DT = Annotated[datetime, BeforeValidator(lambda v: datetime.strptime(v, "%Y%m%d%H%M").replace(
tzinfo=ZoneInfo(settings.timezone)
))]
class Session(BaseXmlModel, tag='session'):
session_id: int = element(tag='id')
screen_identifier: str = element()
complex_identifier: str = element()
start: DT = element()
end: DT = element()
feature_duration: int = element()
title: str = element()
rating: int = element()
seats_available: int = element()
seats_sold: int = element()
attributes: list[str] = wrapped('session_attributes', element(tag='session_attribute'))
class Sessions(RootXmlModel, tag='sessions'):
root: list[Session]
class AAMPos(BaseXmlModel, tag='AAMPos'):
sessions: Sessions = element()