Register Guidelines E-Books Today's Posts Search

Go Back   MobileRead Forums > E-Book Formats > ePub

Notices

Reply
 
Thread Tools Search this Thread
Old Yesterday, 10:53 AM   #1
Kayadelenium
Connoisseur
Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!
 
Posts: 57
Karma: 100000
Join Date: Jul 2026
Location: Planet Earth
Device: Kobo Forma
epubsana — automatic repair for what epubcheck reports (not an editor)

Some of you have been putting epubveri through its paces in PeterT's thread, and nearly every false positive fixed since 0.5.15 came from that — real books finding what fixtures can't. Thank you. I'd like to try the same thing for the other half.

epubsana repairs the defects epubveri reports. epubveri says what's wrong; epubsana turns the safely-fixable findings into edits you approve one at a time, applies them, and prints a report of exactly what changed.

What it is not: it is not an editor and it is not trying to become one. It has no UI for writing markup, no preview, no book view. Sigil and calibre are where you edit a book; epubsana is meant to clear the mechanical, boring defects before you open it there, so the errors you're left staring at are the ones that actually need a human. If it ever competes with an editor, I've made a mistake.

Three ways to try it
  • In your browser, nothing installed: https://veripublica.github.io/epubsana/ — the file never leaves the page; it's WebAssembly running locally, not an upload.
  • CLI:
    Code:
    cargo install epubsana
    , or prebuilt binaries for Windows/macOS/Linux on the releases page.
  • Library: Rust crate
    Code:
    epubsana
    , or npm
    Code:
    @veripublica/epubsana-wasm
    .

Why it's safe to point at a real book
  • It never writes in place. Output goes to
    Code:
    <name>_fixed.epub
    , and it refuses outright if you aim the output at the input.
  • Code:
    --dry-run
    shows you every proposed fix and changes nothing.
  • Every fix is confirmed one at a time by default, with a plain-English rationale for each, and the run ends with a report of what was changed and what was left alone.
  • It re-validates the result, so the report's before/after numbers are measured, not claimed.

What it refuses, and why that's the interesting part

A repairer that guesses is worse than no repairer. Some examples of things it will not do:
  • An
    Code:
    <img>
    with no
    Code:
    alt
    .
    Code:
    alt=""
    is correct for a decorative image and wrong for a meaningful one, and nothing in the file says which. Inventing alt text is an accessibility bug that looks like a fix.
  • A malformed date. It removes an empty
    Code:
    <dc:date>
    , but leaves
    Code:
    2022-09-08)
    alone — that's a date the author wrote, and deciding which characters are stray is a guess.
  • An empty title. It fills
    Code:
    <title></title>
    from the book's own TOC label or first heading, and declines when the book names that document nowhere. It never falls back to
    Code:
    dc:title
    .
  • Choosing between identifiers. If a package's declared unique identifier resolves to nothing and the book carries both a UUID and an ISBN, which one is canonical is your decision, not the tool's.
  • HTML5 markup in an EPUB 2 book. Renaming
    Code:
    <figure>
    /
    Code:
    <section>
    to
    Code:
    <div>
    would clear thousands of errors and destroy meaning that assistive technology uses. Not doing it.

Known limitations, so you don't have to find them the hard way
  • Fixes are planned once, from the initial validation. A defect that only becomes visible after an earlier fix is not proposed — run it twice if you want those.
  • There's no per-fix undo yet: it's approve-then-apply, and the safety net is that the input is untouched.
  • Code:
    --goal openable
    changes the verdict, not yet which fixers run.

What would actually help

Two things, and the second is the one I can't get anywhere else.

1. Tell me when a repair is wrong. Not "it didn't fix X" — "it changed X and it shouldn't have". epubsana checks its own work by re-validating with epubveri, which means it is structurally blind to any damage epubveri doesn't know how to see. A person who knows their own book is the only check that isn't circular. If a repaired file opens differently, renders differently, or loses something, that's the report I most want.

2. Which defects do you fix by hand, over and over? I rank new fixers by what shows up in real books, and my own shelf has run out of candidates that can be repaired without guessing. Everything still on it is either genuinely ambiguous or needs information the file doesn't contain. So the ranking now has to come from outside — if you find yourself making the same tedious correction across books, that's exactly what should be automated next.

Repo, with a per-defect catalogue of what each fix changes and when it declines: https://github.com/veripublica/epubsana

It's AGPL, or a commercial licence for closed embedders. Written in Rust, no Java, no C dependencies.
Kayadelenium is offline   Reply With Quote
Old Yesterday, 01:30 PM   #2
rantanplan
Weirdo
rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.rantanplan ought to be getting tired of karma fortunes by now.
 
