goon/app/models/external_record.py
goon-foss ad0284585b Initial commit
Goon — self-hosted aggregator for adult-content scene metadata.

Indexes scenes from TPDB, StashDB, and 30+ public adult tube sites.
Cross-source deduplication via perceptual hash + Levenshtein distance.
FastAPI backend + APScheduler worker + React Native (Expo) mobile client.

FOSS, ad-free, donation-funded. See README for details.
2026-05-20 10:10:22 +02:00

42 lines
1.5 KiB
Python

import enum
import uuid
from datetime import datetime
from sqlalchemy import DateTime, Enum, ForeignKey, LargeBinary, String, UniqueConstraint, func
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy.orm import Mapped, mapped_column
from app.models.base import Base, UUIDPKMixin
class EntityKind(str, enum.Enum):
scene = "scene"
performer = "performer"
studio = "studio"
tag = "tag"
movie = "movie"
class ExternalRecord(UUIDPKMixin, Base):
"""Surowy snapshot encji z konkretnego źródła. Idempotentny — raw_hash chroni przed reprocessingiem."""
__tablename__ = "external_records"
__table_args__ = (
UniqueConstraint("source_id", "entity_kind", "external_id"),
)
source_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("sources.id", ondelete="CASCADE"), nullable=False, index=True
)
entity_kind: Mapped[EntityKind] = mapped_column(
Enum(EntityKind, name="entity_kind"), nullable=False
)
external_id: Mapped[str] = mapped_column(String, nullable=False)
raw: Mapped[dict] = mapped_column(JSONB, nullable=False)
raw_hash: Mapped[bytes] = mapped_column(LargeBinary(32), nullable=False)
fetched_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)
last_seen_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)