From b299d57d6cc240381aed51f91e5a26f1e633d78d Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Mon, 24 Aug 2026 06:25:19 +0000 Subject: Pre-extract reader-mode content during feed fetch, not on article open Feeds like West Hawaii Today need Readability to strip a paywall/ boilerplate wrapper, and that extraction was happening lazily the first time an article was opened -- a hidden WebView load + JS eval that left the reader sitting on a spinner. Do it for new articles from reader-mode feeds right inside FeedFetchWorker.fetchOne instead, so it's already cached (both on the launch fetch and the 5am morning fetch) by the time the article is actually opened. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_017GMEkHeqKz6FLkmizowBTK --- .../org/terst/feedreader/work/FeedFetchWorker.kt | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/org/terst/feedreader/work') diff --git a/app/src/main/java/org/terst/feedreader/work/FeedFetchWorker.kt b/app/src/main/java/org/terst/feedreader/work/FeedFetchWorker.kt index ecd186b..5583014 100644 --- a/app/src/main/java/org/terst/feedreader/work/FeedFetchWorker.kt +++ b/app/src/main/java/org/terst/feedreader/work/FeedFetchWorker.kt @@ -19,6 +19,7 @@ import org.terst.feedreader.data.FeedParser import org.terst.feedreader.data.Net import org.terst.feedreader.data.Settings import org.terst.feedreader.data.await +import org.terst.feedreader.readability.ReaderExtractor import okhttp3.Request import java.security.MessageDigest import java.util.concurrent.atomic.AtomicInteger @@ -30,6 +31,10 @@ import java.util.concurrent.atomic.AtomicInteger * costs a 304 instead of a full re-download and re-parse. Only ever triggered by * fetchNow -- a fresh app launch or an explicit tap on the refresh button, never * a background schedule. + * + * For a reader-mode feed, new articles are also run through ReaderExtractor right + * here, so extractedContent is already cached by the time the user opens one -- + * see fetchOne. */ class FeedFetchWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { @@ -128,7 +133,23 @@ class FeedFetchWorker(context: Context, params: WorkerParameters) : CoroutineWor // Room returns -1 for a row OnConflictStrategy.IGNORE actually skipped // (already stored), and the real inserted rowid (>= 0) for a genuinely new // one -- count only the latter so "N new articles" reflects reality. - val newCount = db.articleDao().insertNew(articles).count { it != -1L } + val insertResults = db.articleDao().insertNew(articles) + val newArticles = articles.zip(insertResults).mapNotNull { (article, result) -> article.takeIf { result != -1L } } + val newCount = newArticles.size + + if (feed.readerModeEnabled) { + // Pre-extract reader-mode content right here during the fetch, instead of + // lazily the first time the article is opened (see ReaderScreen's + // LaunchedEffect). For a reader-mode feed like West Hawaii Today, that + // lazy path meant every fresh article's first open sat on a spinner for a + // hidden WebView load + Readability JS eval (several seconds, sometimes + // much longer on a slow/heavy page) before any content showed. By the time + // the user actually taps into it here, it's already cached. + for (newArticle in newArticles) { + val extracted = ReaderExtractor.extract(applicationContext, newArticle.link) + extracted?.content?.let { db.articleDao().setExtractedContent(newArticle.id, it) } + } + } db.feedDao().updateFetchResult( id = feed.id, -- cgit v1.2.3