Posts: 1,184
Karma: 13169150
Join Date: Nov 2019
Location: Wuppertal, Germany
Device: Kobo Libra 2, Kobo Sage, Kobo Aura H2O, reMarkable PaperPro
Great idea!
rantanplan is offline   Reply With Quote
Advert
Old Yesterday, 02:51 PM   #3
Doitsu
Grand Sorcerer
Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.Doitsu ought to be getting tired of karma fortunes by now.
 
Doitsu's Avatar
 
Posts: 5,871
Karma: 24222221
Join Date: Dec 2010
Device: Kindle PW2
Quote:
Originally Posted by Kayadelenium View Post
epubsana repairs the defects epubveri reports. epubveri says what's wrong; epubsana turns the safely-fixable findings into edits you approve one at a time, applies them, and prints a report of exactly what changed.
It'd help a lot if the JSON output included a standard unified diff (the diff -u/git diff format) for each fix's edit(s).
This would greatly simplify creating plugins for Sigil, Calibre and other epub editors.
Doitsu is offline   Reply With Quote
Old Today, 08:45 PM   #4
Kayadelenium
Connoisseur
Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!Kayadelenium rocks like Gibraltar!
 
Posts: 57
Karma: 100000
Join Date: Jul 2026
Location: Planet Earth
Device: Kobo Forma
Thanks, both of you.

Doitsu — you're right, and the current output is a worse fit for your purpose than the docs make it look. Here is a real fix item from --format json as it stands today:

Code:
{
  "type": "fix",
  "outcome": "proposed",
  "code": "RSC-005",
  "rule": "opf.content_document.schema_violation",
  "severity": "error",
  "location": "Chapter-003.html",
  "message": "Wrap 3 runs of non-block content in <div> in Chapter-003.html",
  "data": {
    "fix_id": "fix.bare_text_in_body",
    "tier": "confirm_needed",
    "changes": [
      "wrap in <div>: \"<br />\"",
      "wrap in <div>: \"<br />\"",
      "wrap in <div>: \"<br /><br /><br /><br />\""
    ]
  }
}
Those changes entries are descriptions written for a person to read. Nothing downstream can render them or act on them — so for the consumer the JSON format exists to serve, they are not enough, exactly as you say.

I checked where a diff would have to live before replying. Our JSON contract makes items[].data tool-owned and requires consumers to ignore fields they don't recognise, so epubsana can add this on its own: no change to the shared spec, and no existing consumer breaks. The contract also already has the mode this belongs in — --dry-run emits the same envelope with every item marked "proposed", which is precisely the run a plugin would make to show someone a change before applying it.

Two issues are now open:

- #8 — Emit a unified diff per fix under items[].data: https://github.com/veripublica/epubsana/issues/8
- #7 — Workspace: a speculative apply: https://github.com/veripublica/epubsana/issues/7

The dependency between them is real rather than bureaucratic. Fixers currently write their edits straight into the in-memory container, so there is no way to ask what a fix would produce without producing it. That same missing piece is what per-fix rollback needs, so I would rather build it properly than bolt a diff onto the end.

Three questions where your answer is worth more than my guess:

1. One diff per fix, or one per file? Some fixes span files — renaming an invalid id rewrites every reference to it, across content documents and the NCX.
2. Diffs on applied fixes as well, or only under --dry-run?
3. Large diffs — cap them, and if so, how would you want a cap signalled? A fix over a big document can produce a lot of output, and I would rather settle that before someone's plugin runs into it.

One case has no text diff at all: the PKG-006 fix re-packages the container so the mimetype entry comes first and stored. Whatever gets emitted there has to say so, rather than showing an empty diff that reads as "nothing changed".

No timeline promised — I would rather land it correctly than quickly.
Kayadelenium is offline   Reply With Quote
Reply

Tags
epub, epub2, epub3, epubsana, epubveri


Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
[Editor Plugin] EpubCheck Doitsu Plugins 230 04-10-2026 03:19 AM
squashed images in Editor/Tools/Reports after search rjwse@aol.com Calibre 1 12-18-2019 12:00 PM
Possible bug in editor (reports) ratanplan Editor 2 02-18-2015 06:22 AM
Reports of 3.1 being pushed out for automatic upgrade Tiersten Amazon Kindle 33 02-20-2011 10:37 AM
Web-based epubcheck upgraded to epubcheck 1.0.5 kjk ePub 4 02-09-2010 09:53 PM


All times are GMT -4. The time now is 11:40 PM.


MobileRead.com is a privately owned, operated and funded community.