I read every day but rarely have my e-reader on me — so I built a self-hosted EPUB library that syncs my reading position between my Kobo and my phone (varbook.hophop.be)
from n2024@lemmy.world to selfhosted@lemmy.world on 11 Jun 20:52
https://lemmy.world/post/48051053

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:

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:

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: 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.

#selfhosted

threaded - newest

Bluegrass_Addict@lemmy.ca on 11 Jun 21:30 next collapse

I just use a book

edit: ohh this is more vibecoded slop. nevermind…

n2024@lemmy.world on 11 Jun 22:01 collapse

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: github.com/ndieschburg/varbook

Lost_My_Mind@lemmy.world on 11 Jun 22:18 collapse

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.world on 11 Jun 22:27 collapse

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.

TropicalDingdong@lemmy.world on 11 Jun 21:53 next collapse

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.world on 11 Jun 22:04 collapse

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

MagnificentSteiner@lemmy.zip on 11 Jun 22:02 next collapse

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.world on 11 Jun 22:14 collapse

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.

EncryptKeeper@lemmy.world on 11 Jun 22:25 next collapse

Book Orbit just added this functionality in the latest release. Grimmory I believe has this too.

n2024@lemmy.world on 11 Jun 22:52 next collapse

Yeah they look great. One thing I focused on that I haven’t seen in them: a real offline-first PWA, books cached locally so I can read with no signal, and it syncs back when I’m online. That’s my main daily use case (train, no wifi), so it’s the part I cared most about.

null@piefed.nullspace.lol on 11 Jun 23:05 collapse

without vibe coding

EncryptKeeper@lemmy.world on 12 Jun 12:53 collapse

These are forks of BookLore, which was the vibecoded one.

null@piefed.nullspace.lol on 12 Jun 14:07 collapse

Not true for Bookorbit.

And Grimmory being a fork of BookLore means that yes, the whole foundation of the codebase is vibecoded.

MagnificentSteiner@lemmy.zip on 11 Jun 23:06 collapse

Kavita and Calibre afaik

Here’s a screenshot from my Kavita activity feed synced with KOReader on my Kobo (also works with KOReader on my android phone)

<img alt="" src="https://lemmy.zip/pictrs/image/3aef2fc5-52ac-44cd-8ad3-64b6ee85409a.avif?format=webp">

ragingHungryPanda@piefed.keyboardvagabond.com on 11 Jun 23:57 next collapse

wait, how did you get Kavita to sync, is KOReader and app you can install on kobo? kobo can do apps?

SatyrSack@quokk.au on 12 Jun 04:06 next collapse

It is not just installing an app. It is more like flashing an alternate operating system entirely. Hopefully that does not sound too intimidating, because it is well worth it.

https://github.com/koreader/koreader/wiki/Installation-on-Kobo-devices

Anivia@feddit.org on 12 Jun 08:01 next collapse

KOReader can be installed on almost any e-reader, even Kindles. Although installing kt on a Pocketbook reader would of course be the superior option over a Kobo 😉 github.com/koreader/koreader

It does have a learning curve though, definitely aimed at powerusers

MagnificentSteiner@lemmy.zip on 12 Jun 08:40 collapse

Here’s how to install KOReader on Kobo

github.com/…/Installation-on-Kobo-devices

Here’s the Kavita wiki page about KOReader that includes how to set up progress sync

wiki.kavitareader.com/guides/3rdparty/koreader/

ikidd@lemmy.dbzer0.com on 12 Jun 01:23 next collapse

Calibre doesn’t sync reading position.

whysofurious@lemmy.dbzer0.com on 12 Jun 12:58 collapse

Also Komga works pretty well with Koreader. I moved my books from Kavita to Komga and I found it to be more reliable regarding the two-way syncing progress (at least for me).

i_stole_ur_taco@lemmy.ca on 11 Jun 22:19 next collapse

How do you reconcile the Kobo wanting to sync reading position every time you turn it on? Or is that not a problem with your workflow?

I have issues in my own app and some other containers where the kobo is slow to upload reading stats, so every time my kobo wakes up, it throws up a dialog asking if I want to skip to my latest reading position. If I pick yes, it dumps me back 10-20 pages.

It’s easy enough to say no but it’s so annoying to have a delayed dialog every time I wake the thing up.

n2024@lemmy.world on 11 Jun 22:24 collapse

Not a problem for me, because my sync is manual, not automatic. I assigned it to a gesture (tap the top-right corner): wifi on, sync, done. Waking the device doesn’t trigger anything, so I never get that “jump to latest position?” dialog.

I did it this way mainly for battery, I don’t want wifi turning on every time the Kobo wakes up. And I push my position at the end of my reading, so the server is always up to date and there’s nothing stale to pull next time.

I did think about auto-syncing when you open a book, but haven’t done it yet, partly for the reasons you mention. For now the manual gesture works well for me.

bfg9k@lemmy.world on 11 Jun 22:39 next collapse

Why not just use Audiobookshelf? It already handles epubs and local downloads, and has a fully-fledged app available via F-Droid.

Plus it’s not AI-coded slop.

Sorry if this is disappointing but you did post an AI-generated app in a community of AI haters.

mushroommunk@lemmy.today on 11 Jun 22:57 next collapse

And if one of the many amazing open source projects don’t do what you want, make a few of them better rather than spinning off yet another slop app that does the same thing that will split people and support.

n2024@lemmy.world on 11 Jun 22:59 next collapse

