diff --git a/CHANGELOG.md b/CHANGELOG.md index 91a3932..2b28402 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- An episode whose file turns out to be a torrent shows as downloaded once it is, instead of being fetched again on every check of its feed, and no longer holds up the checking of other feeds while it downloads and seeds. - Downloading the latest 65 to 100 items of a feed queues them at once, instead of hanging until most had downloaded and holding up adding feeds and Refresh meanwhile. - Changes to the feed list made at the same moment, such as two people adding feeds, or a feed added while the server settings change, no longer undo one another. - A download that stops partway is given up after two minutes without data, instead of holding up every scan and download until a restart. diff --git a/src/main.rs b/src/main.rs index 14cd66e..0ec2991 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1761,7 +1761,8 @@ async fn scan_one( continue; } match fetch_one(ctx, id, item.id, feed_cfg, &item.url, &dest_dir).await { - Ok((path, bytes)) => { + Ok(None) => scan.torrents += 1, + Ok(Some((path, bytes))) => { ctx.out.emit(Event::DownloadDone { feed: id.to_string(), enclosure: item.id, @@ -1996,6 +1997,8 @@ fn merge_policy(subs: &[db::Sub], feed_cfg: &config::Feed, global: usize) -> Pol policy } +/// Downloads one file and records it. None when it turned out to be a torrent, handed off to run +/// on its own, which records it when it finishes. #[tracing::instrument(name = "download", skip_all, fields(feed = feed_id, enclosure = enclosure, url = url))] async fn fetch_one( ctx: &Arc, @@ -2004,7 +2007,7 @@ async fn fetch_one( feed_cfg: &config::Feed, url: &str, dest_dir: &std::path::Path, -) -> Result<(PathBuf, u64)> { +) -> Result> { // Throttled to whole percents, as the original's lastDLStepSize guard did. let mut last_pct = -1i64; let name = download::filename_for(url, None); @@ -2035,12 +2038,22 @@ async fn fetch_one( ctx.db.mark_enclosure(url, "skipped", Some("torrents disabled")).await?; anyhow::bail!("body is a torrent and torrents are disabled"); } - return torrent_one(ctx, feed_id, enclosure, url, dest_dir).await; + // As one advertised as a torrent goes: off the worker where it can be, and recorded either + // way. Run here and never recorded, it stayed pending, and every scan of its feed ran it + // again, on the worker, for up to the stall limit and the seeding time (#155). + if ctx.detach_torrents { + ctx.db.mark_enclosure(url, "downloading", None).await?; + spawn_torrent(ctx, feed_id.to_owned(), enclosure, url.to_owned(), dest_dir.to_owned()); + return Ok(None); + } + let (path, bytes) = torrent_one(ctx, feed_id, enclosure, url, dest_dir).await?; + ctx.db.mark_downloaded(url, &path, bytes).await?; + return Ok(Some((path, bytes))); } let path = download::place(&got, dest_dir).await?; ctx.db.mark_downloaded(url, &path, got.bytes).await?; - Ok((path, got.bytes)) + Ok(Some((path, got.bytes))) } /// Runs a torrent off the command worker, so feed scans and HTTP downloads keep moving @@ -2114,14 +2127,15 @@ async fn download_one(ctx: &Arc, id: i64) -> Result<()> { if !cfg.torrent.enabled { Err(anyhow::anyhow!("torrents are disabled")) } else { - torrent_one(ctx, &enc.feed_id, enc.id, &enc.url, &dest_dir).await + torrent_one(ctx, &enc.feed_id, enc.id, &enc.url, &dest_dir).await.map(Some) } } else { fetch_one(ctx, &enc.feed_id, enc.id, feed_cfg, &enc.url, &dest_dir).await }; match result { - Ok((path, bytes)) => { + Ok(None) => {} // A torrent after all, running on its own. + Ok(Some((path, bytes))) => { ctx.db.mark_downloaded(&enc.url, &path, bytes).await?; ctx.out.emit(Event::DownloadDone { feed: enc.feed_id.clone(),