tawasuyu

sergio/humanoid

HTML 38Markdown 1TOML 10 Definitions

⎇ 81bd1537ab8e172ed59193ef9e316ad76f44b778 vela/src/main/java/com/rizoma/vela/data/Repositorio.kt 105 lines · 3.8 KB History raw

vela: modo reunión — transcripción offline por fragmento (Vosk) 81bd1537a · sergio ·

1package com.rizoma.vela.data
2
3import android.content.Context
4import org.json.JSONArray
5import org.json.JSONObject
6import java.io.File
7
8/**
9 * Guarda y lee las sesiones en `filesDir/sesiones/<id>/`. Cada sesión es una
10 * carpeta con `audio.m4a` y `log.json`. Sin base de datos ni deps: JSON crudo
11 * con escritura atómica (`.tmp` + rename), como el resto del rizoma.
12 */
13class Repositorio(context: Context) {
14
15    private val base = File(context.filesDir, "sesiones")
16
17    fun carpeta(id: Long): File = File(base, id.toString()).apply { mkdirs() }
18
19    /** Escribe (o reescribe) el log de una sesión de forma atómica. */
20    fun escribirLog(
21        id: Long,
22        inicioEpoch: Long,
23        sampleRate: Int,
24        modo: Modo,
25        duracionRealMs: Long,
26        duracionSonoraMs: Long,
27        segmentos: List<Segmento>,
28    ) {
29        val root = JSONObject().apply {
30            put("id", id)
31            put("inicioEpoch", inicioEpoch)
32            put("sampleRate", sampleRate)
33            put("modo", modo.name)
34            put("duracionRealMs", duracionRealMs)
35            put("duracionSonoraMs", duracionSonoraMs)
36            put("segmentos", JSONArray().apply {
37                segmentos.forEach { s ->
38                    put(JSONObject().apply {
39                        put("i", s.indice)
40                        put("ini", s.inicioRealMs)
41                        put("dur", s.duracionMs)
42                        put("arch", s.archivoMs)
43                        put("pico", s.picoDb.toDouble())
44                        put("medio", s.medioDb.toDouble())
45                        if (!s.texto.isNullOrBlank()) put("txt", s.texto)
46                    })
47                }
48            })
49        }
50        val dir = carpeta(id)
51        val tmp = File(dir, "log.json.tmp")
52        tmp.writeText(root.toString())
53        tmp.renameTo(File(dir, "log.json"))
54    }
55
56    /** Lista las sesiones (más recientes primero), sin cargar los segmentos. */
57    fun listar(): List<Sesion> {
58        val dirs = base.listFiles()?.filter { it.isDirectory } ?: return emptyList()
59        return dirs.mapNotNull { cargarDe(it) }
60            .sortedByDescending { it.inicioEpoch }
61    }
62
63    fun cargar(id: Long): Sesion? = cargarDe(File(base, id.toString()))
64
65    private fun cargarDe(dir: File): Sesion? {
66        val log = File(dir, "log.json")
67        if (!log.exists()) return null
68        return try {
69            val o = JSONObject(log.readText())
70            val arr = o.optJSONArray("segmentos") ?: JSONArray()
71            val segs = ArrayList<Segmento>(arr.length())
72            for (i in 0 until arr.length()) {
73                val s = arr.getJSONObject(i)
74                segs.add(
75                    Segmento(
76                        indice = s.optInt("i", i),
77                        inicioRealMs = s.optLong("ini"),
78                        duracionMs = s.optLong("dur"),
79                        archivoMs = s.optLong("arch"),
80                        picoDb = s.optDouble("pico", -70.0).toFloat(),
81                        medioDb = s.optDouble("medio", -70.0).toFloat(),
82                        texto = s.optString("txt", "").ifBlank { null },
83                    )
84                )
85            }
86            Sesion(
87                id = o.getLong("id"),
88                inicioEpoch = o.getLong("inicioEpoch"),
89                sampleRate = o.optInt("sampleRate", 16000),
90                modo = runCatching { Modo.valueOf(o.optString("modo", "NORMAL")) }
91                    .getOrDefault(Modo.NORMAL),
92                duracionRealMs = o.optLong("duracionRealMs"),
93                duracionSonoraMs = o.optLong("duracionSonoraMs"),
94                segmentos = segs,
95                dir = dir,
96            )
97        } catch (_: Exception) {
98            null
99        }
100    }
101
102    fun borrar(id: Long) {
103        File(base, id.toString()).deleteRecursively()
104    }
105}