Llevo años leyendo varias horas al mes. Novelas, ensayos, un poco de todo. He probado bastantes dispositivos a lo largo del tiempo — principalmente Kobos — y siempre me he topado con el mismo problema: sincronizar mis libros y sobre todo mis posiciones de lectura entre mi e-reader, mi portátil con Linux y mi teléfono. La app de Kobo no está mal en la propia liseuse, pero en el móvil va bastante regular y no facilita nada meter EPUBs que no vengan de su tienda. Vamos, que no funcionaba ni de coña.
Al final me remangué y me puse a desarrollar mi propia solución. Como decimos por ahí: es machacando en el yunque como se ve al albañil — o algo así. Os presento VarBook, una aplicación web self-hosted para gestionar tu biblioteca EPUB con sincronización de la progresión entre todos tus dispositivos.
Cuando lees en varios dispositivos, rápidamente te encuentras con un quebradero de cabeza. Leo un capítulo por la noche en mi Kobo en la cama, y luego quiero seguir al día siguiente en el tren con el móvil. Resultado: tengo que buscar manualmente dónde me quedé. Darle 70 veces a "página siguiente" para retomar la sesión de la noche anterior es el tipo de cosa que te hace cerrar el libro antes de lo previsto.
El ecosistema Kobo es bastante cerrado. La aplicación móvil funciona, pero está claramente orientada a su tienda. Cargar tus propios EPUBs es toda una odisea. ¿Y la sincronización de posiciones entre la app móvil y el e-reader físico? Digamos que es... teórica.
Necesitaba algo sencillo: subir mis EPUBs a un sitio, leerlos en cualquier dispositivo, y encontrar mi posición en todas partes. Ni más ni menos.
Así que construí VarBook durante estos últimos meses. Es una aplicación Laravel 12 completa con un frontend React 18 en TypeScript. El lector EPUB integrado está basado en epub.js, una librería JavaScript que gestiona el renderizado de EPUBs directamente en el navegador.
La interfaz es limpia y sencilla. Para añadir libros, basta con arrastrar y soltar. La aplicación extrae automáticamente los metadatos (título, autor, portada) del EPUB. Se puede personalizar el lector: tema claro/oscuro/sepia, tamaño de fuente, tipografía, interlineado — cada dispositivo mantiene sus propias preferencias de lectura.
Para los que gestionan grandes bibliotecas con Calibre, también he desarrollado un plugin que permite enviar EPUBs por lotes directamente a VarBook desde la interfaz de Calibre. Se acabó exportar y luego subir uno a uno.
Los libros subidos están disponibles de tres formas:
La aplicación también gestiona estadísticas de lectura: tiempo dedicado por libro, historial de sesiones, progresión global. Es el tipo de datos que no sabías que querías hasta que los tienes.
Uno de los aspectos que más me importaba es el modo offline. VarBook es una PWA (Progressive Web App) instalable en el móvil — probada en Android por ahora. En la práctica, se puede descargar un libro en la caché local del navegador vía IndexedDB (usando Dexie como wrapper) y leerlo sin conexión a internet.
Las posiciones de lectura se cachean localmente durante la lectura offline. En cuanto vuelves a estar online, todo se sincroniza automáticamente con el servidor gracias a los Service Workers y la API Background Sync.
Pude probar esta funcionalidad durante mi último viaje en avión y funcionó de maravilla. Aunque tengo que reconocer que mis últimos cambios puede que lo hayan roto desde entonces — sindjeu (palabrota belga), es lo que tiene el desarrollo en solitario. Sigue siendo un trabajo en curso.
Para la parte del e-reader Kobo, redescubrí KOReader. Lo había instalado hace un tiempo pero lo descarté rápidamente porque su interfaz me pareció rudimentaria. ¡Menudo error!
KOReader es un visor de documentos open source diseñado para pantallas E Ink. Funciona en Kobo, Kindle, PocketBook, Android e incluso Linux. Con unos minutos de configuración, el lector se vuelve muy agradable. La barra de estado es una pasada: páginas restantes en el capítulo, tiempo estimado de lectura, porcentaje de progresión, batería — un montón de información útil que no siempre encuentras en los lectores comerciales.
Y hablando de batería, aquí es donde KOReader tiene una auténtica killer feature: el WiFi está desactivado por defecto y solo se activa cuando hace falta. Con el firmware original de Kobo, el WiFi se queda encendido en segundo plano, chupando batería constantemente. KOReader corta el WiFi en cuanto deja de ser necesario. Resultado: pasas de unos pocos días de autonomía a varias semanas sin despeinarte. Cuando lees varias horas al día, eso cambia las reglas del juego.
Pero sobre todo, KOReader tiene un sistema de plugins muy completo. Y ahí es donde se pone interesante para VarBook.
He desarrollado un plugin para KOReader (todavía en pruebas pero ya muy funcional) que sincroniza las posiciones de lectura y la progresión con el servidor VarBook. Una herramienta "VarBook" aparece en el menú de herramientas con un botón "Sync to VarBook". He vinculado esta herramienta a un gesto táctil: un toque en la esquina superior derecha de la pantalla.
Mi flujo de lectura diario es algo así:
Es fluido, rápido, y sobre todo funciona sin tener que pensar en ello. El WiFi solo se enciende durante los pocos segundos necesarios para la sincronización, lo que preserva la autonomía del e-reader. Es un detalle, pero es exactamente el tipo de detalle que hace que dejes de usar el firmware original para siempre.
Puede parecer poca cosa, pero la sincronización de posiciones entre el lector web (epub.js) y KOReader en el e-reader me dio bastantes quebraderos de cabeza. El problema fundamental es que estas dos aplicaciones gestionan el posicionamiento de formas completamente distintas.
epub.js utiliza el sistema CFI (Canonical Fragment Identifier) definido por la especificación EPUB. Un CFI tiene un aspecto como /6/4[chap01]!/4/2/1:0 — es una ruta tipo XPath dentro del documento HTML del capítulo, que apunta a un nodo específico del DOM y un offset de carácter. Este sistema es muy preciso en el contexto de un navegador web, pero está fuertemente acoplado al renderizado HTML.
KOReader, por su lado, trabaja con un sistema basado en páginas. Utiliza su propio motor de renderizado (CREngine) que pagina el documento de forma distinta según el tamaño de pantalla, la fuente, el tamaño del texto, etc. La posición se almacena como un porcentaje de progresión y un "xpointer" interno del motor — un formato completamente incompatible con los CFI de epub.js.
En la práctica: la misma posición en un libro genera dos representaciones totalmente diferentes según si lo lees en un navegador o en el e-reader. Y no existe una tabla de conversión universal entre los dos.
Después de bastante pelea y experimentación, acabé optando por una sincronización basada en dos datos comunes a ambos sistemas: el capítulo actual (identificado por su ruta en el archivo EPUB) y el porcentaje de progresión dentro de ese capítulo. El servidor almacena estos dos datos de forma agnóstica, y cada cliente los traduce a su propio sistema de posicionamiento.
No es perfecto — a veces la posición no es precisa a nivel de página exacta. Pero es perfectamente aceptable y sobre todo infinitamente mejor que tener que buscar manualmente tu página cada vez que cambias de dispositivo.
El proyecto está disponible en GitHub: github.com/ndieschburg/varbook. Está traducido al francés, inglés y español. La instalación en vuestro propio servidor está documentada en el README.
También alojo mi propia instancia abierta al registro sin ninguna restricción. Si queréis probarlo sin instalar nada, no dudéis en crearos una cuenta en varbook.hophop.be.
El stack técnico para los curiosos: Laravel 12, React 18, TypeScript, Tailwind CSS, Vite, MySQL, todo desplegado automáticamente vía CI/CD.
El invento se desarrolló en una buena decena de noches con la ayuda de mi amigo Claude, pero lo uso a diario desde hace tres meses y estoy bastante contento con él. Le voy metiendo mejoras regularmente según leo y me voy encontrando con pequeñas frustraciones por el camino. Si tenéis sugerencias, ideas o bugs que reportar, soy todo oídos — las issues de GitHub están abiertas.
Este artículo fue escrito originalmente en francés. Esta traducción fue generada automáticamente con ayuda de IA.