CI / lint (push) Canceled after 0s
CI / typecheck (push) Canceled after 0s
CI / unit-tests (push) Canceled after 0s
CI / integration-tests (push) Canceled after 0s
CI / container-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
New TMDb integration end to end: append_to_response "watch/providers", normalizer parsing grouped by country/monetization type, a WatchProvider catalog entry (external-id keyed, same get_or_create pattern as Company/ Collection/Person) + polymorphic WatchProviderOffering table (new migration 0002), ingestion write (including provider logos via the existing Artwork table), and API exposure -- embedded on movie/series detail plus a dedicated /watch-providers sub-route, shaped to mirror TMDb's own response for easy porting. Note: this data comes from JustWatch via TMDb and carries its own attribution requirement separate from TMDb's general one -- flagged in docs/api.md, must be satisfied before showing this in the frontend. Co-Authored-By: Claude Sonnet 5 <[email protected]>
62 lines
2.0 KiB
Python
62 lines
2.0 KiB
Python
"""watch providers
|
|
|
|
Revision ID: 0002_watch_providers
|
|
Revises: 0001_initial_schema
|
|
Create Date: 2026-09-06
|
|
|
|
Adds the where-to-watch tables (section 17, additive): a WatchProvider
|
|
catalog entry (Netflix, Apple TV, etc. -- TMDb's own provider_id links in
|
|
via the existing external_ids table, same pattern as Company/Collection/
|
|
Person) and WatchProviderOffering, a polymorphic (entity_type, entity_id)
|
|
table like release_dates, one row per (movie/series, country,
|
|
monetization type, provider).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Sequence
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision: str = "0002_watch_providers"
|
|
down_revision: str | None = "0001_initial_schema"
|
|
branch_labels: str | Sequence[str] | None = None
|
|
depends_on: str | Sequence[str] | None = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.create_table(
|
|
"watch_providers",
|
|
sa.Column("id", sa.Uuid(), primary_key=True),
|
|
sa.Column("name", sa.String(200), nullable=False),
|
|
)
|
|
|
|
op.create_table(
|
|
"watch_provider_offerings",
|
|
sa.Column("id", sa.Uuid(), primary_key=True),
|
|
sa.Column("entity_type", sa.String(30), nullable=False),
|
|
sa.Column("entity_id", sa.Uuid(), nullable=False),
|
|
sa.Column("country_code", sa.String(2), sa.ForeignKey("countries.code"), nullable=False),
|
|
sa.Column("monetization_type", sa.String(20), nullable=False),
|
|
sa.Column(
|
|
"watch_provider_id",
|
|
sa.Uuid(),
|
|
sa.ForeignKey("watch_providers.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
),
|
|
sa.Column("display_priority", sa.Integer(), nullable=True),
|
|
sa.Column("link", sa.Text(), nullable=True),
|
|
)
|
|
op.create_index(
|
|
"ix_watch_provider_offerings_entity",
|
|
"watch_provider_offerings",
|
|
["entity_type", "entity_id"],
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_index("ix_watch_provider_offerings_entity", table_name="watch_provider_offerings")
|
|
op.drop_table("watch_provider_offerings")
|
|
op.drop_table("watch_providers")
|