Skip to content

fix(transmission): poll the audiobook category as well as the ebook one - #2712

Merged
vavallee merged 3 commits into
vavallee:mainfrom
ccarpinteri:pr/transmission-poll-audiobook-category
Oct 2, 2026
Merged

vavallee merged 3 commits into
vavallee:mainfrom
ccarpinteri:pr/transmission-poll-audiobook-category

Conversation

@ccarpinteri

Copy link
Copy Markdown
Contributor

Problem

checkTransmissionDownloads only fetches torrents under client.Category:

torrents, err := trans.GetTorrents(ctx, client.Category)

When CategoryAudiobook is set, audiobook grabs go to that category instead. The poller never sees them, so those downloads stay at "downloading" for good even though the torrent is sitting in the client and finishes normally.

The other clients already poll both through CategoriesToPoll. Transmission was missed.

Change

Poll every category CategoriesToPoll returns. The two can overlap, so a torrent returned by both is kept once. The zero match warning now names the audiobook category too, so a mismatch there is as visible as one on the ebook category.

Tests

Existing importer suite passes. The two macOS failures I see locally also fail on a clean checkout of main.

Note on ordering

Stacks on #2711. The diff touches the same few lines of checkTransmissionDownloads, so it is easier to review after that one. Happy to rebase it onto main on its own if you would rather take it first.

🤖 Generated with Claude Code

@github-actions github-actions Bot added the bindery-notified Discord notification already sent for this PR label Sep 19, 2026
ccarpinteri and others added 2 commits September 19, 2026 13:07
…orrent id

torrent-add returns a numeric id that only lasts as long as the daemon
session. Transmission renumbers every torrent when it restarts, but
Bindery stored that id as the download's TorrentID and the poller looked
downloads up by it.

After a restart the id matches nothing, so the poller skips the row and
the download sits at "downloading" for good while the torrent carries on
seeding. Nothing imports it. Ids are also reused, so a stored id can come
back pointing at a different torrent, and then the wrong payload is
imported and the wrong torrent is acted on.

This stores hashString instead, which stays the same for the life of the
torrent, and looks downloads up by it. The RPC takes a hash anywhere it
takes an id, so removal works off the same value. Stall detection and the
queue's live progress overlay are keyed by hash too, since both compare
against the stored value. Stall detection gets no numeric fallback
because the caller removes what it matches; the overlay keeps one because
it only draws a row.

Rows written before this change still hold a numeric id. They are matched
by comparing Transmission's addedDate with the download's grab time,
which a restart does not change, and only when the pairing is clear: a
torrent no download is close to is left alone, a torrent one download is
close to is assigned, and a torrent several downloads are close to needs
the release name to pick one or it is left for the user. The row is then
rewritten to the hash, the same way the qBittorrent hash recovery in vavallee#939
works. The stale id is never used to find the torrent. Leaving a download
stuck can be undone, removing the wrong torrent cannot.

Terminal downloads are skipped: they will not be imported or removed
again, so rewriting their identifier can only be wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
checkTransmissionDownloads only fetched torrents under client.Category.
When CategoryAudiobook is set, audiobook grabs go to that category
instead, so the poller never saw them and those downloads stayed at
"downloading" for good.

It now polls every category CategoriesToPoll returns, the same set the
other clients already poll, and keeps a torrent once if both categories
return it. The zero-match warning names the audiobook category too, so a
mismatch there is as visible as one on the ebook category.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ccarpinteri
ccarpinteri force-pushed the pr/transmission-poll-audiobook-category branch from 55377ad to b785e51 Compare September 19, 2026 03:09
@codecov

codecov Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.70588% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/importer/scanner_poll.go 64.70% 4 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@vavallee vavallee left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right fix, and CategoriesToPoll is exactly what the other clients already use, so Transmission just catches up with them. Dedupe on overlap is covered. Passes merged onto main on top of #2711. Same DCO sign-off needed as #2711.

main already carries the info hash work from vavallee#2711, so this keeps
main for that and applies only this PR's poll change, plus a
regression test and changelog fragment.

Signed-off-by: vavallee <vavallee@protonmail.com>
@vavallee
vavallee merged commit d0593fd into vavallee:main Oct 2, 2026
39 of 41 checks passed
vavallee added a commit to ccarpinteri/bindery that referenced this pull request Oct 2, 2026
main now carries vavallee#2711 and vavallee#2712, which this branch stacked on, so this
keeps main for those and applies only the remove on import change. It
also limits the settings toggle to qBittorrent and Transmission, the two
clients whose import path removes the torrent, and adds the changelog
fragment.

Signed-off-by: vavallee <vavallee@protonmail.com>
vavallee added a commit that referenced this pull request Oct 2, 2026
Main moved under this branch: Transmission downloads are keyed by info
hash (#2711), the importer polls the Transmission audiobook category
(#2712), remove on import exists (#2713) and per indexer seed limits
apply after add (#2917).

Conflict resolution keeps both sides. GetStalledTorrents now keys both
Transmission halves of the StallReport by lower-cased info hash, never
the session id, and the torrent-get field list carries main's addedDate
alongside metadataPercentComplete and peersConnected.

Re-checking the logic against current main turned up three things,
fixed here:

- Stall detection still polled only the Transmission ebook category, so
  an audiobook magnet was invisible to it. It now polls every category
  CategoriesToPoll returns, counting a torrent both filters return once
  so the outage guard's denominator is not doubled.
- A no-metadata torrent was removed with delete-local-data. It has no
  files, so it is now removed entry only (StallKind.DeletesData), the
  same as remove on import. Client reported stalls still delete data.
- The re-search after a no-metadata stall did nothing when the dead
  release still ranked first: it was approved again and the #2710
  cooldown refused the grab instead of trying the runner up. The
  re-search now carries the stalled GUID and a decision spec skips it
  for that one search only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016fJcCVbNnKsmj2MAAMwWj9
Signed-off-by: vavallee <vavallee@protonmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bindery-notified Discord notification already sent for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants