Aplicación de escritorio para explorar y descargar archivos desde Myrient, pensado para preservar video juegos y cachurear.
- Descripción del proyecto
- Características principales
- Gestión de descargas
- Estados de descarga
- Interfaz y experiencia de usuario
- Tecnologías utilizadas
- Funcionamiento del motor de descargas
- Requisitos del sistema
- Instalación
- Uso básico
- Romset Builder
- Configuración
- Estado del proyecto
- Roadmap
- Estructura del proyecto
- Scripts disponibles
- CI / Calidad
- Contribuciones
- Advertencias y notas
- Limitaciones conocidas
- Manejo de errores
- Seguridad (resumen)
- Licencia
- Créditos
Dpana Hub – ROM Download Manager (dpanahub-rdm) es un gestor de descargas que permite explorar los catálogos de Myrient, LoLROMs, PleasureDome y My Abandonware y descargar archivos de forma fiable y eficiente. Myrient es un recurso de preservación con más de 2,9 millones de entradas; esta aplicación ofrece:
- Exploración local: acceso rápido a los catálogos mediante bases de datos SQLite locales, sin depender de la web oficial para navegar.
- Multi-catálogo: pantalla de inicio para elegir fuente (Myrient, LoLROMs, PleasureDome o My Abandonware); cada catálogo se gestiona con el mismo flujo (compresión .7z, descompresión al arranque, índices y búsqueda).
- Descargas robustas: cola persistente, descargas simples y descargas fragmentadas por chunks para archivos grandes, con reintentos, verificación de integridad y control de concurrencia.
- Proyecto abierto: código estructurado y extensible, adecuado para revisión y contribuciones.
Está orientado a usuarios que quieren descargar ROMs y datos de preservación desde Myrient, LoLROMs, PleasureDome o My Abandonware con una interfaz clara y un motor de descargas preparado para redes inestables y archivos grandes.
- Descargas simples: archivos por debajo de un umbral (p. ej. 50 MB) se descargan en una sola conexión.
- Descargas fragmentadas (chunked): archivos más grandes se dividen en partes que se descargan en paralelo para aprovechar mejor el ancho de banda (bandas dinámicas: 50–500 MB → 4–8 chunks; > 500 MB → 8–16 chunks).
- Persistencia de cola: el estado de la cola se guarda en SQLite; al reiniciar la aplicación, las descargas pueden continuar donde quedaron.
- Resiliencia: reintentos automáticos con back-off exponencial ante errores de red; circuit breaker para evitar saturar hosts con fallos repetidos.
- Integridad: fusión atómica de chunks y verificación por hash cuando está disponible.
- Validación previa: comprobación de espacio en disco y rutas antes de iniciar.
- Test de calibración: herramienta en configuración para ajustar chunks y paralelismo según la conexión.
- Bases de datos locales: SQLite con catálogos Myrient (más de 2,6 M de archivos), LoLROMs, PleasureDome y My Abandonware; pantalla de inicio para seleccionar la fuente a explorar.
- Filtros: por nombre, tamaño, fecha, extensión, etc.
- Navegación: explorador de carpetas tipo gestor de archivos.
- Favoritos: sistemas o carpetas guardadas por fuente (Myrient, LoLROMs, PleasureDome o My Abandonware).
- Romset Builder: asistente paso a paso para elegir una fuente, navegar por proyectos/compañías y carpetas hasta una carpeta con archivos, ver resumen (cantidad de archivos y tamaño estimado) y agregar todo el romset a la cola de descargas de una vez.
- Enlaces magnet: modal dedicado para ver, copiar o abrir en cliente externo cuando una descarga ofrece enlace magnet.
- Diseño moderno: tema claro/oscuro, tipografía Inter. Dos modos visuales seleccionables en Configuración:
- Glassmorphism (por defecto): estilos tipo vidrio y transparencias.
- Frutiger Aero / Web 2.0 Gloss: estilo inspirado en Windows Vista/7 (glossy, colorido, reflejos superiores, blur real y profundidad 3D suave); disponible en variante clara y oscura.
- Micro-animaciones: hover, transiciones y feedback visual.
- Progreso detallado: velocidad (EMA), ETA, porcentaje global y por archivo; indicador de progreso por chunks en descargas fragmentadas.
- Control de cola: pausar, reanudar, reiniciar o eliminar descargas.
- Selección múltiple: añadir muchos archivos a la cola de una vez (hasta un límite configurable).
- Modo preparación de cola: al superar un umbral de archivos agregados, se puede revisar el lote y confirmar antes de iniciar las descargas.
- Romset Builder: wizard accesible desde el menú lateral que guía la selección de catálogo (Myrient, LoLROMs, PleasureDome o My Abandonware), proyecto o compañía, carpetas anidadas y muestra un resumen (archivos y tamaño) antes de agregar la carpeta completa a la cola.
- Descarga simple: un solo archivo, una conexión HTTP. Aplicada por defecto a archivos pequeños (p. ej. < 50 MB) para no sobrecargar el servidor en la mayoría del catálogo.
- Descarga por chunks: para archivos más grandes, el motor divide el rango en fragmentos (HTTP Range), descarga varios chunks en paralelo, los escribe en disco, los fusiona en un único archivo y opcionalmente verifica el hash. El umbral y el número de chunks dependen de la configuración (p. ej. 50 MB de umbral; bandas 50–500 MB y > 500 MB con distinto número y tamaño de chunk).
- Cola: las descargas se encolan con prioridad; un planificador (Scheduler) asigna slots según límites de descargas simultáneas y chunks simultáneos por archivo. El estado se persiste en SQLite (StateStore).
Cada descarga recorre un ciclo de estados (guardados en SQLite):
| Estado | Descripción breve |
|---|---|
queued |
En cola, esperando slot. |
starting |
Asignada a un slot; preparando conexión o chunks. |
downloading |
Descargando (simple o por chunks). |
paused |
Pausada por el usuario. |
merging |
(Solo chunked) Fusionando chunks en el archivo final. |
verifying |
Comprobando integridad (hash/tamaño). |
completed |
Finalizada correctamente. |
failed |
Error (red, servidor, disco, etc.). |
cancelled |
Cancelada por el usuario. |
Los chunks de una descarga fragmentada tienen sus propios estados: pending, downloading, completed, failed, paused. El frontend muestra el estado actual de cada descarga y, en su caso, el progreso por chunk.
- Ventana principal: barra de título, barra de búsqueda, panel lateral (navegación/favoritos), área de archivos/carpetas y panel de cola de descargas.
- Tema: claro u oscuro; modo visual elegible en Configuración → Personalización: Glassmorphism (por defecto) o Frutiger Aero (Web 2.0 Gloss), con estilos tipo vidrio/glossy y componentes Vue (tablas, modales, toasts).
- Acciones rápidas: descargar archivo, descargar selección, descargar carpeta completa (con confirmación y límite de archivos por carpeta).
- Cola de descargas: lista de ítems con progreso, velocidad, ETA y acciones (pausar, reanudar, reiniciar, eliminar); filtro por estado y búsqueda por nombre/ruta/URL.
- Panel de estadísticas: modal (accesible desde el menú lateral) con métricas de sesión (velocidad actual, descargas iniciadas/completadas/fallidas, bytes descargados, latencia, métricas por host, estado del circuit breaker).
- Configuración: carpeta de descargas, descargas simultáneas, chunks por archivo, umbral de confirmación en lotes, notificaciones, reanudar al iniciar, tema visual (Glassmorphism / Frutiger Aero), test de calibración.
- Consola de logs: accesible desde la interfaz para diagnóstico.
- Apertura de carpeta de datos: acceso rápido a config, logs y base de datos de la aplicación.
| Capa | Tecnología |
|---|---|
| Runtime | Electron 40 |
| Lenguaje | TypeScript (electron, workers, scripts); Vue 3 con <script setup lang="ts"> |
| Frontend | Vue 3 (Composition API), Vite 7 |
| Base de datos | Better-SQLite3 (catálogo y estado de descargas) |
| Validación | Zod |
| Logging | electron-log |
| Estilos | CSS con variables con temas de glassmorphism y modo aereo como windows 7 |
| Iconos | Lucide Vue Next |
- Entrada: el usuario pide una descarga (archivo, selección o carpeta). El frontend llama a la API expuesta por Electron (
window.api), que valida y delega en el backend. - Persistencia: el backend (DownloadEngine, StateStore) registra la descarga en SQLite con estado
queuedy metadatos (URL, ruta, tamaño si está disponible, etc.). - Planificación: el Scheduler respeta límites de descargas simultáneas y chunks por archivo; asigna slots y prioridad (con aging para evitar inanición).
- Ejecución:
- Archivos “pequeños” (p. ej. < 50 MB): SimpleDownloader hace una petición HTTP y escribe a disco; progreso y estado se actualizan y se emiten al frontend vía EventBus.
- Archivos “grandes”: ChunkManager calcula los rangos, ChunkDownloader descarga chunks en paralelo, FileAssembler fusiona en un único archivo; Verifier comprueba hash/tamaño si aplica.
- Eventos: EventBus notifica cambios de estado y progreso; el frontend actualiza la cola y los indicadores en tiempo real.
- Cierre: al cerrar la aplicación, el motor pausa descargas activas, persiste el estado en SQLite y permite un cierre ordenado para poder reanudar después.
Componentes clave del motor: DownloadEngine, StateStore, Scheduler, ChunkManager, ChunkDownloader, SimpleDownloader, FileAssembler, Verifier, EventBus, CircuitBreakerManager, SessionManager, DownloadValidator, SpeedTracker, ChunkStore, DownloadMetrics (métricas de sesión), ChunkProgressAggregator, AdaptiveChunkSizer, AdaptiveConcurrencyController.
Flujo de datos (usuario → backend → UI):
flowchart LR
subgraph ui [Frontend Vue]
User[Usuario]
API[window.api]
end
subgraph main [Main Process]
IPC[ipcStateHandlers]
Engine[DownloadEngine]
Sched[Scheduler]
State[StateStore]
Simple[SimpleDownloader]
Chunk[ChunkDownloader]
EventBus[EventBus]
end
User --> API
API --> IPC
IPC --> Engine
Engine --> Sched
Engine --> State
Engine --> Simple
Engine --> Chunk
Engine --> EventBus
EventBus --> IPC
IPC --> API
API --> User
Los estados de una descarga se persisten en StateStore (SQLite): queued → starting → downloading → (opcional) merging → verifying → completed, o failed / cancelled / paused.
- Node.js: 20.x o superior (solo para desarrollo).
- npm: 10.x o superior.
- 7-Zip: necesario para la extracción inicial de la base de datos si se distribuye en formato
.7z. - Sistema operativo: Windows 10/11 (portable x64), macOS (dmg/zip) o Linux (AppImage, .deb).
- Bases de datos de catálogo: al menos
myrient_data.db(omyrient_data.7z); opcionalmentelolrom_data.db,pleasuredome_data.dbymyabandonware_data.db(o sus.7z) para explorar LoLROMs, PleasureDome y My Abandonware. Ubicación:resources/en desarrollo oextraResourcesen el build. - Resolución de pantalla: la ventana admite un tamaño mínimo de 320×240 píxeles (útil en monitores CRT o ventanas muy pequeñas). La interfaz es responsive y se adapta a distintos anchos, proporciones (4:3, 16:9, 21:9, 9:16) y escalado del sistema operativo (DPI).
git clone https://github.com/crtgamers/dpanahub-rdm.git
cd dpanahub-rdm
npm install
# Copiar o colocar las bases de datos en resources/
# myrient_data.db (requerido) y opcionalmente lolrom_data.db, pleasuredome_data.db, myabandonware_data.db
# Si se usan archivos .7z, 7-Zip debe estar instalado
npm run devTras npm run build o npm run build:win, el ejecutable portable (x64) se genera en dist-electron/.
Opcional: script deploy.ps1 para descargar e instalar la aplicación de forma remota (ejemplo: irm https://... | iex). También existe Install.ps1 para instalación local; puede requerir configurar la ruta o ID del paquete según el caso.
Tras npm run build o npm run build:mac, se generan dmg y zip en dist-electron/. Los builds por defecto no están firmados ni notarizados; ver workflows en .github/workflows/build-macos.yml para CI.
Tras npm run build:linux, se generan AppImage y paquete .deb en dist-electron/. Para AppImage puede ser necesario libfuse2 (en Ubuntu/Debian: sudo apt-get install libfuse2).
- Explorar: navega por carpetas en el panel o usa la búsqueda para encontrar archivos.
- Descargar un archivo: usa el botón de descarga del archivo.
- Descargar varios: selecciona archivos y usa “Descargar selección” (respetando el límite de selección, p. ej. 1000 archivos).
- Descargar carpeta: usa “Carpeta completa”; se aplica confirmación y límite de archivos por carpeta (p. ej. 1000, configurable).
- Gestionar la cola: en “Cola de descargas” puedes pausar, reanudar, reiniciar o eliminar ítems.
- Romset Builder: en el menú lateral, “Romset Builder” abre un asistente para elegir fuente (Myrient, LoLROMs, PleasureDome o My Abandonware), navegar por proyectos/compañías y carpetas hasta la que quieras descargar, ver el resumen (número de archivos y tamaño) y agregar toda la carpeta a la cola con un clic.
- Enlaces magnet: si una descarga ofrece enlace magnet, puedes abrirlo desde la cola para copiarlo o abrirlo con tu cliente de torrents.
Opciones avanzadas: filtros en el panel de archivos, modo preparación de cola (revisar lote antes de iniciar), Romset Builder (menú lateral) para encolar carpetas completas por wizard, test de calibración en Configuración, consola de logs y abrir carpeta de datos desde la app.
El Romset Builder es un asistente (wizard) integrado que permite elegir una carpeta completa del catálogo —por ejemplo un proyecto o un sistema— y agregar todos sus archivos a la cola de descargas en un solo paso, con un resumen previo de cantidad de archivos y tamaño estimado.
- En el menú lateral (sidebar), haz clic en «Romset Builder» (icono de capas). Se abre un panel modal sobre la aplicación.
El asistente tiene tres fases, con un indicador de pasos (stepper) y breadcrumb en la parte superior:
-
Fuente de datos
Elige el catálogo: Myrient, LoLROMs, PleasureDome o My Abandonware. La aplicación cargará la base de datos correspondiente si aún no está activa. -
Navegación
- En Myrient: el primer nivel muestra solo proyectos oficiales (No-Intro, Redump, TOSEC, MAME, HBMAME, FinalBurn Neo, Total DOS Collection, eXo, etc.). Selecciona un proyecto y luego navega por las carpetas (sistema, variantes, etc.) hasta la carpeta que quieras descargar.
- En LoLROMs, PleasureDome o My Abandonware: el primer nivel muestra las compañías o fabricantes (o estructura equivalente) desde la raíz. Elige una y luego navega por carpetas hasta la que contenga los archivos.
- En cada nivel puedes filtrar la lista si hay muchas opciones (aparece un campo de búsqueda cuando hay más de 8 ítems).
- El wizard detecta automáticamente cuándo la carpeta seleccionada contiene archivos: en ese momento pasa al resumen sin pedir más niveles.
-
Resumen
Se muestra la ruta elegida (fuente y carpetas), el número total de archivos y el tamaño estimado (calculado de forma recursiva en la base de datos, sin transferir la lista completa).
Si todo es correcto, pulsa «Agregar a la cola». Los archivos de esa carpeta se encolan como una descarga de carpeta completa; se aplican las mismas reglas que en «Carpeta completa» (confirmación y límites si los tienes configurados).
- Anterior: vuelve al paso o nivel anterior (por ejemplo, a elegir otra subcarpeta o a cambiar de fuente).
- Siguiente: confirma la carpeta seleccionada en el nivel actual y carga el siguiente nivel, o pasa al resumen si esa carpeta ya tiene archivos.
- Cancelar / Cerrar: cierra el asistente sin agregar nada a la cola.
- Agregar a la cola (solo en resumen): encola todos los archivos de la carpeta elegida y cierra el modal.
- Debe estar configurada una carpeta de descargas en Configuración; si no, al agregar a la cola puede mostrarse un aviso.
- El resumen (archivos y tamaño) se calcula en el backend con la base de datos del catálogo activo; no se descargan listados desde internet.
- Si cambias de fuente (Myrient, LoLROMs, PleasureDome o My Abandonware) en el primer paso, la app carga la base correspondiente automáticamente.
- El Romset Builder está disponible en los tres idiomas de la aplicación (español, español Chile, inglés).
| Variable | Descripción |
|---|---|
VITE_DEV_SERVER_URL |
URL del servidor Vite (solo desarrollo). |
NODE_ENV |
development o production. |
La aplicación guarda configuración y estado en el directorio de datos del usuario:
- Windows:
%APPDATA%\dpanahub-rdm\(o la ruta devuelta porapp.getPath('userData')). - macOS:
~/Library/Application Support/dpanahub-rdm/. - Linux:
~/.config/dpanahub-rdm/.
En ese directorio suelen estar: config/*.json, downloads-state.db (cola y estado de descargas), window-state.json, logs/*.log.
- Carpeta de descargas: ruta base donde se guardan los archivos.
- Descargas simultáneas: 1–3 (por defecto 3).
- Chunks simultáneos por archivo: 1–5 (por defecto 3).
- Umbral de confirmación en lotes: cuántos archivos agregar antes de mostrar confirmación.
- Notificaciones: activar/desactivar toasts.
- Reanudar al iniciar: restaurar descargas pausadas al abrir la aplicación.
La aplicación incluye actualizaciones automáticas con electron-updater cuando se ejecuta la versión empaquetada:
- Al iniciar se comprueba si hay una nueva versión en segundo plano.
- En Configuración → Actualizaciones puedes ver la versión actual, pulsar Buscar actualizaciones y, si hay una descarga lista, Reiniciar e instalar.
Windows (dos modos):
- Portable (un solo
.exe): el updater descarga el nuevo.exey lo ejecuta al reiniciar. - Carpeta (ejecutar desde
dpanahub-rdm-win): el updater descarga el ZIP del release, lo extrae y reemplaza los archivos de la carpeta in-place antes de reiniciar.
Para publicar releases y que los usuarios reciban actualizaciones:
- El
build.publishenpackage.jsonya está configurado para el repo (p. ej.crtgamers/dpanahub-rdm). - Crea releases en GitHub con etiquetas versionadas (p. ej.
v1.3.1). - Windows: sube a la release los archivos que genera
npm run buildonpm run build:winendist-electron/:- latest.yml (obligatorio para que funcione “Buscar actualizaciones” en el portable): se genera automáticamente tras el build. Sin este archivo en el release, el updater devuelve error 404 al buscar actualizaciones.
- .exe portable: para que el updater lo encuentre, el nombre del asset en el release debe usar guiones:
Dpana-Hub-–-ROM-Download-Manager-<version>.exe(p. ej.Dpana-Hub-–-ROM-Download-Manager-1.3.1.exe). El scriptgenerate-latest-yml.tsya referencia ese nombre. - .zip (modo carpeta):
Dpana Hub – ROM Download Manager <version>-win.zip(p. ej.Dpana Hub – ROM Download Manager 1.3.1-win.zip).
- Opcional: usa CI con
GH_TOKENyelectron-builder --publish alwayspara publicar automáticamente (incluyelatest.yml).
El proyecto se encuentra en desarrollo activo, en estado beta: las funcionalidades principales (exploración, cola, descargas simples y por chunks, persistencia, verificación) están implementadas y en uso. La v1.9.0 incorpora los catálogos PleasureDome y My Abandonware (cuatro fuentes en total: Myrient, LoLROMs, PleasureDome, My Abandonware), el modal de enlaces magnet para copiar o abrir en cliente externo, y mejoras en la configuración y descarga de bases de datos por fuente. La v1.8.0 añade el indicador de estado de la base de datos en el sidebar y el flujo de verificación y descarga de bases cuando no están presentes; la v1.7.0 el modo visual Frutiger Aero; la v1.6.0 el Romset Builder; la v1.5.0 el soporte multi-catálogo y pantalla de inicio. Ver CHANGELOG.md para el detalle. Pueden existir limitaciones (véase Limitaciones conocidas) y el roadmap incluye mejoras de compatibilidad, UX y documentación (véase Roadmap).
Previstas (detalle en TODO.md):
- Wizard de configuración inicial (First Run Wizard): tema, carpeta de descargas, chunks, confirmaciones.
- Sistema de tutorial interactivo: pasos guiados por menú, búsqueda, cola y descargas.
- Filtros avanzados: etiquetas de región (JPN, USA, EUR), normalización (JP=JPN, US=USA, etc.).
- Glosario de términos: Aftermarket, Rev, Split, región, etc., accesible desde menú y ayuda contextual.
- Sección informativa de emuladores: enlaces, descripciones y sistemas compatibles; sin ejecución de ROMs en una primera fase.
- Múltiples idiomas (i18n): ya implementado en 1.3.0. Español como idioma principal (por defecto), inglés y español de Chile (es-CL). Validaciones en CI, tipado fuerte de keys, CONTRIBUTING para añadir idiomas. Ver CONTRIBUTING.md.
dpanahub-rdm/
├── electron/ # Proceso principal de Electron (TypeScript)
│ ├── engines/ # Motor de descargas
│ │ ├── DownloadEngine.ts # Orquestador principal
│ │ ├── StateStore.ts # Persistencia transaccional (SQLite WAL, downloads-state.db)
│ │ ├── Scheduler.ts # Planificación y límites de cola
│ │ ├── ChunkStore.ts # Almacén de chunks en disco
│ │ ├── ChunkManager.ts # Coordinación de descargas fragmentadas
│ │ ├── ChunkDownloader.ts# Descarga de chunks HTTP Range
│ │ ├── SimpleDownloader.ts # Descarga directa (archivos pequeños)
│ │ ├── FileAssembler.ts # Fusión atómica de chunks
│ │ ├── Verifier.ts # Verificación de integridad por hash
│ │ ├── EventBus.ts # Eventos hacia el frontend
│ │ ├── DownloadMetrics.ts# Métricas de sesión (velocidad, latencia, por host)
│ │ ├── CircuitBreakerManager.ts
│ │ ├── SessionManager.ts
│ │ ├── DownloadManager.ts
│ │ ├── DownloadValidator.ts
│ │ └── SpeedTracker.ts
│ ├── services/ # Lógica de negocio
│ │ ├── BaseService.ts
│ │ ├── DownloadService.ts
│ │ ├── FileService.ts
│ │ ├── QueueService.ts
│ │ └── SearchService.ts
│ ├── workers/ # worker_threads (descarga, merge, consultas DB)
│ ├── constants/
│ ├── utils/
│ ├── migration/
│ ├── ipcHandlers.ts
│ ├── ipcStateHandlers.ts
│ ├── updater.ts # Actualizaciones automáticas (electron-updater)
│ ├── main.ts
│ ├── preload.ts
│ ├── window.ts
│ ├── database.ts
│ └── config.ts
├── src/ # Frontend Vue 3 + Vite (TypeScript)
│ ├── App.vue
│ ├── main.ts
│ ├── style.css
│ ├── components/
│ ├── composables/ # useDownloads, useQueueFilter, useFileSelection, etc.
│ ├── constants/
│ ├── locales/ # i18n (en, es, es-CL)
│ ├── plugins/
│ ├── services/
│ └── utils/
├── scripts/ # Scripts de build (TypeScript, ejecutados con tsx)
│ ├── build-db-7z.ts
│ ├── build-icon.ts
│ ├── check-cjs-usage.ts
│ ├── inspect-asar.ts # Inspección de app.asar (tamaño por carpeta)
│ ├── prune-app-deps.cjs # Hook beforePack: reduce tamaño del asar
│ └── rename-win-output.ts
├── resources/ # Base de datos SQLite (no versionada: .db, .7z, etc.)
├── __tests__/
├── .github/workflows/
├── vite.config.ts
├── deploy.ps1 # Script de instalación remota (PowerShell)
├── Install.ps1 # Script de instalación local (Windows)
└── package.json
El frontend se comunica con Electron mediante window.api (preload + contextBridge). El backend está en TypeScript; los workers se compilan con npm run build:electron-workers (tsconfig.workers.json). Se usa SQLite para catálogo y cola.
Documentación del código: los módulos principales (electron, src, shared) están documentados con JSDoc: descripción de módulo, @param y @returns en funciones y métodos públicos. Facilita el mantenimiento y la incorporación de contribuidores.
| Script | Descripción |
|---|---|
npm run dev |
Modo desarrollo con Hot Reload (Vite + Electron). |
npm run build |
Compila frontend, workers y genera ejecutable (Windows portable por defecto; incluye compresión de myrient_data.db y lolrom_data.db a .7z). |
npm run build:win |
Build solo para Windows (portable x64). |
npm run build:mac |
Build solo para macOS (dmg + zip, sin firma). |
npm run build:linux |
Build solo para Linux (AppImage + .deb). |
npm run build:electron-workers |
Compila los workers de Electron (TypeScript → dist-electron/workers). |
npm run build-icon |
Genera iconos para la aplicación. |
npm run inspect-asar |
Tras un build, inspecciona el contenido de app.asar y muestra tamaños por carpeta (útil si el asar pesa mucho). |
npm run lint |
Ejecuta ESLint. |
npm run lint:fix |
ESLint con corrección automática. |
npm run format |
Formatea con Prettier. |
npm run format:check |
Comprueba formato sin modificar. |
npm run test |
Suite completa de tests (Jest con ES modules). |
npm run test:unit |
Solo tests unitarios. |
npm run test:integration |
Solo tests de integración. |
npm run test:acceptance |
Tests de aceptación. |
npm run test:watch |
Tests en modo watch. |
npm run test:coverage |
Tests con cobertura. |
npm run check-cjs |
Verifica uso de CommonJS. |
npm run depcheck |
Comprueba dependencias no usadas o no declaradas (ejecutar de vez en cuando). |
npm run typecheck |
Verificación de tipos con TypeScript (sin emitir). |
npm run typecheck:vue |
Verificación de tipos en componentes Vue (vue-tsc). |
npm run typecheck:all |
typecheck + typecheck:vue (usado en CI). |
npm run validate-locales |
Comprueba que todos los idiomas tengan las mismas keys que en/common.json. |
npm run validate-i18n-keys |
Comprueba que las keys usadas en t() existan en en. |
npm run validate-i18n-keys:orphans |
Lista keys definidas pero no usadas como literal en código. |
Tamaño del instalador (app.asar): un app.asar de más de ~100 MB suele indicar que se está empaquetando algo innecesario (p. ej. node_modules completos o binarios de todas las plataformas). El build incluye un hook beforePack (scripts/prune-app-deps.cjs) que elimina de node_modules lo que no se necesita en runtime (p. ej. código fuente de better-sqlite3, binarios 7z de otras plataformas). Si aun así el asar es grande, ejecuta npm run inspect-asar tras un build para ver qué carpetas ocupan más espacio.
Revisión de dependencias: puedes ejecutar npm run depcheck periódicamente para detectar paquetes declarados en package.json que no se usan en el código, o dependencias en uso no declaradas. Revisa los resultados (p. ej. herramientas usadas solo en scripts de build pueden aparecer como "no usadas") antes de eliminar algo. Nota: @types/jest puede aparecer como "unused" en depcheck; es un falso positivo: Jest se usa en la suite de tests y los tipos se consumen indirectamente. No elimines @types/jest de devDependencies.
Estructura de tests: la suite está en __tests__/: unit (módulos aislados con mocks), integration (flujos que combinan varios módulos o IPC) y acceptance (criterios de aceptación). Los mocks de Electron, config y base de datos están en __tests__/__mocks__/. Para ejecutar solo una carpeta: npm run test -- --testPathPattern=__tests__/unit (o __tests__/integration). Cobertura de código: npm run test:coverage (genera informe en coverage/). Ver CONTRIBUTING.md para convenciones y cómo mockear Electron/DB al añadir tests.
El flujo de GitHub Actions (.github/workflows/ci.yml) se ejecuta en cada push y PR a main/master:
- Lint y tests: checkout, Node 20,
npm ci,npm run validate-locales,npm run validate-i18n-keys,npm run typecheck:all,npm run lint,npm run format:check,npm run test:unit,npm run test:integration. No incluye compilación de artefactos instalables. Opcional en local:npm run test:coveragepara ver cobertura.
Workflows separados (build por plataforma):
build-windows.yml: genera ejecutable portable Windows (x64) enwindows-latest.build-linux.yml: genera AppImage y .deb para Linux enubuntu-latest(requierelibfuse2para AppImage).build-macos.yml: genera builds de macOS (dmg, zip, .app) sin firma enmacos-latest.
La aplicación soporta varios idiomas. El idioma se determina en este orden:
- Idioma guardado por el usuario (Configuración → Personalización → Idioma).
- Idioma del sistema (Windows, macOS o Linux vía Electron).
- Por defecto: Español (
es).
- Español (
es) – referencia base. - Español (Chile) (
es-CL) – fallback aessi falta una clave. - English (
en).
-
Añadir un idioma nuevo
-
Copia la carpeta
src/locales/en/y renómbrala al código de idioma (ej:frpara francés). -
Traduce solo los valores del archivo
common.json; no cambies las claves (son semánticas, ej:errors.connectionError). -
Registra el idioma en
src/locales/index.ts: añade el código aSUPPORTED_LOCALESy aLOCALE_LABELS.
-
-
Actualizar un idioma existente
- Edita
src/locales/<código>/common.jsony traduce las claves nuevas o ajusta textos. No elimines claves.
- Edita
-
Validar
- Ejecuta
npm run validate-locales. El script comprueba que no falten claves ni haya claves inválidas respecto aen/common.json.
- Ejecuta
Estructura de archivos:
src/locales/
├── en/
│ └── common.json ← Referencia
├── es/
│ └── common.json
├── es-CL/
│ └── common.json
└── index.ts ← SUPPORTED_LOCALES y LOCALE_LABELS
Las contribuciones son bienvenidas. Se recomienda:
- Leer CONTRIBUTING.md para detalles sobre cómo contribuir y, en particular, cómo añadir o modificar idiomas (i18n).
- Abrir un issue para discutir cambios grandes o nuevas funcionalidades.
- Seguir el estilo de código del proyecto (ESLint, Prettier).
- Si tocas traducciones o textos de la UI: ejecutar
npm run validate-localesynpm run validate-i18n-keysantes del PR (el CI también los ejecuta). - Añadir o ajustar tests cuando sea apropiado.
- Respetar la licencia GPL v3 del proyecto (obra derivada bajo la misma licencia).
- Bases de datos de catálogo: la aplicación requiere al menos la base de datos Myrient (
myrient_data.dbomyrient_data.7z) enresources/; opcionalmente LoLROMs, PleasureDome y My Abandonware (sus respectivos.dbo.7z). Son archivos grandes; su obtención y actualización se entregan entre versiones; la descarga desde la aplicación está disponible cuando faltan (v1.8.0); la auto-actualización está prevista como mejora futura. - Uso responsable: Myrient es un recurso de preservación; usa la aplicación de forma responsable y conforme a las condiciones de uso del servicio.
- Rutas y permisos: asegúrate de tener espacio suficiente y permisos de escritura en la carpeta de descargas y en el directorio de datos de la aplicación.
- Bases de datos: requiere al menos
myrient_data.dbenresources/; opcionalmentelolrom_data.db,pleasuredome_data.dbymyabandonware_data.dbpara LoLROMs, PleasureDome y My Abandonware. Son archivos pesados y está en evaluación su optimización. - Selección masiva: máximo de 1000 archivos por selección; para más, usar descarga de carpeta completa.
- Carpeta completa: la descarga de carpeta completa permite configurar un número máximo de archivos por carpeta.
- Descargas por chunks: en algunos casos las descargas fragmentadas pueden fallar de forma intermitente; el motor reintenta el chunk desde cero para garantizar integridad, lo que puede provocar pausas breves en la progresión. La opción de chunks se puede activar manualmente en configuración.
- Cola no inicia en casos puntuales: en situaciones poco frecuentes (p. ej. tras reemplazar ciertos archivos o encolar muchos ítems), la cola puede no arrancar; reiniciar la aplicación suele resolverlo. Se trata de un bug conocido bajo investigación.
- Backend:
uncaughtExceptionyunhandledRejectionse registran en log y se puede notificar al frontend (error-notification). Los handlers IPC pasan por un wrapper que captura excepciones y devuelve{ success: false, error: string }cuando corresponde. - Frontend: manejador global de errores y componentes de respaldo para fallos en subárboles; las llamadas a
window.apicompruebansuccessantes de usardata. - Red: reintentos con back-off exponencial; circuit breaker para hosts problemáticos; notificaciones opcionales al usuario en fallos de chunk o descarga.
La aplicación aplica las siguientes medidas de seguridad en el proceso main (backend):
- Validación de entradas: términos de búsqueda (longitud, caracteres especiales), IDs de nodo y de descarga (enteros positivos), nombres de archivo de configuración (solo
.json, sin path traversal). Toda entrada que llega por IPC se valida antes de usarse. - Rutas de descarga: las rutas que envía el renderer se normalizan con
path.resolvey se rechazan si contienen..(path traversal). Se bloquean la raíz del sistema y directorios críticos del SO (p. ej. Windows, Program Files); las rutas “sensibles” (p. ej. carpetas del sistema) se consideran válidas pero el frontend puede mostrar advertencia. - URLs: solo se aceptan URLs con protocolo HTTPS y cuyo host esté en la lista permitida (
config.security.allowedHosts). Las descargas solo se inician hacia esos dominios. - SQL: las consultas al catálogo y al estado de descargas usan prepared statements (placeholders); no se concatena entrada de usuario en SQL. Los nombres de tabla (p. ej. FTS) se validan con una lista blanca de caracteres y se rechazan si contienen palabras clave peligrosas.
- Nombres de archivo: los títulos y nombres que forman parte de rutas de guardado se sanitizan (caracteres prohibidos, nombres reservados en Windows, longitud máxima) antes de escribir en disco.
- Rate limiting: los canales IPC sensibles (búsqueda, añadir descarga, obtener estado de cola, etc.) tienen límite de frecuencia para mitigar abuso.
Para más detalle, ver los módulos electron/utils/validation.ts, electron/utils/downloadPath.ts y los handlers en electron/ipcHandlers.ts y electron/ipcStateHandlers.ts.
Este proyecto está bajo la licencia GNU General Public License v3.0 (GPL v3). Puedes usar, modificar y redistribuir el software bajo los términos de esta licencia; las obras derivadas deben distribuirse bajo la misma licencia. Ver LICENSE para el texto completo.
- Autores: Bastian Aguirre (CRT Gamers Chile), Pablo M. Iglesias.
- Myrient – Por su gran trabajo preservando y funcionando como hosting de datos.
- Erista – Infraestructura de acceso a los archivos.
- LoLROMs – Por su gran trabajo preservando y funcionando como hosting de datos.
- PleasureDome – Por su gran trabajo preservando y funcionando como hosting de datos.
- My Abandonware – Por su gran trabajo preservando y funcionando como hosting de datos.
- Comunidad CRT Gamers Chile – Por inspirarnos y darnos feedback.
- Icono y fondo del modo aéreo – La gran Monstwitos (https://www.instagram.com/monstuwitos/) diseñó el icono de la aplicación y el fondo del modo Aéreo.
Desarrollado con todo mi corazon para la comunidad CRT Gamers Chile (el grupete de mi corazoncito) y para la comunidad de preservación de videojuegos en el mundo. En nuestros corazones todavia esta el legado de CTMW.