image-cache: rewrite URLs eagerly, download lazily via scheme handler
process() was downloading all images before returning, blocking the article list update for potentially minutes on a first run or after a cache wipe. Move all network I/O out of process(): - process() now only rewrites src="https://..." to the custom feedthemonkey-img:/// scheme — it is synchronous and instant. - The URI scheme handler already downloads and caches on demand, so images are fetched the first time the WebView requests them and served from disk on every subsequent view. This means the article list appears immediately after a server fetch regardless of how many images need caching.
This commit is contained in:
parent
00700c3211
commit
3f759bce2e
2 changed files with 20 additions and 40 deletions
|
|
@ -134,47 +134,27 @@ fn serve_file(request: webkit6::URISchemeRequest, path: PathBuf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Download all remote images in every article and rewrite their src attributes
|
/// Rewrite all remote image src attributes to feedthemonkey-img:// URIs.
|
||||||
/// to feedthemonkey-img:// URIs so images are served through the cache handler,
|
/// No network requests are made here — images are downloaded lazily by the
|
||||||
/// which re-downloads automatically on a cache miss.
|
/// URI scheme handler the first time the WebView requests them, then cached.
|
||||||
pub async fn process(articles: Vec<Article>) -> Vec<Article> {
|
pub fn process(articles: Vec<Article>) -> Vec<Article> {
|
||||||
let dir = images_dir();
|
|
||||||
std::fs::create_dir_all(&dir).ok();
|
|
||||||
|
|
||||||
let client = reqwest::Client::builder()
|
|
||||||
.timeout(std::time::Duration::from_secs(30))
|
|
||||||
.build()
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let re = regex::Regex::new(r#"src="(https?://[^"]+)""#).unwrap();
|
let re = regex::Regex::new(r#"src="(https?://[^"]+)""#).unwrap();
|
||||||
|
articles
|
||||||
let mut out = Vec::with_capacity(articles.len());
|
.into_iter()
|
||||||
for mut article in articles {
|
.map(|mut article| {
|
||||||
let content = article.content.clone();
|
let content = article.content.clone();
|
||||||
let mut rewritten = content.clone();
|
let mut rewritten = content.clone();
|
||||||
|
for cap in re.captures_iter(&content) {
|
||||||
for cap in re.captures_iter(&content) {
|
let url = &cap[1];
|
||||||
let url = &cap[1];
|
rewritten = rewritten.replace(
|
||||||
let path = dir.join(url_to_filename(url));
|
&format!("src=\"{}\"", url),
|
||||||
if !path.exists() {
|
&format!("src=\"{}\"", original_url_to_scheme_uri(url)),
|
||||||
if let Ok(resp) = client.get(url).send().await {
|
);
|
||||||
if let Ok(bytes) = resp.bytes().await {
|
|
||||||
std::fs::write(&path, &bytes).ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Always rewrite to the scheme URI so the handler can re-download
|
article.content = rewritten;
|
||||||
// if the cache directory is ever deleted.
|
article
|
||||||
rewritten = rewritten.replace(
|
})
|
||||||
&format!("src=\"{}\"", url),
|
.collect()
|
||||||
&format!("src=\"{}\"", original_url_to_scheme_uri(url)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
article.content = rewritten;
|
|
||||||
out.push(article);
|
|
||||||
}
|
|
||||||
out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove cached image files no longer referenced by any article.
|
/// Remove cached image files no longer referenced by any article.
|
||||||
|
|
|
||||||
|
|
@ -597,7 +597,7 @@ pub mod imp {
|
||||||
async move {
|
async move {
|
||||||
let articles = api.fetch_unread().await?;
|
let articles = api.fetch_unread().await?;
|
||||||
let articles = if cache_images {
|
let articles = if cache_images {
|
||||||
crate::image_cache::process(articles).await
|
crate::image_cache::process(articles)
|
||||||
} else {
|
} else {
|
||||||
articles
|
articles
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue