1 755 421 scen nie ma dlugosci ani na scenie, ani na zrodle, wiec wypadaja z feedu: w SQL "duration_sec >= 60" nie jest prawda dla NULL, przez co scena o nieznanej dlugosci znika tak samo jak dziesieciosekundowy smiec. Filtr zostaje, bo odcina smieci, uzupelniamy dane. Swiadomie waskie originy. Uniwersalny regex trafia w smieci: porntrex ma w HTML "duration: 5" reklamy, mypornerleak dlugosc ciastka 720, a xhamster i porntrex wypisuja dlugosci filmow z paska obok (naiwne dopasowanie dalo 198s zamiast 240s). Zla dlugosc jest gorsza niz brak, bo dedup opiera sie na niej najmocniej. - xvideos, xnxx: VideoObject LD-JSON, 5/5 na probce - xhamster: videoEntity z kontrola zgodnosci id z URL-a - porntrex pominiety: strona szczegolow nie podaje wlasnej dlugosci Kolejka jak przy phashu (plan raz, mielenie paczkami, przezywa restart): 845 899 scen, 500 stron co 5 min, czyli ok. 6 dni. Plan powtarza sie co 24h, zeby swieze sceny bez dlugosci tez trafialy do kolejki. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
55 lines
1.9 KiB
Python
55 lines
1.9 KiB
Python
"""duration_backfill_queue: kolejka scen do doliczenia dlugosci ze strony tuba
|
|
|
|
Uzasadnienie i liczby: `app/models/duration_backfill_queue.py`.
|
|
|
|
Revision ID: 0031_duration_backfill
|
|
Revises: 0030_scenes_quality_idx
|
|
Create Date: 2026-08-20
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
from sqlalchemy.dialects import postgresql
|
|
|
|
# Uwaga: `alembic_version.version_num` to varchar(32), dluzsze id nie wejdzie.
|
|
revision: str = "0031_duration_backfill"
|
|
down_revision: str | None = "0030_scenes_quality_idx"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.create_table(
|
|
"duration_backfill_queue",
|
|
sa.Column("scene_id", postgresql.UUID(as_uuid=True), nullable=False),
|
|
sa.Column("page_url", sa.String(length=1024), nullable=False),
|
|
sa.Column("origin", sa.String(length=64), nullable=False),
|
|
sa.Column("attempts", sa.Integer(), nullable=False, server_default="0"),
|
|
sa.Column("done_at", sa.DateTime(timezone=True), nullable=True),
|
|
sa.Column(
|
|
"created_at",
|
|
sa.DateTime(timezone=True),
|
|
server_default=sa.func.now(),
|
|
nullable=False,
|
|
),
|
|
sa.ForeignKeyConstraint(
|
|
["scene_id"], ["scenes.id"], ondelete="CASCADE",
|
|
name="fk_duration_backfill_queue_scene_id_scenes",
|
|
),
|
|
sa.PrimaryKeyConstraint("scene_id", name="pk_duration_backfill_queue"),
|
|
)
|
|
# Paczka bierze wiersze niezrobione, po originie (zeby nie zawalic jednego hosta).
|
|
op.create_index(
|
|
"ix_duration_backfill_queue_pending",
|
|
"duration_backfill_queue",
|
|
["origin", "attempts"],
|
|
postgresql_where=sa.text("done_at IS NULL"),
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_index(
|
|
"ix_duration_backfill_queue_pending", table_name="duration_backfill_queue"
|
|
)
|
|
op.drop_table("duration_backfill_queue")
|