package org.terst.feedreader.data import org.terst.feedreader.readability.ConsentNotice import org.terst.feedreader.readability.RecirculationWidgets import org.terst.feedreader.readability.UnrenderedTex /** What a cached `articles.extractedContent` value turned out to be worth. */ data class CachedExtraction( /** The content to show, or null if there is nothing usable. */ val content: String?, /** * True when a cached consent notice was thrown away. The caller has nothing to * 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, /** * 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, 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 * disclaimer", with `extractedContent cached: true`) was already on disk: every * subsequent open read it straight back out, so no amount of fixing the extractor * would have changed what the user saw. A poisoned row is cleared here rather than * in a schema migration, so it is repaired whenever the article is next opened -- * including for anything extracted before this check existed. * * [clearCache] is passed in rather than taking the DAO so this stays a plain * decision that can be tested without a database. */ suspend fun loadCachedExtraction( cached: String?, clearCache: suspend () -> Unit ): CachedExtraction { 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( // Recirculation widgets are deliberately not in the `discard` list above. A cached // article carrying the publisher's promo blocks is a good article with litter in it, // not a poisoned row: cleaning it in place shows the right thing immediately, where // discarding it would throw away a usable body and fetch the identical one back. content = RecirculationWidgets.strip(cached), discardedConsentNotice = false ) clearCache() return discard }