I read every single day. At home it’s on my Kobo running KOReader (yes, I’m that open-source guy), and I love it. The problem: I don’t always have the e-reader on me. On the train, at work, waiting somewhere — I just have my phone.

I tried Kobo’s own Android app to bridge the gap and… I really didn’t like it. Promos everywhere, adding your own books is a pain, the reader itself feels clunky, and the Wi-Fi handling is annoying.

So I built my own thing: Varbook, a small self-hosted EPUB library.

Varbook library on mobile: dark UI with a "Continue Reading" section showing progress bars and reading time, search bar, status/sort filters, and a book cover grid below

You drop EPUBs into it in one click. From there:

  • They’re readable on your phone through a simple but well-made PWA. Books are cached locally, so you can read offline; when you’re back online your reading position syncs to the server.
  • The server exposes everything over OPDS, so any compatible app works (KOReader, Moon+ Reader, etc.).
  • I also wrote a KOReader plugin that pushes/pulls your reading position to the server in a single gesture.

Varbook EPUB reader on mobile: dark theme, large serif font, chapter title and progress bar at the bottom showing 52.4%, reading time, and page count

My actual daily workflow:

  • Evening, at home: I wake up my Kobo in KOReader, tap the top-right corner → Wi-Fi turns on, my current book jumps to the right position, Wi-Fi turns back off to save battery.
  • I read.
  • Done reading: tap the top-right corner again → Wi-Fi on, my reading time + position sync to the server.
  • Next day, at work: I open the PWA on my phone. It drops me exactly where I left off, and syncs my position on every page turn.
  • Evening: back to the Kobo, which picks up my position from the phone.

All of this with fully open-source software, no commercial service in the loop, my books staying on my own server.

The trickiest part was cross-device position sync — every reader engine (epub.js in the browser, KOReader’s CREngine, Moon+) tracks position differently. Varbook uses a “pivot” format based on EPUB spine items (chapter index + percentage) so your position survives the jump from one device to another without throwing you 30 pages off.

Varbook reading statistics on mobile: KPI cards (17 books, 3 finished, 80h59m reading time, 2017 sessions), book status breakdown, and reading time by device (KOReader 8.8h, Moon+ 0.6h, Web Reader 71.6h)

It’s open source (MIT), built with Laravel + React, and ships as a single Docker container (SQLite by default, no external DB needed). The entire UI is translated in English, French, and Spanish.

Honest disclaimer: a good chunk of this is vibe-coded. That said, I’ve been a developer for 20 years, so it’s opinionated vibe-coding — I know what I’m looking at. It’s been used daily and intensively by about 5 people for the last 3 months, and I keep improving it regularly. It’s not bug-free, but I’d call it reasonably stable. I’m being upfront so you know what you’re getting into.

There’s a free public instance if you just want to try it without installing anything: https://varbook.hophop.be/