Thanks for the suggestion. I know Audiobookshelf, but it’s audiobook-first and the EPUB side is basic, it doesn’t do the KOReader ↔ web position sync I built this for. And no worries about the AI part, I was upfront in the post on purpose. You don’t have to use it or like it. I built it for myself, it works for me every day, and I shared it in case it’s useful to someone else. That’s all.

ikidd@lemmy.dbzer0.com on 12 Jun 01:26 collapse

Don’t let the anti-AI bullshit get you down. You built something that worked for you, it isn’t the basis of national security for everyone and you wanted to share it. And you opensourced it so if I want to bolt on an IRC downloader or something, it’s easy.

I appreciates you.

pogmommy@lemmy.ml on 12 Jun 02:18 collapse

You built something

Debatable

ikidd@lemmy.dbzer0.com on 12 Jun 05:04 collapse

Just can’t resist eh.

I have an old seed drill and the ECU smoked itself last fall. $6000-8000 if I can find a used one and then wait for it to show up, hopefully it works.

Pulled out Hermes on GPT5.5, spent the weekend building a DIY unit that monitors shaft and airspeeds, controls clutches, and gives me a browser page that I can watch all that stuff. I’m currently sitting in the tractor and waiting for it to build me a new feature I didn’t have on the old monitor where I can manually enter acres done.

<img alt="captured_image1037892746433104354" src="https://lemmy.dbzer0.com/pictrs/image/3897622e-dd30-4d29-a386-d573be867f18.webp">

It would have taken me months to build this and I’d have done nothing but work on that. Now I can tweak this while I work, or even access it remotely and change things if someone else is using it.

People can get on their high horse all they want, it cost me almost nothing to build something I can modify as I wish now. AI has democratized software. Hate it all you want, it works.

B0rax@feddit.org on 12 Jun 05:53 next collapse

Nice project!

GreenKnight23@lemmy.world on 12 Jun 06:46 next collapse

AI has democratized software.

<img alt="lol" src="https://c.tenor.com/zkoIACGvSEIAAAAd/tenor.gif">

n2024@lemmy.world on 12 Jun 08:03 next collapse

This is the perfect example, honestly. Same spirit: a real problem, solved fast with the tool in hand. Hope the acres-done feature compiles before you finish the field 😄

ikidd@lemmy.dbzer0.com on 12 Jun 14:24 collapse

What’s cool is that I can watch it build the feature in another page (actually, I have a ttyd session in the app so I can bring up a terminal on the Pi to work with Hermes or Opencode) and it will run pytests against a test instance of the service, then swap it into the production files and restart the service. I get about 2 seconds of disconnect where the cards don’t update, and then I refresh the browser and it’s live. If I don’t like it, I can tell it to revert to the earlier commit or change things. It’s magical.

Then I blew a hydraulic hose and went to bed. AI can’t help me with that.

Natanox@discuss.tchncs.de on 12 Jun 11:00 next collapse

AI has democratized software.

If you mean that everyone can now build something that most likely will fall apart in the future, where nobody knows what’s actually inside as nobody reads it, where you might get hit with copyright claims because you stole code willy-nilly (you can’t hide behind the AI, you did it), that is full of security issues as well as structural nonsense and you may never know if the LLM decides to delete everything star anew while blasting a 6000€ hole in your pocket doing do…

…well then yes, it “democratized” something.

[deleted] on 12 Jun 14:57 collapse
.
irmadlad@lemmy.world on 12 Jun 13:21 collapse

old seed drill

The 'ol Jethro Tull

irmadlad@lemmy.world on 11 Jun 23:16 collapse

community of AI haters.

Didn’t down vote…but not all of us are AI haters. A lot of us also have the unique ability to actually scroll right on by things we are uninterested in without leaving castigating remarks. If I were to launch into a diatribe every time someone mentioned the 'arr stack in here, I think most of you would be like 'Hey man, how about giving it a rest. We get it. You don’t like the ‘arr stack’, and you’d have a valid point.

my 2p

carotte@lemmy.blahaj.zone on 12 Jun 02:29 next collapse

I built

yeah right

kaotic@lemmy.world on 12 Jun 02:54 collapse

He literally calls out a good portion was vibe coded.

gedaliyah@lemmy.world on 12 Jun 02:30 next collapse

Anx reader syncs stats and position across devices in this way, but I don’t think it runs on the kobo reader.

jacksilver@lemmy.world on 12 Jun 02:50 next collapse

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).

SmackemWittadic@lemmy.world on 12 Jun 02:52 next collapse

Count the em dashs in this post, clanker

chairmarker@piefed.zip on 12 Jun 03:18 next collapse

This looks pretty good. I’ve been wanting to set up something similar, so I’ll give it a try. Does this support other file types, like cbz?

n2024@lemmy.world on 12 Jun 15:11 collapse

Thanks, glad it speaks to you! Right now it’s EPUB-only. That was my own need, and the whole thing is really built around book reading (reader, fonts, cross-device position sync, reading stats), so I focused on doing that one format well rather than handling everything.

CBZ/comics would need a different reader and a different idea of “reading position”, so it’s not on the roadmap for now. But if you give it a try, I’d love to hear how it goes.

beegnyoshi@lemmy.zip on 12 Jun 07:26 next collapse

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

n2024@lemmy.world on 12 Jun 15:23 collapse

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.

n2024@lemmy.world on 12 Jun 15:37 collapse

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.

pech@lemmy.world on 12 Jun 15:51 collapse

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. 🎉