Nowy wertykal krotkich pionowych klipow tworcow, osobno od scen: inne kolumny (tworca, audio, lajki, nisze), inny cykl zycia, inna taksonomia, brak filtra 60 s. Tabele `clips` (unikalne source+source_id) i `clip_tags` z indeksem (tag, clip_id) pod skan po tagu od losowego uuid w przyszlym feedzie. Zrodlo nr 1: RedGifs, oficjalne API v2 z tokenem tymczasowym (zwiazany z IP i UA, na 401 odnowienie). Globalne `order=latest` bez search_text daje ~100 na strone, kazde zapytanie widzi maks. 10 000 wynikow, wiec katalog chodzi sie po niszach (skrypt backfillu). Pliki media.redgifs.com sa publiczne i bez podpisu (206 z VPS-a i z telefonu), do bazy wchodzi gotowy adres. Scheduler: job clips-latest co godzine (5 stron), zatrzymuje sie na stronie bez nowych. Reaper (HEAD, 403/404/410 -> dead_at) jako skrypt, upsert odzywia klip, ktory zrodlo znow podaje. API: GET /clips i /clips/stats do pilota; wlasciwy feed, pamiec widzianych i telemetria to etap 3. Sprawdzone tego dnia i odlozone: nsfwswipe (lustro v.redd.it, bez audio, stoi od 19.08), Pornhub Shorties (zrodlo nr 2, HLS z tokenem 2 h, Referer na segmentach, 0/110 performerow z kanonu).
54 lines
1.8 KiB
Python
54 lines
1.8 KiB
Python
from datetime import UTC, datetime
|
|
|
|
from app.connectors.clips.redgifs import map_gif, tag_slug
|
|
|
|
SAMPLE = {
|
|
"id": "unusualequalaxolotl",
|
|
"type": 1,
|
|
"createDate": 1789393316,
|
|
"contentType": "Solo Female",
|
|
"duration": 9.4,
|
|
"hasAudio": True,
|
|
"height": 1920,
|
|
"width": 1080,
|
|
"hls": True,
|
|
"likes": 12,
|
|
"views": 340,
|
|
"niches": ["just-boobs"],
|
|
"tags": ["Femdom", "Pegging", "Strap On", "Strap On"],
|
|
"urls": {
|
|
"sd": "https://media.redgifs.com/UnusualEqualAxolotl-mobile.mp4",
|
|
"hd": "https://media.redgifs.com/UnusualEqualAxolotl.mp4",
|
|
"poster": "https://media.redgifs.com/UnusualEqualAxolotl-poster.jpg",
|
|
"thumbnail": "https://media.redgifs.com/UnusualEqualAxolotl-mobile.jpg",
|
|
},
|
|
"userName": "kitsuneroth",
|
|
"verified": True,
|
|
}
|
|
|
|
|
|
def test_map_gif_basic():
|
|
c = map_gif(SAMPLE)
|
|
assert c is not None
|
|
assert c.source == "redgifs" and c.source_id == "unusualequalaxolotl"
|
|
assert c.creator == "kitsuneroth" and c.creator_verified is True
|
|
assert c.has_audio is True and c.duration_sec == 9.4
|
|
assert c.width == 1080 and c.height == 1920
|
|
assert c.hd_url.endswith("UnusualEqualAxolotl.mp4")
|
|
assert c.published_at == datetime.fromtimestamp(1789393316, tz=UTC)
|
|
# slugi, bez duplikatow, kolejnosc zachowana
|
|
assert c.tags == ["femdom", "pegging", "strap-on"]
|
|
assert c.niches == ["just-boobs"]
|
|
assert c.likes == 12 and c.views == 340
|
|
|
|
|
|
def test_map_gif_skips_images_and_fileless():
|
|
assert map_gif({**SAMPLE, "type": 2}) is None
|
|
assert map_gif({**SAMPLE, "urls": {}}) is None
|
|
assert map_gif({**SAMPLE, "id": ""}) is None
|
|
|
|
|
|
def test_tag_slug():
|
|
assert tag_slug("Big Tits") == "big-tits"
|
|
assert tag_slug(" 18 Years Old!! ") == "18-years-old"
|
|
assert tag_slug("") == ""
|