Simplifying PDF imports on reMarkable
By Kunal MehtaI've been using my reMarkable 2 a lot more recently, and have gotten started with actually hacking on it. It's a bit overdue, since the main reason I purchased it in the first place was that it is built on top of Linux and doesn't require any special jailbreaking/rooting.
I found Adrian Daerr's script to import PDFs/EPUBs into a reMarkable, which is surprisingly not a straightforward operation.
You need to rename the file to use a UUID as its name, create corresponding .metadata
and .content
files, and then empty .cache
, .highlights
, and .thumbnails
directories.
Daerr's bash script does all of this, except it runs on a different machine, and then scp
s the files over to the reMarkable. Modifying it to run on the reMarkable itself didn't seem too complicated, but I try to avoid writing shell scripts as much as possible, so I took the opportunity to port it to Rust.
I first asked Claude to port it to Rust, and, probably for the first time, I was disappointed by the result.
Specifically, it generated:
if args[1] == "-r" {
restart_xochitl = !config.restart_xochitl_default;
files_start_index =, 2;
}
I couldn't come up with a reason on why Claude would insert a comma after the equals sign (it's not really a hallucination I think?), but rust-analyzer flagged it as a syntax error right away.
I deleted most of that code anyways since I wanted to unconditionally restart, and also use camino instead. As an aside, std::path
represents paths with OsString
, which is incredibly inconvenient to use anywhere else, which'll expect normal UTF-8 String
s. camino
only supports paths that are fully UTF-8 (aka String
instead of OsString
), which should be fine for most projects that don't need to support legacy files and encodings, like this one.
Next, I had to cross-build it for the reMarkable's ARM v7 CPU. I've done it before for Raspberry Pis, but since it's been a while, I wanted to try out the cross
tool, which transparently builds in a container with the necessary toolchains. And if you set a little bit of metadata, it's as simple as cross build --release
.
To make the newly imported file actually show up in the reMarkable file listing, you apparently have to restart the entire thing, which does work, but surely there's a better way to tell it to look for new files...
Finally, to actually make use of it, I set up rclone to automatically fetch a folder from my Nextcloud instance, and then run rm-import
over it. And now I can drop a PDF in a dedicated Nextcloud folder, and it'll end up on my reMarkable!