diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-10-16 21:04:38 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-10-16 21:04:38 +0000 |
| commit | e50f4fbbca21b85648f6c4045cbd50f672d315cd (patch) | |
| tree | f1f0b6e97b67e7291db7a9944c0fb8725212354a /app/src/main/java/org/terst/feedreader/data/CachedExtraction.kt | |
| parent | 3f988c1749460528c31dfc239a3a9544a8f52c30 (diff) | |
Render an article's maths instead of showing its TeX source
Reported against lcamtuf's Substack ("we should render tex",
blog.coredump.cx/p/yours-truly): reader mode showed raw
"\(p = \text{...}\)" where equations should be.
What the page actually ships is the TeX SOURCE, as text, inside a
"latex-rendered" div -- Substack renders it in the browser with its own
script, which never runs here. Readability keeps that text verbatim (it
strips the class, not the text), so nothing was being discarded during
extraction and no amount of extraction-side repair would have helped:
there was simply never any rendered markup to keep.
So render it during extraction, where JavaScript is already running for
Readability's sake. KaTeX (vendored in assets, never fetched -- this
runs against untrusted third-party pages) converts each expression to
MathML before Readability sees the document, and the reader WebView
renders that natively. The reader keeps JavaScript OFF, as it must, and
needs no stylesheet, webfont or script of KaTeX's; the only reader-side
change is containing a wide equation so it scrolls within its own box
instead of dragging the whole article sideways.
Two details worth knowing:
- KaTeX refuses {align} outside display mode, and Substack wraps display
maths in INLINE delimiters (a block-styled span does the centring), so
a mode that renders nothing is retried in the other one. An expression
neither mode can render is left as source -- no worse than before.
- The reported article came with "extractedContent cached: true", so the
raw source was already on disk and every open read it back. Recognised
and dropped on read (same mechanism as the cached consent notice),
which re-extracts the article the next time it is opened.
APK grows by ~90KB: the vendored katex.min.js (267KB) compresses to 91KB
in the APK. No new permissions, no schema change, no new JS-enabled
surface.
Verified on the emulator against the live article: stale raw-TeX cache
discarded, article re-extracted, all four equations rendered, and a wide
align block scrolls inside itself.
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/data/CachedExtraction.kt')
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/data/CachedExtraction.kt | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/app/src/main/java/org/terst/feedreader/data/CachedExtraction.kt b/app/src/main/java/org/terst/feedreader/data/CachedExtraction.kt index 313d467..3a791cc 100644 --- a/app/src/main/java/org/terst/feedreader/data/CachedExtraction.kt +++ b/app/src/main/java/org/terst/feedreader/data/CachedExtraction.kt @@ -1,6 +1,7 @@ package org.terst.feedreader.data import org.terst.feedreader.readability.ConsentNotice +import org.terst.feedreader.readability.UnrenderedTex /** What a cached `articles.extractedContent` value turned out to be worth. */ data class CachedExtraction( @@ -11,12 +12,24 @@ data class CachedExtraction( * show and should extract again -- the cache is the reason the article looked * broken, so dropping it silently would just leave a blank reader. */ - val discardedConsentNotice: Boolean -) + val discardedConsentNotice: Boolean, + /** + * True when a cached extraction holding raw TeX source was thrown away -- it was + * extracted before extraction knew how to render maths (see [UnrenderedTex]). + */ + val discardedUnrenderedTex: Boolean = false +) { + /** + * True when something was thrown away, whatever it was: there is nothing to show and + * the caller has to extract again. + */ + val discarded: Boolean get() = discardedConsentNotice || discardedUnrenderedTex +} /** * Reads a cached extraction, dropping it if it is the site's cookie/consent notice - * rather than the article. + * rather than the article, or if it is an older extraction whose maths never got + * rendered. * * Needed because the extractor's own guard can only keep a bad extraction from * being written in future. The reported bug ("reader mode just extracts cookie @@ -33,9 +46,20 @@ suspend fun loadCachedExtraction( cached: String?, clearCache: suspend () -> Unit ): CachedExtraction { - if (!ConsentNotice.looksLikeConsentNotice(cached)) { - return CachedExtraction(content = cached, discardedConsentNotice = false) - } + val discard = when { + ConsentNotice.looksLikeConsentNotice(cached) -> + CachedExtraction(content = null, discardedConsentNotice = true) + // Same shape of problem, different cause: this one was extracted before extraction + // rendered maths, so it holds the TeX source the page shipped. + UnrenderedTex.looksLikeUnrenderedTex(cached) -> + CachedExtraction( + content = null, + discardedConsentNotice = false, + discardedUnrenderedTex = true + ) + else -> null + } ?: return CachedExtraction(content = cached, discardedConsentNotice = false) + clearCache() - return CachedExtraction(content = null, discardedConsentNotice = true) + return discard } |
