Wallabako 1.4.0 released
I don't particularly like it when people announce their personal projects on their blog, but I'm making an exception for this one, because it's a little special for me.
You see, I have just released Wallabako 1.4.0 (and a quick, mostly irrelevant 1.4.1 hotfix) today. It's the first release of that project in almost 3 years (the previous was 1.3.1, before the pandemic).
The other reason I figured I would mention it is that I have almost never talked about Wallabako on this blog at all, so many of my readers probably don't even know I sometimes meddle with in Golang which surprises even me sometimes.
What's Wallabako
Wallabako is a weird little program I designed to read articles on my E-book reader. I use it to spend less time on the computer: I save articles in a read-it-later app named Wallabag (hosted by a generous friend), and then Wallabako connects to that app, downloads an EPUB version of the book, and then I can read it on the device directly.
When I'm done reading the book, Wallabako notices and sets the article as read in Wallabag. I also set it to delete the book locally, but you can actually configure to keep those books around forever if you feel like it.
Wallabako supports syncing read status with the built-in Kobo interface (called "Nickel"), Koreader and Plato. I happen to use Koreader for everything nowadays, but it should work equally well on the others.
Wallabako is actually setup to be started by udev
when there's a
connection change detected by the kernel, which is kind of a gross
hack. It's clunky, but actually works and I thought for a while about
switching to something else, but it's really the easiest way to go,
and that requires the less interaction by the user.
Why I'm (still) using it
I wrote Wallabako because I read a lot of articles on the internet. It's actually most of my readings. I read about 10 books a year (which I don't think is much), but I probably read more in terms of time and pages in Wallabag. I haven't actually made the math, but I estimate I spend at least double the time reading articles than I spend reading books.
If I wouldn't have Wallabag, I would have hundreds of tabs open in my web browser all the time. So at least that problem is easily solved: throw everything in Wallabag, sort and read later.
If I wouldn't have Wallabako however, I would be either spend that time reading on the computer -- which I prefer to spend working on free software or work -- or on my phone -- which is kind of better, but really cramped.
I had stopped (and developing) Wallabako for a while, actually, Around 2019, I got tired of always read those technical articles (basically work stuff!) at home. I realized I was just not "reading" (as in books! fiction! fun stuff!) anymore, at least not as much as I wanted.
So I tried to make this separation: the ebook reader is for cool book stuff. The rest is work. But because I had the Wallabag Android app on my phone and tablet, I could still read those articles there, which I thought was pretty neat. But that meant that I was constantly looking at my phone, which is something I'm generally trying to avoid, as it sets a bad example for the kids (small and big) around me.
Then I realized there was one stray ebook reader lying around at home. I had recently bought a Kobo Aura HD to read books, and I like that device. And it's going to stay locked down to reading books. But there's still that old battered Kobo Glo HD reader lying around, and I figured I could just borrow it to read Wallabag articles.
What is this new release
But oh boy that was a lot of work. Wallabako was kind of a mess: it was using the deprecated go dep tool, which lost the battle with go mod. Cross-compilation was broken for older devices, and I had to implement support for Koreader.
go mod
So I had to learn go mod
. I'm still not sure I got that part right:
LSP is yelling at me because it can't find the imports, and I'm
generally just "YOLO everythihng" every time I get anywhere close
to it. That's not the way to do Go, in general, and not how I like to
do it either.
But I guess that, given time, I'll figure it out and make it work for me. It certainly works now. I think.
Cross compilation
The hard part was different. You see, Nickel uses SQLite to store metadata about books, so Wallabako actually needs to tap into that SQLite database to propagate read status. Originally, I just linked against some sqlite3 library I found lying around. It's basically a wrapper around the C-based SQLite and generally works fine. But that means you actually link your Golang program against a C library. And that's when things get a little nutty.
If you would just build Wallabag naively, it would fail when deployed
on the Kobo Glo HD. That's because the device runs a really old
kernel: the prehistoric Linux kobo 2.6.35.3-850-gbc67621+ #2049
PREEMPT Mon Jan 9 13:33:11 CST 2017 armv7l GNU/Linux
. That was built
in 2017, but the kernel was actually released in 2010, a whole 5
years before the Glo HD was released, in 2015 which is kind of
outrageous. and yes, that is with the latest firmware release.
My bet is they just don't upgrade the kernel on those things, as the Glo was probably bought around 2017...
In any case, the problem is we are cross-compiling here. And Golang is pretty good about cross-compiling, but because we have C in there, we're actually cross-compiling with "CGO" which is really just Golang with a GCC backend. And that's much, much harder to figure out because you need to pass down flags into GCC and so on. It was a nightmare.
That's until I found this outrageous "little" project called modernc.org/sqlite. What that thing does (with a hefty does of dependencies that would make any Debian developer recoil in horror) is to transpile the SQLite C source code to Golang. You read that right: it rewrites SQLite in Go. On the fly. It's nuts.
But it works. And you end up with a "pure go" program, and that thing compiles much faster and runs fine on older kernel.
I still wasn't sure I wanted to just stick with that forever, so I
kept the old sqlite3 code around, behind a compile-time tag. At the
top of the nickel_modernc.go
file, there's this magic string:
//+build !sqlite3
And at the top of nickel_sqlite3.go
file, there's this magic string:
//+build sqlite3
So now, by default, the modernc
file gets included, but if I pass
--tags sqlite3
to the Go compiler (to go install
or whatever), it
will actually switch to the other implementation. Pretty neat stuff.
Koreader port
The last part was something I was hesitant in doing for a long time, but that turned out to be pretty easy. I have basically switch to using Koreader to read everything. Books, PDF, everything goes through it. I really like that it stores its metadata in sidecar files: I synchronize all my books with Syncthing which means I can carry my read status, annotations and all that stuff without having to think about it. (And yes, I installed Syncthing on my Kobo.)
The koreader.go port was less than 80 lines, and I could even make a nice little test suite so that I don't have to redeploy that thing to the ebook reader at every code iteration.
I had originally thought I should add some sort of graphical interface in Koreader for Wallabako as well, and had requested that feature upstream. Unfortunately (or fortunately?), they took my idea and just ran with it. Some courageous soul actually wrote a full Wallabag plugin for koreader, in Lua of course.
Compared to the Wallabako implementation however, the koreader plugin is much slower, probably because it downloads articles serially instead of concurrently. It is, however, much more usable as the user is given a visible feedback of the various steps. I still had to enable full debugging to diagnose a problem (which was that I shouldn't have a trailing slash, and that some special characters don't work in passwords). It's also better to write the config file with a normal text editor, over SSH or with the Kobo mounted to your computer instead of typing those really long strings over the kobo.
There's no sample config file which makes that harder but a workaround is to save the configuration with dummy values and fix them up after. Finally I also found the default setting ("Remotely delete finished articles") really dangerous as it can basically lead to data loss (Wallabag article being deleted!) for an unsuspecting user...
So basically, I started working on Wallabag again because the koreader implementation of their Wallabag client was not up to spec for me. It might be good enough for you, but I guess if you like Wallabako, you should thank the koreader folks for their sloppy implementation, as I'm now working again on Wallabako.
Actual release notes
Those are the actual release notes for 1.4.0.
Ship a lot of fixes that have accumulated in the 3 years since the last release.
Features:
- add timestamp and git version to build artifacts
- cleanup and improve debugging output
- switch to pure go sqlite implementation, which helps
- update all module dependencies
- port to wallabago v6
- support Plato library changes from 0.8.5+
- support reading koreader progress/read status
- Allow containerized builds, use gomod and avoid GOPATH hell
- overhaul Dockerfile
- switch to
go mod
Documentation changes:
- remove instability warning: this works well enough
- README: replace branch name master by main in links
- tweak mention of libreoffice to clarify concern
- replace "kobo" references by "nickel" where appropriate
- make a section about related projects
- mention NickelMenu
- quick review of the koreader implementation
Bugfixes:
- handle errors in http request creation
- Use OutputDir configuration instead of hardcoded wallabako paths
- do not noisily fail if there's no entry for book in plato
- regression: properly detect read status again after koreader (or plato?) support was added
How do I use this?
This is amazing. I can't believe someone did something that awesome. I want to cover you with gold and Tesla cars and fresh water.
You're weird please stop. But if you want to use Wallabako, head over
to the README file which has installation instructions. It
basically uses a hack in Kobo e-readers that will happily overwrite
their root filesystem as soon as you drop this file named
KoboRoot.tgz in the .kobo
directory of your e-reader.
Note that there is no uninstall procedure and it messes with the
reader's udev
configuration (to trigger runs on wifi
connect). You'll also need to create a JSON configuration file
and configure a client in Wallabag.
And if you're looking for Wallabag hosting, Wallabag.it offers a 14-day free trial. You can also, obviously, host it yourself. Which is not the case for Pocket, even years after Mozilla bought the company. All this wouldn't actually be necessary if Pocket was open-source because Nickel actually ships with a Pocket client.
Shame on you, Mozilla. But you still make an awesome browser, so keep doing that.
Thank you for the update, I've encountered wallabako some month back and really like it.
My motivation and setup for using it is similar to yours. However, I'm using wallabako als cli on OpenBSD and save epubs to a syncthing share that is connected with my pocketbook reader.
Keep going.