feat(providers): phases 7.3/7.4/7.6/8.1 — provenance, health, NDJSON, contrat unique
CI / build-and-test (push) Successful in 14m43s
CI / build-and-test (push) Successful in 14m43s
7.3: capturedAt/source au registre + 6 adaptateurs + module provenance.ts + ?debug=1 (search-transport.mjs). 7.4: ProviderHealthService + badge source degradee. 7.6: squelettes par provider + snapshots progressifs + transport NDJSON /api/search. 8.1: ProviderAdapter unifie (search enveloppe + channelContent/channelMeta/capabilities) via getProviderAdapter + test de contrat offline.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
-- Phase 5.1 : catalogue video persistant (table `videos`).
|
||||
--
|
||||
-- Volontairement MINCE : pas de table de streams, pas de formats, pas de
|
||||
-- commentaires. Le but est de casser la denormalisation `title`/`thumbnail`
|
||||
-- dupliquee dans `watch_history` et `playlist_items` (phase 5.4), pas de
|
||||
-- reimplementer le catalogue.
|
||||
--
|
||||
-- Migration 100 % additive et reversible : `DROP TABLE videos` suffit a revenir
|
||||
-- en arriere, aucun `ALTER` sur une table existante.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS videos (
|
||||
provider TEXT NOT NULL, -- nom long (convention existante)
|
||||
video_id TEXT NOT NULL,
|
||||
title TEXT,
|
||||
thumbnail TEXT,
|
||||
duration_seconds INTEGER,
|
||||
views INTEGER,
|
||||
published_at TEXT,
|
||||
url TEXT,
|
||||
kind TEXT, -- video | short | live | clip | channel
|
||||
channel_external_id TEXT,
|
||||
channel_name TEXT,
|
||||
channel_avatar_url TEXT,
|
||||
width INTEGER,
|
||||
height INTEGER,
|
||||
raw_json TEXT, -- debug, tronque a 4 Ko
|
||||
captured_at TEXT NOT NULL, -- fraicheur (indicateur UI §9.3)
|
||||
created_at TEXT,
|
||||
PRIMARY KEY (provider, video_id)
|
||||
);
|
||||
|
||||
-- Fraicheur : sert au tri « vu recemment » et a l'indicateur de perinatalite.
|
||||
CREATE INDEX IF NOT EXISTS idx_videos_captured ON videos(captured_at DESC);
|
||||
|
||||
-- Requetes de contenu de chaine par identifiant externe.
|
||||
CREATE INDEX IF NOT EXISTS idx_videos_channel ON videos(provider, channel_external_id);
|
||||
|
||||
-- Phase 5.3 : backfill depuis les tables denormalisees.
|
||||
-- `INSERT OR IGNORE` : ne jamais ecraser une ligne deja observee dans `videos`
|
||||
-- (plus riche que la source de backfill).
|
||||
--
|
||||
-- Le `provider` est NORMALISE en nom long : `watch_history` et `playlist_items`
|
||||
-- conservent la forme recue (courte `yt` ou longue `youtube`) selon l'appelant,
|
||||
-- alors que `videos` est cle par le nom long. Sans ce CASE, ('yt','id') et
|
||||
-- ('youtube','id') creeraient deux lignes et les lectures normalisees
|
||||
-- n'en verraient qu'une.
|
||||
INSERT OR IGNORE INTO videos
|
||||
(provider, video_id, title, thumbnail, captured_at, created_at)
|
||||
SELECT
|
||||
CASE LOWER(provider)
|
||||
WHEN 'yt' THEN 'youtube' WHEN 'dm' THEN 'dailymotion'
|
||||
WHEN 'tw' THEN 'twitch' WHEN 'pt' THEN 'peertube'
|
||||
WHEN 'od' THEN 'odysee' WHEN 'ru' THEN 'rumble'
|
||||
ELSE LOWER(provider) END,
|
||||
video_id, title, thumbnail, last_watched_at, last_watched_at
|
||||
FROM watch_history
|
||||
WHERE video_id IS NOT NULL AND title IS NOT NULL;
|
||||
|
||||
INSERT OR IGNORE INTO videos
|
||||
(provider, video_id, title, thumbnail, captured_at, created_at)
|
||||
SELECT
|
||||
CASE LOWER(provider)
|
||||
WHEN 'yt' THEN 'youtube' WHEN 'dm' THEN 'dailymotion'
|
||||
WHEN 'tw' THEN 'twitch' WHEN 'pt' THEN 'peertube'
|
||||
WHEN 'od' THEN 'odysee' WHEN 'ru' THEN 'rumble'
|
||||
ELSE LOWER(provider) END,
|
||||
video_id, title, thumbnail, added_at, added_at
|
||||
FROM playlist_items
|
||||
WHERE video_id IS NOT NULL AND title IS NOT NULL;
|
||||
@@ -120,6 +120,8 @@ CREATE TABLE IF NOT EXISTS channels (
|
||||
subs_count INTEGER,
|
||||
verified INTEGER DEFAULT 0,
|
||||
last_refreshed_at INTEGER,
|
||||
banner_url TEXT,
|
||||
description TEXT,
|
||||
UNIQUE(provider, external_id)
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user