From 8e06fc84c0b540f8ba87afa19d4c08eab7af80d9 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Wed, 22 Jul 2026 20:46:48 +0000 Subject: Resolve lazy-loaded images/media before running Readability Many sites lazy-load media via JS: the real URL sits in a data-src/ data-srcset attribute and only gets copied into src/srcset once the site's own script runs -- which never happens in the reader WebView (JS is off by design, so articles can't run arbitrary third-party scripts). Left alone this showed either a placeholder/category icon stretched to fill the article width (reported live with a screenshot: a giant flask icon in place of the real photo on an Ars Technica article), or nothing but alt text (reported for NYT articles' images and videos). Before either Readability pass, walk / elements and copy common lazy-load attributes (data-src, data-original, data-lazy-src, data-srcset) into src/srcset, falling back to the first srcset candidate if src is still empty. Also strip width/height attributes on images -- they're sized for the site's real photo, not whatever was in the unresolved src, so our own max-width:100%/height:auto sizing now takes over based on the (correctly resolved) image's actual dimensions. Verified live: the Ars Technica article that previously showed the stretched flask icon now renders clean, with no image where the broken one used to appear and the full real article text intact. --- .../feedreader/readability/ReaderExtractor.kt | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/app/src/main/java/org/terst/feedreader/readability/ReaderExtractor.kt b/app/src/main/java/org/terst/feedreader/readability/ReaderExtractor.kt index 7e8e10c..82300ac 100644 --- a/app/src/main/java/org/terst/feedreader/readability/ReaderExtractor.kt +++ b/app/src/main/java/org/terst/feedreader/readability/ReaderExtractor.kt @@ -74,6 +74,44 @@ object ReaderExtractor { return (article && article.textContent) ? article.textContent.trim().length : 0; } + // Many sites lazy-load media via JS: the real URL sits in a + // data-src/data-srcset attribute and only gets copied into + // src/srcset once the site's own script runs -- which never + // happens here (JS is off in the reader WebView by design, so + // articles can't run arbitrary third-party scripts). Left alone + // this shows either a tiny placeholder/category icon stretched to + // fill the article width (the site's width/height attributes, + // sized for the real photo, still apply to whatever's in src), or + // nothing but the img's alt text if src is empty. Resolve these + // before Readability runs so it captures real media, not the + // unresolved lazy attribute. + var lazyAttrs = ['data-src', 'data-original', 'data-lazy-src']; + var imgs = document.querySelectorAll('img'); + for (var i = 0; i < imgs.length; i++) { + var img = imgs[i]; + for (var j = 0; j < lazyAttrs.length; j++) { + var lazySrc = img.getAttribute(lazyAttrs[j]); + if (lazySrc) { img.setAttribute('src', lazySrc); break; } + } + var lazySrcset = img.getAttribute('data-srcset'); + if (lazySrcset) img.setAttribute('srcset', lazySrcset); + if (!img.getAttribute('src') && img.getAttribute('srcset')) { + var first = img.getAttribute('srcset').split(',')[0].trim().split(/\s+/)[0]; + if (first) img.setAttribute('src', first); + } + // Drop width/height attributes now that src may point at a + // differently-sized image than whatever they were set for -- + // our own stylesheet's max-width:100%/height:auto sizes + // correctly from the (now-resolved) image's real dimensions. + img.removeAttribute('width'); + img.removeAttribute('height'); + } + var sources = document.querySelectorAll('source'); + for (var i = 0; i < sources.length; i++) { + var lazySrcset = sources[i].getAttribute('data-srcset') || sources[i].getAttribute('data-src'); + if (lazySrcset) sources[i].setAttribute('srcset', lazySrcset); + } + // Readability's default hidden-element skip (treating display:none / // visibility:hidden nodes as boilerplate) is correct for the vast // majority of sites -- it's what keeps collapsed nav/footer/sidebar -- cgit v1.2.3