- YouTube está haciendo pruebas A/B de un método que, en lugar de mostrar anuncios a quienes usan bloqueadores, introduce una demora antes de que empiece el video que parece un buffering falso
- La demora se implementa como backoff en el streaming SABR, y InnerTube responde a la primera solicitud de contenido
/videoplayback indicando que espere el equivalente al 80% de la duración del anuncio
- Los usuarios que no bloquean anuncios casi no perciben la misma demora, porque durante la reproducción del anuncio se va cargando el contenido
- Si se establece
isInlinePlaybackNoAd en true, InnerTube no entrega anuncios y también desaparece el backoff del stream GVS; la lista de filtros predeterminada de uBlock Origin ya incluye una evasión relacionada
- En algunos experimentos, YouTube usa un locker script que bloquea objetos globales como
JSON.stringify para interferir con los hooks de filtros; en Chromium se evita con un hook sobre Object.assign
Dónde aparece el buffering falso
- YouTube ha estado haciendo pruebas A/B en los últimos meses con nuevas medidas anti bloqueadores de anuncios
- Una de las medidas observadas es un buffering falso que solo aparece al inicio del video
- No ocurre a mitad del video
- La duración de la demora equivale al 80% del anuncio que originalmente se habría mostrado
- Incluso usando un bloqueador de anuncios, sigue ahorrándose tiempo frente a ver el anuncio completo
- Ejemplos
- Si hay un anuncio de 15 segundos, se produce un backoff de 12 segundos
- Si hay un anuncio no omitible de 6 segundos junto con uno de 15 segundos, se produce un backoff de 16.8 segundos
El papel de InnerTube, GVS y SABR
- InnerTube es la API interna que usan el cliente web y las apps móviles de YouTube para obtener información y detalles del video
- El endpoint tiene la forma
https://www.youtube.com/youtubei/
/youtubei/v1/player se llama cuando el usuario hace clic en un video para obtener los datos de URL y la URL del stream GVS
- GVS es Google Video Services, que entrega streams de video para YouTube, Google Drive y Google Photos
- Para reproducir video desde GVS, hay que obtener una URL
/videoplayback desde InnerTube o desde la API interna de Drive/Photos
- Las URL de GVS están firmadas y normalmente vencen a las 6 horas, así que no se pueden crear directamente
- Los ISP pueden alojar servidores de Google Global Cache en su propia infraestructura, para servir tráfico de YouTube sin sacarlo de la red del ISP
- GGC solo entrega videos públicos o semipúblicos de YouTube; los videos privados de YouTube y los videos de Drive/Photos siempre se sirven desde centros de datos de Google
- El cliente web de YouTube originalmente hacía streaming indicando los rangos de video necesarios mediante parámetros de consulta en la URL de GVS
- Después YouTube pasó a usar SABR
- SABR significa Server ABR, un protocolo binario propietario de YouTube para bitrate adaptativo del lado del servidor
- Está diseñado para evitar mejor el buffering que formatos públicos como MPEG-DASH
- En vez de enviar datos de video y audio al cliente, el servidor puede responder con un backoff que indica esperar cierto tiempo y volver a intentar
El backoff se aplica por separado del veredicto sobre el bloqueador
- El buffering falso ocurre porque InnerTube entrega un stream GVS que incluye un backoff equivalente al 80% de la duración del anuncio en la primera solicitud
/videoplayback del contenido
- El objetivo no es el stream del anuncio sino el del video de contenido
- Los streams de anuncios y de contenido siguen estando separados
- No se trata de inserción de anuncios del lado del servidor; los experimentos de inserción de anuncios del lado del servidor de YouTube van por separado
- Es probable que el cuadro de diálogo “Experiencing interruptions” se active debido al backoff prolongado de GVS
- Si el usuario está dentro del experimento A/B, este backoff siempre ocurre independientemente de si YouTube considera o no que usa bloqueador de anuncios
- Si no se bloquean los anuncios, el cliente web carga el video de contenido mientras se reproduce el anuncio
- La diferencia perceptible es que el buffering del video de contenido no empieza hasta que el anuncio ha avanzado un 80%
- La afirmación que circula en internet de que YouTube dispara el uso de CPU de usuarios con bloqueador de anuncios hasta dañar la computadora es falsa
- YouTube no usa CPU mientras espera a que expire el backoff
- Incluso si la espera se implementara como spinloop, usar un solo núcleo al máximo durante menos de 30 segundos no dañaría la CPU
Cómo evitar la entrega de anuncios con isInlinePlaybackNoAd
- Para evitar el backoff, no basta con esperar a que termine el anuncio no omitible; hay que hacer que el anuncio no se entregue desde el principio
- Si se establece la propiedad
playbackContext.contentPlaybackContext.isInlinePlaybackNoAd en true dentro de la solicitud player, InnerTube no entrega anuncios
- Si no se entregan anuncios, el stream GVS tampoco incluye backoff
- Se puede crear una regla de filtro que agregue
"isInlinePlaybackNoAd":true cuando el cliente web convierte a string el JSON de la solicitud al servidor
www.youtube.com##+js(trusted-replace-outbound-text, JSON.stringify, 'contentPlaybackContext":{', 'contentPlaybackContext":{"isInlinePlaybackNoAd":true,', condition, 'contentPlaybackContext')
- La propiedad
isInlinePlaybackNoAd está referenciada en el JavaScript del frontend
- Con req2proto se puede extraer la definición protobuf usada en la llamada
/youtubei/v1/player para encontrar esa propiedad
- El cliente web de YouTube se comunica con InnerTube en JSON, pero esta API JSON se genera a partir de definiciones de Protocol Buffers
Limitación: solo es estable en warm navigation
- Este método solo funciona de forma confiable en warm navigation, es decir, cuando la app de página única de YouTube ya está cargada y luego se navega internamente con clics
- En una cold load, cuando se entra directamente a la página watch, el backend de YouTube inserta la respuesta player directamente en la página como
ytInitialPlayerResponse
- Como la solicitud player se genera en el backend, no es posible establecer
isInlinePlaybackNoAd
- Una forma de rodear la cold load es eliminar los datos iniciales para forzar una solicitud player controlable
www.youtube.com##+js(set, ytInitialData, undefined) ! mala idea, ver abajo
www.youtube.com##+js(set, ytInitialPlayerResponse, undefined) ! mala idea!
- Este enfoque tiene demasiados efectos secundarios como para ser práctico
- Rompe por completo los livestreams
- También puede romper otras funciones no probadas
- El reproductor de video parpadea brevemente
- La carga de la página se vuelve más lenta
Locker script y evasión en Chromium
- El filtro funcionaba hasta cierto punto, pero a veces uBlock Origin no lograba hacer hook a
JSON.stringify
- En algunos experimentos A/B, YouTube agrega un locker script al inicio de la etiqueta
<head> del HTML del frontend
- Este script usa
Object.defineProperty para volver non-writable a fetch, JSON, JSON.stringify, JSON.parse, Array, Array.prototype.push, Array.prototype.forEach y otros
- Con eso evita que código posterior cambie el comportamiento usando
Proxy
- uBlock Origin solo puede poner un proxy sobre
JSON.stringify si se ejecuta antes que el locker script
- En Firefox se puede usar un HTML filter para eliminar esa etiqueta
<script> del HTML fuente antes de que la página se procese
- Chromium no soporta la API de extensiones necesaria, así que no se puede hacer de la misma manera
- La evasión actual consiste en hacer hook a
Object.assign en vez de JSON.stringify
Object.assign también es una función que procesa el cuerpo de la solicitud antes del fetch
- No anula el locker script en sí; se parece más a una evasión
- Como el scriptlet de uBO no permite reemplazo de texto en claves de objetos, la lista de filtros inyecta JavaScript
(() => {
const e = {
apply: (e, n, arguments) => {
let t = Reflect.apply(e, n, arguments);
return 3 === arguments.length && t?.body && "string" == typeof t.body && !t.body.includes(`"isInlinePlaybackNoAd":true`) && (t.body = t.body.replace(`"contentPlaybackContext":{`, `"contentPlaybackContext":{"isInlinePlaybackNoAd":true,`)), t
}
};
window.Object.assign = new Proxy(window.Object.assign, e)
})();
- Los mantenedores de uAssets ayudaron con este trabajo de evasión
Material de referencia
Aún no hay comentarios.