goon/app/models/__init__.py
jtrzupek c154deab37 feat(sources): 0-5★ ranking on Sites (freshness/metadata/plays) + playback telemetry
Rates each source on three axes the user asked for:
- freshness: how recently/often new content arrives (newest age + 7d volume)
- richness: metadata coverage (thumbnail/tags/performers/description/studio/duration)
- plays: does it actually play — from real playback telemetry when available,
  else a proxy from the resolve mechanism. 0★ = offline (gates the overall stars,
  so a fresh+rich source that doesn't play still ranks bottom — the hqfap/4k69 case)

Backend:
- playback_events: fire-and-forget telemetry POST from the app per playback attempt
  (origin + success/error + time-to-first-frame), append-only, 30d retention
- source_stats: per-origin computed scores, refreshed by a scheduler job (6h);
  /sources joins it and sorts by stars
- models + local migration 0025; new GOON_SCHED_SOURCE_STATS_HOURS setting

Mobile:
- Sites rows show ★ rating; tap the stars for a breakdown (axes + metadata %, plus
  whether "plays" is measured or estimated)
- PlayerScreen reports playback success/failure per source (native path only —
  symmetric, conservative); origin threaded through Scene/Movie play callsites

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:00:59 +02:00

72 lines
2 KiB
Python

from app.models.base import Base
from app.models.blacklist import BlacklistedPerformer, BlacklistedStudio, BlacklistedTag
from app.models.bug_report import BugReport
from app.models.external_record import ExternalRecord
from app.models.favorite_movie import FavoriteMovie
from app.models.favorite_performer import FavoritePerformer
from app.models.favorite_scene import FavoriteScene
from app.models.favorite_studio import FavoriteStudio
from app.models.ingest_run import IngestRun
from app.models.merge_candidate import MergeCandidate
from app.models.movie import (
Movie,
MovieChapter,
MovieExternalRef,
MoviePerformer,
MovieTag,
)
from app.models.movie_playback_source import MoviePlaybackSource
from app.models.performer import Performer, PerformerAlias, PerformerExternalRef
from app.models.play_progress import MoviePlayProgress, ScenePlayProgress
from app.models.playback_event import PlaybackEvent
from app.models.playback_source import PlaybackSource
from app.models.saved_search import SavedSearch
from app.models.source_stats import SourceStats
from app.models.scene import (
Scene,
SceneExternalRef,
SceneFingerprint,
ScenePerformer,
SceneTag,
)
from app.models.source import Source
from app.models.studio import Studio, StudioAlias, StudioExternalRef
from app.models.tag import Tag
__all__ = [
"Base",
"BlacklistedPerformer",
"BlacklistedStudio",
"BlacklistedTag",
"BugReport",
"ExternalRecord",
"FavoriteMovie",
"FavoritePerformer",
"FavoriteScene",
"FavoriteStudio",
"IngestRun",
"MergeCandidate",
"Movie",
"MovieChapter",
"MovieExternalRef",
"MoviePerformer",
"MoviePlaybackSource",
"MovieTag",
"Performer",
"PerformerAlias",
"PerformerExternalRef",
"MoviePlayProgress",
"ScenePlayProgress",
"PlaybackSource",
"SavedSearch",
"Scene",
"SceneExternalRef",
"SceneFingerprint",
"ScenePerformer",
"SceneTag",
"Source",
"Studio",
"StudioAlias",
"StudioExternalRef",
"Tag",
]