# YouTube Pro Premium — Espejo v3

## Correcciones de esta revisión

- **Home visible al instante:** el RecyclerView principal ya no se declara de tamaño fijo dentro del ScrollView, fuerza relayout al recibir datos y revela el contenido desde el primer resultado, sin tener que salir y volver.
- **Pestañas Todos / Videos / Mixes / En vivo / Podcasts:** cada filtro conserva su última lista en memoria para volver a mostrarla inmediatamente mientras se actualiza; las respuestas tardías de otra pestaña no reemplazan la actual.
- **Miniaturas:** Coil renderiza con el mismo ImageLoader que administra el caché de imágenes, evitando inconsistencias entre caché y pantalla.
- **Descarga desde tarjetas:** los accesos de feed, búsquedas, listas, historial y tarjetas ya no envían DownloadData vacío; abren el selector real de video/audio/subtítulos.
- **Descarga por defecto útil:** si nunca se eligió formato antes, el diálogo selecciona automáticamente el mejor video y audio disponibles. Para solo audio se puede escoger “Sin video”.
- **Descargas sin Content-Length:** ya no se marcan como completas con tamaño -1; se leen hasta EOF y luego se guarda el tamaño real.
- **Descargas visibles mientras la pantalla está abierta:** la pestaña refresca su snapshot de Room al reanudarse, conectarse al servicio, recibir un elemento nuevo y completar una descarga.
- **Metadatos de descarga en segundo plano:** miniatura/SponsorBlock ya no bloquean el inicio de los archivos de audio/video.
- **Compatibilidad de audio:** si el backend cambia/omite el locale de la pista al regenerar la URL, se conserva la selección por calidad/formato.
- **Reproducción continua más rápida:** se mantiene una sola cola/autoplay, se aumenta la precarga Media3 del siguiente a ~15 s y se reintenta brevemente si la cola de playlist todavía se está poblando.
- **Aspecto más cercano a YouTube:** chips planos compactos sin check visible, miniaturas principales más a borde, feed principal sin encabezado extra entre chips y videos, logo rojo tipo reproductor en la barra superior y etiquetas de navegación visibles por defecto.

## Se conserva de v2

- Listas de reproducción y base de datos existentes.
- Descargas locales y reproducción offline.
- Segundo plano / notificación / mini reproductor.
- Caché de API y caché multimedia en disco.
- Carruseles del reproductor.
- Repetir uno, repetir todo, aleatorio, siguiente/anterior y autoplay.

## Validación

- Todos los XML del proyecto fueron parseados: 0 errores estructurales.
- El Gradle completo no puede ejecutarse en este entorno porque no puede descargar `gradle-9.4.1-bin.zip`; la compilación final debe ejecutarse en el PC con `./gradlew.bat clean assembleDebug`.

---

# YouTube Pro Premium — cambios modo espejo (proyecto nuevo)

Este trabajo se realizó **sobre `youtube pro premium.zip`**, conservando la base y las personalizaciones que ya estaban en ese proyecto.

## Objetivos preservados

- Listas de reproducción y biblioteca existentes.
- Descargas existentes y su base de datos.
- Reproducción de audio y video descargado sin conexión.
- Reproductor de video y reproductor/minirreproductor de audio.
- Historial, suscripciones y carouseles existentes bajo el reproductor.
- Inicio de reproducción desde 0, tal como estaba personalizado en este proyecto.

## 1. Caché para reducir llamadas y acelerar navegación/reproducción

Se añadieron tres capas complementarias:

1. **Caché de miniaturas**: se conserva la caché de Coil que ya tenía el proyecto.
2. **Caché de respuestas API** (`ApiResponseCache`):
   - memoria: hasta 80 respuestas recientes;
   - disco: LRU aproximado de 32 MB en `cacheDir/api_response_cache`;
   - streams/búsquedas/tendencias/canales/playlists/sugerencias/SponsorBlock/DeArrow;
   - TTL corto para datos frescos y una ventana stale mayor como respaldo ante fallos temporales;
   - el backend/instancia forma parte de la clave para no mezclar respuestas de servidores distintos;
   - un fallo al escribir caché nunca invalida una respuesta de red que sí llegó correctamente.
3. **Caché de bytes de reproducción Media3** (`PlaybackCache`):
   - hasta 256 MB LRU en `cacheDir/playback_media_cache`;
   - reutiliza fragmentos de audio/video ya cargados por ExoPlayer;
   - ayuda al volver a reproducir contenido y reduce red cuando los mismos rangos siguen en caché.

