oceanstrip removes injected redistributor/conversion watermarks. Two are known today, added through a small registry rather than a hardcoded host:
- OceanofPDF.com injects a link whose text is OceanofPDF.com (an
<a href="...oceanofpdf.com">) into content documents, plus a stray, unreferenced marker file namedoceanofpdf.comat the archive root. Both are removed. - ABC Amber LIT Converter (an old
.lit→ HTML converter) stampsABC Amber LIT Converter http://www.processtext.com/abclit.htmlon nearly every content document. It appears two ways: anchored, with the word "Converter" split across a<b>and its inner<a>; and anchorless, as plain text with the URL not linked (in a<p>, or a<div type="FOOTER">). Both forms are removed.
oceanstrip handles both an anchored form (the stamp is a link) and an anchorless form (plain text, no <a>) with the same balanced-element removal. In every case it deletes a wrapper only when that wrapper's entire visible text is the stamp, so real prose that merely mentions the URL is never touched.
Every watermark is plain markup overlaid on the page, not burned into any image, so removal is lossless. As a bonus, it repairs the mimetype entry (writes it first and stored, uncompressed), which OceanofPDF's repackaging frequently breaks. Cleaned files often validate cleaner than the source.
Adding another producer is one entry in the WATERMARKS table (an href signature and the stamp's visible text); the balanced-element removal engine is otherwise signature-agnostic.
Originals are never modified. Cleaned copies are written to a new path.
Python 3.14+ (requires tqdm).
uv tool install /path/to/oceanstrip # installs the `oceanstrip` command
# or run straight from a checkout:
PYTHONPATH=src python3 -m oceanstrip --helpClean a single book (writes <name> (cleaned).epub beside it, or to an explicit output path):
oceanstrip "_OceanofPDF.com_Some Book.epub"
oceanstrip input.epub "Some Book.epub"--out and --dry-run/-n are batch-only. Passing them in single-file mode is an error (exit 2) rather than a silent no-op, so you do not end up with an unexpected <name> (cleaned).epub when you meant to target a directory. For a single file, give the output path positionally as above; to dry-run or redirect output, use --batch.
Scan a whole library and report which books are watermarked, without writing anything:
oceanstrip --batch ~/docs/Calibre\ Library --dry-runClean every watermarked book in a tree, writing cleaned copies to an output directory (default ~/Downloads):
oceanstrip --batch ~/docs/Calibre\ Library --out ~/DownloadsAll opt-in; the default (clean to a new path, originals untouched) is unchanged.
--checkvalidates each cleaned copy with epubcheck and refuses any clean that regresses fatals or errors versus the original (nothing is written, exit code 3). If epubcheck is not on yourPATH, pass--epubcheck /path/to/epubcheck; if it cannot be found at all,--checkjust warns and proceeds.--in-placereplaces the original after a successful validate, keeping a numbered.bakbeside it. It is the one case where an original is modified, so it is gated on both the backup and the epubcheck validate: it implies--checkand errors out (touching nothing) when epubcheck is unavailable.--json FILEwrites a machine-readable run summary (-for stdout): per-book counts, image warnings, and epubcheck before/after.
oceanstrip book.epub clean.epub --check # validate; refuse a regression
oceanstrip --batch ~/Library --in-place # clean originals, keeping .bak
oceanstrip --batch ~/Library --dry-run --json report.jsonWatermarks burned into a cover image cannot be removed (there is no OCR here), but oceanstrip warns when it sees a signature it cannot strip: an image named like OceanofPDF.com.jpg, or a stamp that survives inside an <img> reference. These show up as ! ... (cannot remove) lines and in the JSON report's image_warnings.
Different EPUB producers nest the watermark differently: a flat <div>, a <div> that also holds an empty sibling <div>, or an <a> inside an <h1> inside a content <div>. A non-greedy regex closes on the first </div> it finds, which is often the wrong one; that orphans a tag and corrupts the XML (it produced 69 fatal parse errors on one real book during development).
Instead, oceanstrip finds the <a>, walks up the real tag stack to the outermost enclosing wrapper whose only visible text is OceanofPDF.com and which holds no media, then deletes that whole balanced element. If no such clean wrapper exists, it removes just the <a>. Because it only ever deletes a complete, balanced element, a well-formed document stays well-formed. See spec.md for the full contract.
The --check flag builds this in: it runs epubcheck over the original and the cleaned copy and requires that the cleaned copy has no more fatals or errors than the original, refusing anything that regresses. Many rips already carry pre-existing issues that are out of scope here, so the bar is "no worse", not "clean". epubcheck stays an external tool, not a dependency; you can also run it by hand against any output.
./run_tests.sh # stdlib unittest suiteMIT. See LICENSE.
If oceanstrip's useful to you and you'd like to chip in:
- liberapay · liberapay.com/bdkl
- bitcoin
bc1qkge6zr45tzqfwfmvma2ylumt6mg7wlwmhr05yv