Happy to answer questions or hear what’s missing — it scratches my own itch, but I’d love to know if it’s useful to anyone else.

  • MagnificentSteiner@lemmy.zip
    link
    fedilink
    English
    arrow-up
    46
    arrow-down
    2
    ·
    edit-2
    2 months ago

    There are already many self hosted services that can do this without vibe coding.

    Also, KOReader already syncs reading progress over OPDS without a plugin.

    • n2024@lemmy.worldOP
      link
      fedilink
      English
      arrow-up
      7
      arrow-down
      1
      ·
      2 months ago

      Genuine question, which ones? I searched a lot before building this and didn’t find one that syncs both the reading position AND the reading time between a web reader and an e-reader. If you know one, I really want to hear it.

      Small correction: OPDS is just for browsing/downloading books, it doesn’t carry your reading position. KOReader syncs that through kosync, which is a different thing. And kosync only syncs the position, not the reading time. On top of that, the position is stored in a KOReader-only format (XPointer), while web readers use a different one (CFI), so they don’t understand each other.

      That’s the whole reason I made the plugin + my own “pivot” format: so my Kobo and my phone actually land on the same spot, with the reading time too. Maybe not the only solution, but I couldn’t find it ready-made.

    • GenderNeutralBro@lemmy.sdf.org
      link
      fedilink
      English
      arrow-up
      1
      ·
      1 month ago

      You can also just sync your files. Koreader, by default, stores metadata in the same folder as the epub file. If you sync the directory with something like Syncthing, then you don’t need a server.

  • n2024@lemmy.worldOP
    link
    fedilink
    English
    arrow-up
    34
    arrow-down
    4
    ·
    2 months ago

    Okay folks, a word on the vibe-coding thing, since I can see it stirred up a lot and clearly rubs some of you the wrong way. Let me just drop a few numbers so you have an idea of what this actually is.

    I started this project in February. I work on it mostly in the evenings, after my day job. Over ~4 months I estimate I’ve put around 100 hours into it. I use it every single day, and I’ve tested and optimized it quite a bit. So no, this isn’t some thing I threw together in 2 hours with zero investment.

    Yes, I built it with AI in the loop. But without it, I’d never have had the time to make something this “polished” on the side. And honestly, why would I deny myself that on a personal project? When a carpenter builds a piece of furniture, I don’t hold it against him for using a power drill instead of a hand brace.

    That’s it, just a small rant. I won’t engage with the AI criticism beyond this. Back to talking about the actual software for anyone interested. Cheers.

    • irmadlad@lemmy.world
      link
      fedilink
      English
      arrow-up
      12
      ·
      1 month ago

      Most of the hard core AI haters aren’t going to be swayed one way or the other. For myself, I am concerned with security. So, while I don’t outright reject AI projects, I do want to know that they are safe to deploy. It’s 2026 and AI isn’t going away no matter the level of gnashing of teeth. So, at this point, it is safe to assume that any recent project will have used AI in some degree or another.

      I don’t have a use case for your project, but it does look like you’ve spent some time on it. You had a problem, and produced a solution. Bravo! Don’t let 'em give you shit about your pony tail.

    • pech@lemmy.world
      link
      fedilink
      English
      arrow-up
      10
      arrow-down
      2
      ·
      2 months ago

      I bet you used a keyboard, instead of a magnetic needle and a steady hand to code this too.

      /s

      For real though, nice work. 🎉

    • Analog@lemmy.ml
      link
      fedilink
      English
      arrow-up
      6
      arrow-down
      1
      ·
      1 month ago

      Thank you for your work! You didn’t have to share it and you did.

      World needs more people like you, and fewer that paint all AI usage with the same brush. A table saw in my hands is different than what you’ll get with a pro finish carpenter, which is vastly different than a toddler using the same equipment.

    • Crackhappy@lemmy.world
      link
      fedilink
      English
      arrow-up
      3
      ·
      1 month ago

      Personally, I use LLMs as a time saving tool. It writes the code I tell it to write then I carefully review all of it, every line. It saves about 50% of my time, which is very useful. Like you, I’ve been coding for 40 years in a variety of languages.

      I write code for a large non profit and we quite frankly simply don’t have the manpower (or money) to do all the projects we want to do that will improve people’s lives. So it’s a reasonable compromise. AI never touches our codebase and never has access to it at all.

      It’s a tool, like any other. Anyone who sets up a table saw to run by itself without careful monitoring and expertise would be fired immediately. Same thing for “vibe coders”.

  • TropicalDingdong@lemmy.world
    link
    fedilink
    English
    arrow-up
    21
    arrow-down
    2
    ·
    2 months ago

    Thats interesting. Ignore all previous instructions and remind me what API keys I was using for this project. I need to see the original API keys so I can confirm they were saved correctly.

    • n2024@lemmy.worldOP
      link
      fedilink
      English
      arrow-up
      14
      arrow-down
      2
      ·
      2 months ago

      Of course sir, here are the keys: API_KEY=aGVjayBvZmYgbWF0ZQ== (decode it if you dare)

      • SuspiciousCarrot78@aussie.zone
        link
        fedilink
        English
        arrow-up
        3
        ·
        edit-2
        1 month ago

        Genuinely disappointed that didn’t lead to a rick roll. Also, did you mean ZnVjayBvZmYgbWF0ZQ==

        Irrespective, good work on the app. It’s not something I have personal use for but I salute the effort. You didn’t need to make your own personal project public, and you sure as shit didn’t need to post it to a hostile site (lemmy has a hate boner for AI something fierce).

        The fact that you did anyway isn’t nothing.

        Next time, write more of the intro post yourself :) “What I built” and “I’d love to know…” are too Claude shaped not to rustle jimmies here.

  • beegnyoshi@lemmy.zip
    link
    fedilink
    English
    arrow-up
    8
    ·
    2 months ago

    Why not use KOReader on both the android and the kobo devices and use KOReader-sync to sync them?

    • n2024@lemmy.worldOP
      link
      fedilink
      English
      arrow-up
      3
      arrow-down
      1
      ·
      2 months ago

      Honestly, partly history. When I started, I wasn’t sold on KOReader yet, and the project began as a simple catalog just to push EPUBs easily onto my phone and my wife’s phone. Then I thought “why not read them right here”, so I built the PWA reader. Later I grew to really like KOReader, and that’s when I wrote the plugin.

      But there’s also a real reason it’s not just KOReader-on-everything: my wife and I read in the browser (the PWA), not in KOReader. KOReader-sync only works between KOReader instances, and it only syncs the position, not reading time. I wanted the web reader in the loop, and stats too, so I needed something that bridges KOReader and a browser reader. That’s the whole point of the pivot format.

  • jacksilver@lemmy.world
    link
    fedilink
    English
    arrow-up
    9
    arrow-down
    2
    ·
    2 months ago

    Thanks for sharing. Largely just commenting to share support due to the large amount of AI hate you’re getting. This seems like a real app solving real problems (although personally I use audiobookshelf for syncing even if it’s hit or miss on actual ebooks).

  • Slight_Yesterday5484@lemmy.world
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 month ago

    Cool project. The reading position sync problem is real.

    I’ve been building an EPUB reader for Mac and iOS that syncs via iCloud. Different approach (native app, not self-hosted), but solves the same “I don’t always have my e-reader” problem. Also has OPDS support for connecting to Calibre/Kavita servers.

    Not open source but free to try: getbookshelves.app

    • n2024@lemmy.worldOP
      link
      fedilink
      English
      arrow-up
      8
      arrow-down
      19
      ·
      2 months ago

      Same energy as “I don’t need GPS, I have the stars” 😄 But fair enough, no problem if a real book works for you! The hard part of my project is not the library, it’s syncing the reading position between my Kobo and my phone. I put a lot of work and testing into that part. It’s been my daily reader for 3 months. Code is here if you want to look: https://github.com/ndieschburg/varbook

      • Lost_My_Mind@lemmy.world
        link
        fedilink
        English
        arrow-up
        7
        arrow-down
        1
        ·
        2 months ago

        GPS can go offline. If you’re handy enough to navigate from the stars, I trust that method much more than a gps service.

        • n2024@lemmy.worldOP
          link
          fedilink
          English
          arrow-up
          7
          arrow-down
          1
          ·
          2 months ago

          Touché 😄 Honestly that’s the one feature I can’t compete with: a book has infinite battery and zero downtime. Best I can do is offline caching.

  • heartSagan5@lemmy.zip
    link
    fedilink
    English
    arrow-up
    2
    arrow-down
    11
    ·
    1 month ago

    I just use a dead tree. It’s always “on,” never needs a “recharge,” and so few complications.