> Importante: la caché acelera, pero Android puede desalojarla. **Descargas** sigue siendo la fuente garantizada para escuchar/ver sin datos.

## 2. Descargas verdaderamente offline

- Si un video se abre desde Descargas, se respeta `isOffline=true` aun cuando el teléfono tenga Internet.
- Si se intenta abrir un video sin red y existe una descarga local, la navegación cambia automáticamente al reproductor offline.
- Al pasar al siguiente descargado ya no se solicita `getStreams()` por Internet.
- El siguiente descargado usa una fuente combinada de **video + audio + subtítulo**, en vez de tomar solamente el primer archivo encontrado.
- Las transiciones offline actualizan ID, miniatura/metadatos, cola, subtítulos, historial y SponsorBlock del nuevo elemento.

## 3. Segundo plano y notificación

- `OnlinePlayerService` y `OfflinePlayerService` usan `android:stopWithTask="false"`.
- Quitar la interfaz de Recientes ya no ordena destruir el servicio de reproducción.
- El servicio heredado `OnClearFromRecentService` ya no detiene el audio/video ni cancela la notificación al quitar la interfaz de Recientes.
- Se conserva `MediaLibraryService`, foreground media playback, audio focus y WakeMode de Media3.
- Los `MediaItem` mantienen título, canal y `artworkUri`, por lo que la notificación/minirreproductor pueden conservar la miniatura.

## 4. Reproducción continua y precarga

- Buffer ajustado a 10 s mínimo / 60 s máximo con 750 ms para inicio y 2 s después de rebuffer.
- Media3 precarga aproximadamente 8 s del siguiente elemento de playlist.
- El servicio obtiene y prepara solamente el siguiente elemento inmediato, en lugar de resolver una lista larga completa antes de empezar.
- Al terminar un elemento, el `Streams` precargado se promueve a actual sin repetir la misma llamada.
- La precarga del próximo elemento comienza inmediatamente en la transición y ya no espera a SponsorBlock.
- **Siguiente / autoplay / notificación / cola** quedan alineados con `PlayingQueue.getNext()`.
- Si el siguiente ya está preparado en ExoPlayer, el servicio salta a él directamente.
- Se corrigió el caso donde el elemento precargado podía llevar el ID/subtítulos del video anterior.
- La UI actualiza su `videoId` en la transición automática, evitando título/carruseles/acciones asociados al video anterior.
- Repetir uno y repetir todo quedan sincronizados entre cola y ExoPlayer.

## 5. Home estilo YouTube con pestañas reales

Se añadió la fila fija de chips:

- **Todos**
- **Videos**
- **Mixes**
- **En vivo**
- **Podcasts**

Cada pestaña genera su propia consulta/categoría y limpia el contenido de la pestaña anterior antes de cargar. Esto corrige el problema donde cambiar de chip parecía mostrar la misma respuesta.

- **Todos**: descubrimiento general apoyado en historial de búsquedas, con fallback de tendencias.
- **Videos**: consulta específica de videos.
- **Mixes**: búsqueda de `music_videos` / mixes.
- **En vivo**: búsqueda específica `live now livestream`, filtrada a emisiones en vivo; fallback LIVE.
- **Podcasts**: consulta específica `podcast interview`; fallback PODCASTS.
- Los filtros aceptan correctamente `StreamItem.TYPE_STREAM` además de `video`.
- Las consultas se mantienen estables para que volver a una pestaña pueda reutilizar el caché en vez de producir una clave aleatoria cada vez.
- Al cambiar a una categoría se ocultan temporalmente las filas personales que solo pertenecen a **Todos**; al volver, historial/listas/suscripciones siguen disponibles.
- Durante categorías distintas de Todos no se vuelven a cargar en paralelo las filas personales que están ocultas.
- Feed principal en **una columna de ancho completo**, más cercano a YouTube móvil.
- Historial y listas se conservan como carouseles horizontales.
- Miniaturas usan `centerCrop`.

## 6. Carouseles bajo el reproductor

Se conservan y mejoran:

- Similares
- Relacionados
- Tendencias
- Últimos del canal
- Recomendaciones

Cambios:

