Scrapers de Nuvio¶
Kino puede instalar los scrapers de un repositorio de proveedores de Nuvio sin que nadie escriba un plugin de Kino: convierte el scraper elegido en un plugin de Kino en el dispositivo, al instalarlo. Esta página cuenta cómo los agrega la gente, qué hace la conversión y hasta dónde llega. No necesitas nada de esto para escribir tu propio plugin; te sirve si mantienes un repositorio de Nuvio, o si quieres saber por qué un plugin convertido se porta distinto de uno escrito a mano.
Cómo los agrega la gente¶
- En Kino, Ajustes ▸ Plugins (en el televisor también se llega con el botón "Plugins" de Inicio),
"Agregar plugin", y se escribe la dirección del repositorio,
owner/repo, igual que para un plugin de Kino. La dirección pegada también puede ser una URLgithub.com/owner/repo, una/tree/<ref>/<carpeta>, o una URLraw.githubusercontent.com/owner/repo/<ref>/.../manifest.json(tambiéngithub.com/.../blob/...o/raw/...hacia un archivo.json): Kino toma la carpeta donde está ese archivo. Cualquier otro archivo se rechaza. - Kino lee
manifest.jsonen la raíz del repositorio. Si está en el formato propio de Nuvio (un objeto con un arregloscrapers), la dirección es un repositorio de Nuvio; si no, Kino la trata como un plugin de Kino (kino-plugin.json). Si la rama principal tiene unmanifest.jsonque no está en ese formato (algunos repositorios guardan ahí una plantilla), Kino prueba también la ramamainy luego lamaster. - Un selector a pantalla completa lista todos los scrapers del manifiesto, con su logo, tipos, idioma, versión y autor, y filtra por tipo (Todas, Películas, Series, Anime) y por idioma. Cada tarjeta dice "Agregar", "Instalado" o "No disponible" (un scraper que el manifiesto desactiva, o desactiva en Android) o "No compatible" (un scraper de fuentes P2P, con o sin debrid: "Kino no admite scrapers de torrents, ni siquiera con debrid", desde Kino 0.9.51). Un repositorio sin nada instalable dice "Este repositorio de Nuvio no tiene scrapers instalables en Android".
- "Agregar" convierte ese scraper y abre la hoja de consentimiento de siempre; después de "Instalar" el selector sigue abierto para agregar otro. Cada scraper queda como su propio plugin, listado en Ajustes ▸ Plugins como cualquier otro.
El selector avisa que los scrapers se convierten desde Nuvio y que su código original tiene licencia GPL-3.0; la descripción del plugin dice lo mismo ("Convertido desde el plugin de Nuvio …; código original GPL-3.0").
Qué arma la conversión¶
El JavaScript del scraper se conserva byte por byte, envuelto con una capa de compatibilidad y un pequeño adaptador, y se instala con un manifiesto generado:
apiVersion6 (4 antes de Kino 0.9.51),version1.<revisión del convertidor>.0(hoy1.4.0, mira Actualizaciones), capacidadessearch,episodes,resolveydownload.- Los
settingsdel plugin, cuando el scraper tieneonSettings(Kino 0.9.51): ver Ajustes del scraper. - Los tipos que sirve el scraper salen de su
supportedTypes, con las formas de escribirlos más comunes unificadas:movie,movies,film,filmsson películas;tv,series,show,showsson series;animees anime (sin importar mayúsculas). Un scraper que declara["movie", "series"]también sirve series. hosts: se detectan solos en el código del scraper (y en una lista remota de dominios que nombre, si la tiene), siempre conapi.themoviedb.orgde primero. Un manifiesto admite máximo 20: si hay más, van primero las direcciones que parecen del propio sitio del scraper, y la descripción avisa "se detectaron más de 20 dominios; algunos quedaron fuera". Un scraper cuyo código no nombra ningún dominio no se puede convertir ("No encontré ningún dominio en el código de …")."streamHosts": "any": sus películas y episodios se pueden reproducir desde cualquier servidor público (la regla)."fetchHosts": "any": sukino.fetchpuede llegar a cualquier servidor público, sin una pregunta por cada host. Los nombres locales, las direcciones privadas, de loopback y link-local, y los nombres que resuelven dentro de la red de la casa siguen rechazados, en cada salto de redirección. Este campo se respeta solo en estas instalaciones convertidas; en un plugin escrito a mano no hace nada (por qué).
Por eso la hoja de consentimiento de un scraper convertido muestra, en rojo, "Puede reproducir video desde cualquier servidor que indique" y "Puede conectarse a cualquier servidor de internet", además de "Puede descargar videos para verlos sin conexión". Nada de él corre antes de que la persona acepte.
Cómo se porta un scraper convertido¶
Los scrapers de Nuvio no tienen catálogo ni búsqueda por texto: solo responden "streams para este id de TMDB". Así que el adaptador trabaja desde TMDB:
- Sin filas de Inicio. El plugin aparece en los resultados de búsqueda, nunca como filas de Inicio.
searchcon id de TMDB responde un ítem, para el id de TMDB que Kino está buscando, con el póster, el fondo, el año y la sinopsis de TMDB cuando TMDB responde a tiempo. Un scraper solo responde por los tipos que declara su manifiesto: uno sin películas (o sin series) no se ofrece como fuente para ellas.searchsin id de TMDB (una búsqueda escrita, por ejemplo en el televisor) le pregunta el texto a la búsqueda de TMDB (/search/multi, o solo películas o solo series cuando es lo único que sirve el scraper o Kino pidió una serie) y responde hasta 10 coincidencias, ordenadas por qué tan parecido es su título a lo buscado y, si empatan, por popularidad en TMDB. El scraper no se llama hasta que la persona escoge una. Si TMDB falla, la búsqueda no responde nada, en vez de un error.episodeslista las temporadas y capítulos desde TMDB, sin la temporada 0 (especiales) y sin los capítulos que todavía no se han emitido.resolvellama algetStreamsdel scraper exactamente como lo hace Nuvio y se queda solo con las copiashttp/https(Kino no tiene cliente BitTorrent). Desde Kino 0.9.51 cada copia reproducible se ofrece: la primera se reproduce y hasta 8 más van como copias alternativas con etiqueta en el menú Servidor, en este orden: archivos de video antes que páginas de embed, y dentro de eso primero 1080p, luego 720p, luego cualquier otra y 2160p/4K de último (la mayoría de celulares y televisores de acá no decodifican 4K HEVC). La etiqueta es la calidad con el nombre del servidor ("1080p · Servidor X"), así que dos copias de la misma calidad se distinguen. Una dirección al estilo Kodi,url|User-Agent=…&Referer=…, se parte: lo que va después de|se vuelve encabezados de la petición. Cuando no queda nada, la persona lee por qué: "sin resultados", "solo enlaces P2P" o "error del scraper: …" con lo que el scraper dejó en el log.- Las descargas funcionan en celulares como en cualquier plugin con
download(Descargas), con las mismas reglas de hosts que al reproducir.
Límites que cambian frente a un plugin escrito a mano¶
| Qué | Scraper de Nuvio convertido | Plugin escrito a mano |
|---|---|---|
Tiempo de resolve |
75 s (el reproductor muestra la espera en pantalla) | 20 s |
Peticiones de kino.fetch por llamada |
250 | 60 |
Hosts a los que llega kino.fetch |
cualquier host público (fetchHosts) |
hosts, servidores escritos por la persona y hosts aprobados uno por uno |
| Dónde puede estar el video | cualquier host público (streamHosts) |
hosts, salvo streamHosts o el permiso amplio de video |
Todo lo demás -- memoria, tamaños de cuerpo, los rechazos de la red de la casa, los otros límites de tiempo -- es igual.
El entorno que recibe un scraper¶
La capa de compatibilidad reconstruye, encima de kino, lo que espera un scraper de Nuvio:
module/exports/require de CommonJS, un fetch con forma de navegador, axios, process.env,
global, setTimeout/clearTimeout, AbortController/AbortSignal, require("crypto") (el de
Node, en lo que usan los scrapers), la API Web Crypto del navegador (crypto.subtle,
crypto.getRandomValues, crypto.randomUUID), TMDB_API_KEY, y los cheerio-without-node-native,
crypto-js y Buffer reales, incluidos solo cuando el código del scraper los necesita.
Desde Kino 0.9.51 (compatibilidad de Nuvio v2) también:
- Los globales de Nuvio:
window,selfySCRAPER_ID;getStreamsse encuentra enmodule.exports,exports.getStreams,defaulto como global; el código async compilado con regenerator funciona, y unrequiredentro de untryo uniftambién. - Un subconjunto de Node:
path,url,util,events,querystring,timers,bufferyhttp/https/undici(sobrekino.fetch), mássetInterval,setImmediateyqueueMicrotask.fs,child_process,net,os,streamy parecidos cargan como módulos vacíos: todo miembro se lee comoundefined, así que la propia revisión del scraper cae afetch, y llamarlo igual es unTypeError. - Scrapers de varios archivos: los archivos hermanos que pide con
requirese leen del mismo repositorio y por el mismo camino (ningún destino nuevo). Máximo 16 archivos y 1 MiB en total;../dentro del repositorio sirve, una ruta que se sale de él (también codificada con%) se rechaza. Un hermano que falla al cargar se reintenta. - Tiempos: 30 s por petición. Un temporizador que el scraper deja corriendo se borra apenas
getStreamstermina, así que la llamada no lo espera.
Un require de algo que no está en esa lista ni es un archivo hermano falla con "Nuvio compat:
require('…') was not bundled with this scraper".
La clave de TMDB de Kino nunca se escribe en el código del plugin convertido: TMDB_API_KEY tiene
una marca fija, y Kino pone la clave real en su lugar solo en peticiones https a
api.themoviedb.org (el mismo mecanismo de secretos sellados que usan las
claves de un plugin). Una petición que lleve la marca a cualquier otro lado se rechaza antes de salir,
y la clave se borra de toda respuesta, error y log que el plugin vea.
Esa marca es solo para scrapers convertidos. Un plugin que escribes tú le pregunta a TMDB por medio de
kino.tmdb (Kino 0.9.53): la llave de Kino detrás de su caché y sus límites, la de la persona solo
cuando la de Kino falla, y ninguna llave en tu código.
Todo eso existe solo dentro de un scraper convertido. Un plugin que escribes tú recibe el motor de Kino tal cual: ninguno de esos globales (Límites y trampas del motor). Lo mismo pasa con el arreglo de los ayudantes async de la trampa del rechazo.
Ajustes del scraper¶
Desde Kino 0.9.51, el onSettings de un scraper se vuelve el formulario de ajustes
del plugin convertido, en su propia pestaña de Ajustes, y lo que la persona escoge se sincroniza entre
sus aparatos como cualquier ajuste de plugin. El scraper lo recibe en SCRAPER_SETTINGS, con sus
propias llaves. Si el formulario del scraper no cabe en los límites de Kino, la hoja de consentimiento
avisa "Algunos ajustes del scraper no caben y quedaron fuera". Un ajuste que pide una cuenta de debrid
hace que el scraper se rechace (ver arriba).
Qué se rechaza¶
Los scrapers de fuentes P2P, con o sin debrid (Kino 0.9.51): Kino no maneja torrents, así que su tarjeta dice "No compatible" y "Kino no admite scrapers de torrents, ni siquiera con debrid"; se juzga igual que un addon P2P de Stremio. Uno instalado antes se apaga en su siguiente revisión de actualizaciones.
Actualizaciones¶
La versión de un plugin convertido es 1.<revisión del convertidor>.0: solo cambia cuando cambia el
convertidor de Kino (hoy 1.4.0), porque los campos version de Nuvio no son confiables. Para
encontrar actualizaciones Kino no compara versiones: "Buscar actualizaciones" (y la revisión en
segundo plano) vuelve a hacer toda la conversión desde el repositorio y compara el código y el
manifiesto que salen con los instalados, así que un cambio en el scraper se encuentra aunque la
versión siga igual. Un cambio que solo toca
el código se instala solo; uno que agrega hosts o un permiso espera la aprobación de la persona, como
cualquier actualización. Un plugin convertido por un Kino más viejo pide
aprobación una vez por lo que agregan las conversiones nuevas (fetchHosts, descargas).
Para quienes mantienen un repositorio de Nuvio¶
- Deja
manifest.jsonen la raíz de la rama principal, con entradasscrapers[]que tenganid,name,filenamee idealmentesupportedTypes,contentLanguage,version,author,descriptionylogo: el selector los muestra y filtra por ellos. - Usa
enabled: falseodisabledPlatforms: ["android"]para los scrapers que no se deben ofrecer. - Devuelve direcciones
http/httpsde video directo cuando las tengas: van antes que las páginas de embed. Ponlequalityynamea cada copia, que son su etiqueta en el menú Servidor. - Escribe la dirección del propio sitio como un literal en el código (o en una lista remota de dominios): así es como Kino encuentra los hosts que va a declarar.