Removes GetHashInfoAsync, and only uses the actual torrentId.
This was originally required as cachedtorrents endpoints used to use a different torrentId to the regular torrent endpoints for whatever reason, but luckily they figured out a while ago that that was not a good idea and just combined them which means calling API to search for hashes isnt needed anymore, hopefully this will reduce rate limiting a bit.
- Applied to TorBox, can be extended easily to other providers
- Reads response headers commonplace for pre-emptive rate limit throttling and retry-after
- When a rate limit is reached, displays a warning in the UI
- Fix socket leak from direct allocation of HttpClient, replaced with factory which handles pooling and re-use of sockets.
While HttpClient is Disposable, it doesn't gaurantee (and does not) directly release underlying sockets for queries at the time the client is disposed. These sockets will go into a TCP WAIT state often for a very long time. The expected pattern in C# is to always use the HttClientFactory which will correctly handle re-use of the OS sockets in suqsequent queries reducing resource and memory leaks.
Tests:
- `GetDownloadLinks`
- `IncludeRegex` filter works
- `ExcludeRegex` filter works
- `DownloadMinSize` filter works
- only `IncludeRegex` is used when both `IncludeRegex` and `ExcludeRegex` are set
- gets links for all files if none of the above filters are set
- returns null if `torrent.RdId` is null
- `GetTorrents`
- [Both full/partial sync] returns empty list when no torrents present in api response
- [full sync] overrides any previous torrents in cache, deleting those not present in the api response
- [partial sync] updates torrents in cache according to the api response
- [partial sync] adds torrents to cache according to the api response
- `Map` (private so tested via `GetTorrents`)
- Computes progress correctly from `Downloaded / Size`
- `UpdateData`
- [`torrentClientTorrent != null`] does not get from api, updates the `torrent` accordingly
- [`torrentClientTorrent == null`] gets from api, updates the `torrent` accordingly
- [`torrentClientTorrent == null`] when torrent deleted from rd, updates `RdStatusRaw = "deleted""`
- when `torrent.RdId == null`, returns the `torrent` unmodified