|
|||||||
![]() |
|
|
Thread Tools | Search this Thread |
|
|
#1 |
|
Junior Member
![]() Posts: 1
Karma: 10
Join Date: Jun 2026
Device: Clara
|
Worked out the Kobo Event.Checksum (and how to restore reading stats)
This is about reading and editing the local analytics database (KoboReader.sqlite) on a Kobo you own, to back up and restore your own reading stats.
I sideload books, and a book's reading stats can get orphaned when its file path (its ContentID) changes, when it's deleted and re-added, or when you move to a new device. Wanting to back them up and put them back led me to the Checksum column in KoboReader.sqlite — the thing that's blocked editing these tables for years — and I worked out how it's computed. Posting it as I believe it's useful. The short version The Checksum on the Event table (and on AbTest, Rules, and Achievement) is: Code:
Checksum = md5( <every column except Checksum, in alphabetical order by column name,
values concatenated as raw bytes, NULL -> nothing> + "kobo.rules" )
The salt is a literal string: the 10 ASCII characters kobo.rules. Where I put it in quotes below, the quotes are just delimiters, not part of the data. Those 10 bytes get appended to the row's bytes and the whole lot is MD5'd, with no key or length prefix or separator in between. The exact recipe
Code:
Event.Checksum = md5( ContentID + str(EventCount) + str(EventType) + ExtraData_bytes
+ FirstOccurrence + LastOccurrence + "kobo.rules" )
Code:
import hashlib, sqlite3
def event_checksum(ContentID, EventCount, EventType, ExtraData,
FirstOccurrence, LastOccurrence):
def b(x):
if x is None: return b""
if isinstance(x, bytes): return x
return str(x).encode()
msg = (b(ContentID) + b(EventCount) + b(EventType) + b(ExtraData)
+ b(FirstOccurrence) + b(LastOccurrence) + b"kobo.rules")
return hashlib.md5(msg).hexdigest()
Copy your own KoboReader.sqlite off the device (it's at .kobo/KoboReader.sqlite) and run this against it. If it prints N/N, the algorithm holds on your firmware too: Code:
con = sqlite3.connect("KoboReader.sqlite")
ok = tot = 0
for et, fo, lo, ec, cid, ed, ck in con.execute(
"SELECT EventType, FirstOccurrence, LastOccurrence, EventCount, ContentID, "
"CAST(ExtraData AS BLOB), Checksum FROM Event WHERE Checksum IS NOT NULL"):
tot += 1
ok += event_checksum(cid, ec, et, ed, fo, lo) == ck
print(f"{ok}/{tot} match") # should print N/N - every row matches (tested on fw 4.45.x)
What it unblocks: the per-book stats page The per-book stats screen doesn't read content.TimeSpentReading. It reads fields out of the Event ExtraData blob. All three numbers (device-confirmed): Code:
hours of reading = ExtraDataReadingSeconds / 3600 avg minutes per session = ExtraDataReadingSeconds / 60 / ExtraDataReadingSessions avg pages per minute = EventType-46.EventCount / (ExtraDataReadingSeconds / 60) To restore a book's stats, overwrite those two ints in both the type-46 and type-3 ExtraData blobs (they're fixed-size, so it's a 4-byte in-place poke), set the type-46 EventCount for the pages/min number, and recompute each row's Event.Checksum. I tested the whole thing on-device: the patched numbers appear on reboot, and reading the book afterward adds to the restored values instead of resetting them. That also makes it automatable. Kobo Utilities already backs up KoboReader.sqlite and restores content.TimeSpentReading, but it doesn't write the checksum-guarded Event rows the stats page reads, so the time it restores never appears on that screen. With a working Event.Checksum, storing and restoring the Event stat fields is well within what the plugin already does. Reading position and content.TimeSpentReading were already writable; the Event stat fields were the missing piece. With those, a book's whole reading history — time spent, sessions, pages per minute, and where you left off — can be backed up and restored as a unit, whether you're re-sending the book or moving to a new device, instead of getting it back in pieces. Notes
|
|
|
|
![]() |
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Aura H2O 2 KoboReader.sqlite - Event - Reading Stats | Karmylla | Kobo Reader | 17 | 08-13-2025 11:15 AM |
| Kobo Reading Stats | ChooChoo | Kobo Reader | 3 | 09-03-2023 06:13 AM |
| Get reading stats and highlights from old kobo | yur | Kobo Reader | 2 | 11-14-2022 03:01 PM |
| Kobo Reading Life stats not updating | pastaenthusiast | Kobo Reader | 29 | 10-13-2016 11:32 AM |
| Help with Kobo reading stats | MandyMill | Kobo Reader | 16 | 01-12-2015 09:35 AM |