goon/app/normalize/movies.py
goon-foss d471bb3293 fix(ingest): dekoduj encje HTML w tytulach scen i filmow
xvideos (JSON-LD) i kilka innych tubow oddaje tytuly z encjami HTML5
(`we're`, `(AI)`), czasem podwojnie zakodowane. normalize
robil z nich slowa `apos`, `lpar`, wiec tytul nie trafial w wyszukiwarke
ani w kanon.

unescape_html w app/normalize/text.py dekoduje encje zakonczone srednikiem
po slowniku HTML5, do skutku (max 3 przebiegi). Wpiete w normalize_scene i
normalize_movie oraz w parsery xvideos_browse i pornxp. Skrypt
fix_html_entity_titles.py poprawia istniejace wiersze (title,
title_normalized, slug gdy byl wyliczony z tytulu).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:59:39 +02:00

67 lines
2.1 KiB
Python

"""RawMovie → NormalizedMovie. Reuse normalize_studio/performer/tag z scenes.py."""
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import date
from app.connectors.base import RawMovie, RawMovieChapter, RawPlaybackSource
from app.normalize.scenes import (
NormalizedPerformer,
NormalizedStudio,
NormalizedTag,
normalize_performer,
normalize_studio,
normalize_tag,
)
from app.normalize.text import normalize, slugify, unescape_html
@dataclass
class NormalizedMovie:
external_id: str
title: str
title_normalized: str
slug: str
release_year: int | None
release_date: date | None
description: str | None
duration_sec: int | None
director: str | None
country: str | None
rating: float | None
poster_url: str | None
backdrop_url: str | None
url: str | None
studio: NormalizedStudio | None = None
performers: list[NormalizedPerformer] = field(default_factory=list)
tags: list[NormalizedTag] = field(default_factory=list)
chapters: list[RawMovieChapter] = field(default_factory=list)
playback_sources: list[RawPlaybackSource] = field(default_factory=list)
cross_source_refs: dict[str, str] = field(default_factory=dict)
def normalize_movie(raw: RawMovie) -> NormalizedMovie:
title = unescape_html(raw.title)
return NormalizedMovie(
external_id=raw.external_id,
title=title,
title_normalized=normalize(title),
slug=slugify(title),
release_year=raw.release_year,
release_date=raw.release_date,
description=raw.description,
duration_sec=raw.duration_sec,
director=raw.director,
country=raw.country,
rating=raw.rating,
poster_url=raw.poster_url,
backdrop_url=raw.backdrop_url,
url=raw.url,
studio=normalize_studio(raw.studio) if raw.studio else None,
performers=[normalize_performer(p) for p in raw.performers],
tags=[normalize_tag(t) for t in raw.tags],
chapters=list(raw.chapters),
playback_sources=list(raw.playback_sources),
cross_source_refs=dict(raw.cross_source_refs),
)