✨ Added
- LazyLibrarian → aMuTorrent → aMule support. Multipart
POST /api/v2/torrents/addhandling (LazyLibrarian sends the dummy-file variant even for magnet URLs), newGET /api/v2/torrents/propertiesandGET /api/v2/torrents/filesendpoints for LazyLibrarian's post-add verification and post-download file discovery, andinvalidateBatchCache()on successful add so the nexttorrents/infopoll sees fresh data (Sonarr/Radarr get the same small QoL win).savepathsent alongsideurlsis mapped to a matching aMule category by path when no category/label is set, with explicit warnings when the path doesn't match anything (#71, contributed by @Mika3578). - qBittorrent WebAPI ≥2.11.2 route aliases.
POST /torrents/stopandPOST /torrents/startaliaspauseTorrent/resumeTorrentrespectively — real qBit renamed those in 2.11.2, and clients like Medusa key off the advertisedwebapiVersion(2.11.4) and call the new names. NewPOST /torrents/setCategoryhandler; returns 409text/plain "Category does not exist"when the requested name isn't in the compat categories cache, matching qBit exactly so clients trigger thecreateCategory+ retry handshake (#74).
🐛 Fixed
- rTorrent 0.16.18 stuck showing "Firewalled" regardless of actual state. rTorrent 0.16.18 deprecated
network.port_open; our multicall was still calling it and falling into thefalsebranch. That command was never a real firewall check anyway — it was a config toggle. Replaced withnetwork.listen.port > 0(rTorrent is actually bound and listening), forward-compatible with 0.16.18 and backward-compatible with older builds. size/downloaded/completedshipped as JSON strings, crashing Medusa (unsupported operand type(s) for /: 'str' and 'str'). Real qBit returns numbers; Sonarr/Radarr's .NET deserializer coerces silently, but strict consumers (Python, typed Go/Rust) don't. Root cause:_mapUnifiedItemToDownloadwas needlesslyString()-casting numeric fields on the way in, and the converter passed them through verbatim. Fixed at both layers: source (drop the casts) and output boundary (Number()-coerce every numeric field before returning). Coverssize,total_size,amount_left,downloaded,completed,downloaded_session,uploaded,uploaded_session,dlspeed,upspeed,ratio(#72).- Torznab returned 0 items for long
qvalues (Medusa passes series name + full episode title as free-text). aMule'sSearchList.cpp:104rejects a parsed expression when boolean operators exceed 10; the grammar inserts an implicit AND per adjacent-word pair, so 12+ words trips "Search expression is too complex". Long queries are now capped at 11 words (10 for tvsearch, reserving 1 for the appended format token), with a warn-level log so users can correlate. tvsearch also emits an absolute-style variant (Show 05) alongside the existing1x05/S01E05— catches ED2K releases named "Show 01 - Title" (common French / documentary / anime naming). If all season/episode variants collectively return 0, falls back to a single retry with the bare (capped) series name (#73).
♻️ Improved
- qBittorrent-compat polish.
_findTorrentInfoByHashenriches only the matched candidate instead of every one (O(N) → O(1) enrich calls per lookup); negative-result cache (5s TTL, cleared on successful add) so bogus-hash polls don't refetch aMule on every request; 404 responses onproperties/filesnowtext/plainmatching qBit;npm testscript portable across all shells (test/**/*.test.jsglob replaced withtest/directory recursion).