Contexto: yt-extract — API quirks + deck TweetDeck (operativo, no re-derivar)
ENDPOINT videoTrainability (el observatorio): GET https://www.googleapis.com/youtube/v3/videoTrainability?id=VIDEO&key=KEY - Funciona con SOLO API key (sin OAuth). - 1 video por llamada (NO acepta lote: si mandas id="a,b" devuelve el string concatenado con permitted ["None"], sin resultados por video). ~1 unidad/call. - permitted: ["None"] (opt-out, DEFAULT) | ["All"] | [lista de parties]. - Todo el trending MX + canales probados => OUT. El opt-in es raro; esa es la señal.RESOLVER CANAL (yt/live.py resolve_channel_id): - forHandle NO es confiable (falla con handles reales ej @elchapucero, @ElFinancieroTV). - Usar fallback: forHandle -> search.list(type=channel). IDs "UC..." pasan directo. - CUIDADO: un customUrl puede apuntar a un canal VIEJO del mismo nombre. Ej: @aristeguionline -> canal con 5 videos de 2015-2017. El activo es otro ID. => siempre verificar edad del último video (stale flag).COSTOS (quota 10,000/dia): search.list = 100 unidades (caro). videos.list / channels.list / playlistItems / videoTrainability ~= 1 unidad cada uno. Patrón barato por canal (~3 uds + N trainability): channels.list(contentDetails) -> playlistItems(uploads) -> videos.list -> N x trainability.DECK (yt/deck.py): feeds.json -> build_deck -> print_deck (terminal) + deck.html (TweetDeck). feeds.json: {trending:{region,max}, per_channel, stale_days, channels:[ids/nombres]}.HALLAZGO BUG ORGANICO: la señal de "repetibilidad" del dataset Kaggle (2018) esa NIVEL CANAL, no video (15 reentradas de 33k). En vivo, lo análogo es: - "stale channel" (canal sin actividad reciente) - opt-in ALL vs OUT por canal.