summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/readability/EvalDecision.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/readability/EvalDecision.kt')
-rw-r--r--app/src/main/java/org/terst/feedreader/readability/EvalDecision.kt61
1 files changed, 61 insertions, 0 deletions
diff --git a/app/src/main/java/org/terst/feedreader/readability/EvalDecision.kt b/app/src/main/java/org/terst/feedreader/readability/EvalDecision.kt
new file mode 100644
index 0000000..ed0033d
--- /dev/null
+++ b/app/src/main/java/org/terst/feedreader/readability/EvalDecision.kt
@@ -0,0 +1,61 @@
+package org.terst.feedreader.readability
+
+/** What to do with one `evaluateJavascript` result. */
+sealed interface EvalDecision {
+ /** Nothing more to try: this is the extraction's outcome. */
+ data class Done(val result: ExtractionResult) : EvalDecision
+
+ /** The page probably was not ready; inject the script again. */
+ data object Retry : EvalDecision
+}
+
+/**
+ * Decides, for one script result, whether extraction succeeded, should be
+ * retried, or has failed and why.
+ *
+ * Lifted out of the WebView callback it used to live inside so it can be
+ * exercised without a device. The bug that prompted that: a result consisting
+ * only of the page's cookie-consent banner was non-blank and error-free, so it
+ * counted as a success, was cached to `articles.extractedContent`, and was never
+ * reconsidered. Reported live as "reader mode just extracts cookie disclaimer".
+ */
+internal fun decideEvalOutcome(
+ article: ExtractedArticle?,
+ rawResult: String,
+ attempt: Int,
+ maxAttempts: Int
+): EvalDecision {
+ val readabilityError = article?.error?.takeIf { it.isNotBlank() }
+ // A banner is exactly what a half-loaded page produces -- the consent script
+ // runs early, the article body may not be in the DOM yet -- so this is not
+ // usable, which routes it into the same retry the extractor already does for
+ // an empty result rather than being accepted.
+ val isConsentNotice = article != null &&
+ readabilityError == null &&
+ ConsentNotice.looksLikeConsentNotice(article.content)
+ val usable = article != null &&
+ readabilityError == null &&
+ !article.content.isNullOrBlank() &&
+ !isConsentNotice
+
+ return when {
+ usable -> EvalDecision.Done(ExtractionResult.Success(article!!))
+
+ // Readability ran and objected: that verdict will not change.
+ readabilityError != null ->
+ EvalDecision.Done(ExtractionResult.Failure(ExtractionFailure.ReadabilityError(readabilityError)))
+
+ attempt < maxAttempts -> EvalDecision.Retry
+
+ // Every attempt came back with nothing but the consent notice, so this is
+ // what the page actually serves -- report it as its own failure rather
+ // than passing a cookie disclaimer off as the article.
+ isConsentNotice ->
+ EvalDecision.Done(ExtractionResult.Failure(ExtractionFailure.ConsentInterstitial))
+
+ article == null ->
+ EvalDecision.Done(ExtractionResult.Failure(ExtractionFailure.BadResult(rawResult)))
+
+ else -> EvalDecision.Done(ExtractionResult.Failure(ExtractionFailure.NoContent))
+ }
+}