- también aparecen durante reproducción desde playlist;
- Últimos del canal intenta cargar realmente el canal actual usando caché;
- Tendencias consulta contenido de tendencia usando caché y tiene fallback local;
- ya no se descartan automáticamente videos largos, mixes o podcasts solo por superar 15 minutos;
- siguen excluyéndose Shorts y directos del autoplay normal para evitar saltar a un live infinito;
- miniaturas de los carouseles se precargan mediante la caché de imágenes;
- las filas vacías se ocultan;
- al cambiar de video se limpian/cancelan cargas anteriores para que una respuesta tardía no pinte carouseles del video anterior.

## 7. Minirreproductor

- Miniatura 16:9 con `centerCrop` y sin relleno innecesario.
- Título + canal visibles.
- Controles a la derecha.
- La cola/siguiente/anterior usan el mismo camino del MediaSession para aprovechar elementos ya preparados.

## 8. Llamadas lentas / errores

- Timeout de streams ampliado a 10 s.
- Un timeout aislado ya no activa un bloqueo global de 60 s.
- Se eliminó el comportamiento que podía saltar a un video arbitrario del historial si fallaba la carga.
- El breaker queda reservado a rate limiting explícito.
- SponsorBlock mantiene un solo monitor periódico por servicio, evitando acumular loops de 100 ms por cada video.

## Validaciones realizadas en este entorno

- **395 archivos XML/Manifest analizados: 0 errores XML.**
- Los Kotlin modificados fueron pasados por el parser de `kotlinc`: **0 errores de sintaxis/redeclaración** en el filtrado sintáctico.
- Se verificó que no queden referencias antiguas del Home (`homeViewModel.trending` / `loadMoreTrending`).

### Limitación de compilación aquí

No se pudo completar `gradlew` en este entorno porque el wrapper intenta descargar Gradle 9.4.1 desde `services.gradle.org` y este entorno no tiene salida de red para esa descarga. Por eso el APK final debe compilarse en tu PC, donde ya tienes Android SDK/Gradle disponibles.

## Compilar desde VS Code / PowerShell

Desde la raíz del proyecto:

```powershell
.\gradlew.bat assembleDebug
```

APK generado:

```text
app\build\outputs\apk\debug\app-debug.apk
```

Para compilar e instalar directamente en un Android conectado por ADB:

```powershell
.\gradlew.bat installDebug
```

## Prueba recomendada antes de reemplazar tu APK habitual

1. Instalar el debug.
2. Verificar Todos / Videos / Mixes / En vivo / Podcasts y comprobar que cambian de contenido.
3. Abrir un video y dejar que avance automáticamente al siguiente.
4. Probar Siguiente/Anterior desde reproductor y desde notificación.
5. Minimizar, apagar pantalla y quitar la app de Recientes mientras reproduce.
6. Descargar un video con audio, poner modo avión y reproducirlo desde Descargas.
7. En modo avión, pasar al siguiente descargado.
8. Volver a un video recién reproducido y comparar tiempo de arranque/carga.
9. Probar una playlist completa y confirmar que conserva orden y continuidad.
10. Confirmar que Similares/Relacionados/Tendencias/Últimos/Recomendaciones cambian con el nuevo video.

## v4 — correcciones de reproducción offline y continuidad

- Se evita abrir descargas vacías o parciales en ExoPlayer. Los registros huérfanos sin pista de video ya no aparecen como videos descargados.
- El reproductor offline valida que exista un archivo local real y con bytes antes de construir el `MediaSource`; si no es reproducible, falla de forma controlada en vez de destruir el servicio.
- Al cambiar de reproducción online a offline (o viceversa) se detiene primero el servicio anterior para impedir que dos servicios compartan/modifiquen la misma cola simultáneamente.
- Se protege `PlayerFragment.onDestroy()` para que no acceda a un binding ya destruido al reemplazar el reproductor.
- Se eliminó una carrera de autoplay: con el contador desactivado, `STATE_ENDED` ya no provoca dos órdenes de “siguiente” simultáneas desde la UI y el servicio.
- El siguiente tema online se precarga a nivel de respuesta `Streams` y se promueve al terminar la canción. Así se evita una segunda llamada a la API y se reconstruye la fuente por la ruta normal/probada del reproductor, en lugar de insertar un `MediaItem` crudo que podía fallar al cambiar de canción.
- Las configuraciones de subtítulos ignoran entradas sin URL válida para que una pista de subtítulos incompleta no rompa la preparación del siguiente contenido.
