|
2 | 2 |
|
3 | 3 |  |
4 | 4 |
|
| 5 | +Exporta el historial de **Now Playing / Está sonando** (Android System Intelligence, ASI) de dispositivos Google Pixel a **CSV**, e incorpora una función para **descargar las canciones** listadas en ese historial (vía `yt-dlp`) al almacenamiento de la app. Pensada y construida como proyecto de **Aprendizaje Basado en Proyectos (PBL)**.  |
5 | 6 |
|
6 | | -Exporta el historial de **Now Playing / Está sonando** (Android System Intelligence) de los dispositivos Google Pixel a **CSV** directamente desde Android. |
7 | | -Incluye **deduplicación opcional** (por intervalos de tiempo) para eliminar líneas repetidas y un botón para **compartir** el CSV generado. |
8 | | - |
9 | | -> **Requiere root.** La base de datos de ASI es privada del sistema y no es accesible sin privilegios elevados (root). Por tanto asegurate de concederle permisos de superusuario en Magisk, KSU o aPatch a la aplicación antes de usarla, y reinicia el móvil, de lo contrario te dará error. |
| 7 | +> **⚠️ Requiere root.** La base de datos de ASI es privada del sistema. Concede permisos de superusuario (Magisk / KernelSU / aPatch) antes de usarla. Para explorar los ficheros resultantes puede hacer falta un gestor con root. |
10 | 8 |
|
11 | 9 | --- |
12 | 10 |
|
13 | 11 | ## Características |
14 | | -- ✅ Exportación a **CSV** en `Descargas` (vía MediaStore). |
15 | | -- ✅ **Deduplicación** por ventanas de tiempo (p. ej., 10 min). |
16 | | -- ✅ **Compartir** el CSV desde la app. |
17 | | -- ✅ UI Material minimalista, modo oscuro. |
18 | | -- ✅ Reutiliza scripts Python (Chaquopy) para la lógica de export/dedupe. |
| 12 | + |
| 13 | +* ✅ Exportación a **CSV** del historial “Está Sonando”. |
| 14 | +* ✅ **Deduplicación** inteligente (ventanas de tiempo) para limpiar duplicados y “falsos repetidos”. |
| 15 | +* ✅ **Descarga de canciones** desde el CSV con `yt-dlp` al directorio privado de la app (no necesita permisos de almacenamiento). |
| 16 | +* ✅ UI minimalista con feedback de progreso en tiempo real.  |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## Rutas y formatos |
| 21 | + |
| 22 | +* **DB de ASI** (ejemplos habituales): |
| 23 | + |
| 24 | + ``` |
| 25 | + /data/data/com.google.android.as/databases/history_db |
| 26 | + /data/user_de/0/com.google.android.as/databases/history_db |
| 27 | + /data/data/com.google.android.as.oss/databases/history_db |
| 28 | + ``` |
| 29 | +* **Salida CSV**: en `Descargas` (MediaStore) con nombre `now_playing_export_YYYYMMDD_HHMMSS[_dedup].csv`. |
| 30 | +* **Descargas de audio** (con `yt-dlp`): |
| 31 | + |
| 32 | + ``` |
| 33 | + /Android/data/com.d4vram.nowplayingexporterpy/files/Music/NPEpy_download_songs/ |
| 34 | + ``` |
| 35 | + |
| 36 | + Formato típico: `.webm` (sin post-procesado FFmpeg). Para escucharlas en tu reproductor, **mueve/copialas** a `/sdcard/Music/`.  |
19 | 37 |
|
20 | 38 | --- |
21 | 39 |
|
22 | 40 | ## Cómo funciona (resumen técnico) |
23 | | -1. **Root** (libsu) copia la base de datos privada de ASI (`history_db`) a la sandbox de la app. |
24 | | - - Rutas candidatas (ejemplos): |
25 | | - ``` |
26 | | - /data/data/com.google.android.as/databases/history_db |
27 | | - /data/user_de/0/com.google.android.as/databases/history_db |
28 | | - /data/data/com.google.android.as.oss/databases/history_db |
29 | | - ... |
30 | | - ``` |
31 | | -2. **Chaquopy** ejecuta `np_export.py` para leer SQLite y generar el **CSV** temporal. |
32 | | -3. (Opcional) `np_dedupe.py` aplica **deduplicación** por tiempo (**recomendada** para evitar múltiples líneas repetidas que salen incluso sin corresponderse a las veces que fueron reproducidas, por el momento desconozco cual es el error por el que ocurre esto). |
33 | | -4. La app mueve el CSV final a **Descargas** con nombre `now_playing_export_YYYYMMDD_HHMMSS[_dedup].csv`. |
34 | | -5. Botón/acción para **compartir** el CSV (intent estándar). |
| 41 | + |
| 42 | +1. **Root (libsu)** copia `history_db` de ASI a la sandbox de la app. |
| 43 | +2. **Chaquopy (Python)** ejecuta `np_export.py` para leer SQLite y generar el **CSV** temporal. |
| 44 | +3. (Opcional) `np_dedupe.py` aplica **deduplicación** por ventana temporal. |
| 45 | +4. La app guarda el CSV final en **Descargas** y ofrece **compartir** por intent estándar. |
| 46 | +5. Con el CSV listo, **`yt-dlp`** busca y descarga los audios a la carpeta privada de la app.  |
35 | 47 |
|
36 | 48 | --- |
37 | 49 |
|
38 | 50 | ## Requisitos |
39 | | -- Probado en Andorid 16 en Pixel usando KernelSU Next con ASI → ✅ funciona. |
40 | | -- Esperado (no verificado): Android 12–15 en Pixel con ASI debería funcionar (las rutas de la DB suelen ser alguna de estas, previamente mencionadas en el punto 1: |
41 | 51 |
|
42 | | - /data/data/com.google.android.as/databases/history_db, |
43 | | - /data/user_de/0/com.google.android.as/databases/history_db, |
44 | | - /data/data/com.google.android.as.oss/databases/history_db), |
| 52 | +* **Root** (Magisk / KernelSU Next / aPatch). |
| 53 | +* **ASI** instalado (Android System Intelligence). |
| 54 | +* Probado en **Android 16** (Pixel con KernelSU Next). Se espera compatibilidad Android **12–15** en Pixel (no garantizada).  |
| 55 | + |
| 56 | +--- |
| 57 | + |
| 58 | +## Lecciones aprendidas (problemas → soluciones) |
| 59 | + |
| 60 | +1. **FFmpeg & `yt-dlp`**: Chaquopy no aporta FFmpeg vía pip. `yt-dlp` puede bajar audio nativo (`.webm`) **sin FFmpeg**, así que se eliminó la falsa dependencia y se configuró “best audio”. |
| 61 | +2. **Progreso en tiempo real**: se añadió una interfaz `PythonCallback` desde Kotlin para recibir logs/estado del script Python y mostrarlos en la UI. |
| 62 | +3. **DNS / red intermitente**: además de declarar `android.permission.INTERNET`, se implementaron **reintentos** con pausas y “pausa larga” tras N descargas. |
| 63 | +4. **Scoped Storage (API 29+)**: escribir en `Music` público da `Operation not permitted`. Solución: **usar almacenamiento privado de la app** en `/Android/data/.../files/` (no requiere permisos en Android 10+).  |
| 64 | + |
| 65 | +--- |
| 66 | + |
| 67 | +## Uso |
| 68 | + |
| 69 | +1. **Instala** el APK. |
| 70 | +2. **Concede root** cuando te lo pida. |
| 71 | +3. Pulsa **Exportar** para generar el CSV del historial. |
| 72 | +4. (Opcional, recomendado) Activa **Deduplicar**. |
| 73 | +5. Pulsa **Descargar canciones** para poblar `NPEpy_download_songs/`.  |
| 74 | + |
| 75 | +> **Tip importante para buena legibilidad**: abrir el CSV en hojas de cálculo sin romper columnas |
| 76 | +
|
| 77 | + |
| 78 | + > Para que no te “trocee” los títulos por espacios, toca exactamente esto: |
| 79 | + |
| 80 | + En Opciones de separador |
| 81 | + |
| 82 | + ✅ Coma |
45 | 83 |
|
46 | | - pero no garantizado. |
| 84 | + ⛔ Espacio → DESMARCA |
| 85 | + |
| 86 | + ⛔ Punto y coma → DESMARCA |
47 | 87 |
|
48 | | -- **Root** (Magisk, KernelSU/KSU Next, aPatch) y permisos a la apk. |
49 | | -- Android System Intelligence (o equivalente) instalado. |
| 88 | + ⛔ Tabulador → DESMARCA (déjalo solo si tu archivo lleva tabs) |
50 | 89 |
|
| 90 | + En Delimitador de cadena → elige " (comillas dobles). |
| 91 | + |
| 92 | + Conjunto de caracteres → Unicode (UTF-8) (como ya tienes). |
| 93 | + |
| 94 | + (Recomendado) En la vista previa, haz clic en el encabezado de la columna timestamp_iso (y cualquier otra de tiempo) y en Tipo de columna pon Texto para que no te lo reinterprete como fecha rara. |
| 95 | + |
| 96 | + Luego pulsa Aceptar. |
| 97 | + Con eso la vista previa debe pasar de palabras sueltas en mil columnas a columnas limpias: artist | title | timestamp_iso | ... |
| 98 | + |
| 99 | + 👉 Si aun así ves todo roto, abre el archivo en un editor y mira el separador real: |
| 100 | + |
| 101 | + Si ves ; entre campos, importa marcando Punto y coma (y desmarcando lo demás). |
| 102 | + |
| 103 | + Si ves ,, usa Coma como arriba. |
| 104 | + |
| 105 | +--- |
| 106 | + |
| 107 | +## Arquitectura y tecnologías |
| 108 | + |
| 109 | +* **Kotlin (Android)**: UI + lógica principal. |
| 110 | +* **Chaquopy (Python)**: ejecución de scripts (`np_export.py`, `np_dedupe.py`, `np_download.py`). |
| 111 | +* **`yt-dlp`**: búsqueda/descarga de audio. |
| 112 | +* **`libsu`**: operaciones root. |
| 113 | +* **SQLite**: base de datos de ASI. |
| 114 | +* **Scoped Storage**: políticas de acceso en Android 10+.  |
51 | 115 |
|
52 | 116 | --- |
53 | 117 |
|
54 | 118 | ## Compilación |
55 | | -### Opción Android Studio |
56 | | -- Abrir el proyecto. |
57 | | -- **Build > Make Project** o **Run**. |
58 | 119 |
|
59 | | -### Opción CLI |
| 120 | +### Android Studio |
| 121 | + |
| 122 | +* Abre el proyecto y **Sync**. |
| 123 | +* **Build > Make Project** o **Run**. |
| 124 | + |
| 125 | +### CLI |
| 126 | + |
60 | 127 | ```bash |
| 128 | +git clone <URL_DEL_REPOSITORIO> |
| 129 | +cd NowPlayingExporterPy |
61 | 130 | ./gradlew :app:assembleDebug |
62 | | -# o |
63 | | -./gradlew :app:assembleRelease |
| 131 | +# APK en: app/build/outputs/apk/debug/app-debug.apk |
| 132 | +``` |
| 133 | + |
| 134 | + |
| 135 | + |
| 136 | +--- |
64 | 137 |
|
| 138 | +## Contribuciones |
| 139 | + |
| 140 | +¡Bienvenidas! Abre un *issue* o un *pull request* con tu propuesta.  |
| 141 | + |
| 142 | +## Licencia |
| 143 | + |
| 144 | +**GPL-3.0**. Consulta el archivo `LICENSE` para más detalles.  |
| 145 | + |
| 146 | +--- |
0 commit comments