Hotfix for download link generation and account switching
This commit is contained in:
@@ -4,9 +4,12 @@ import (
|
||||
"bufio"
|
||||
"cmp"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/sirrobot01/decypharr/internal/request"
|
||||
"github.com/sirrobot01/decypharr/pkg/rclone"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -40,6 +43,20 @@ const (
|
||||
WebdavUseHash WebDavFolderNaming = "infohash"
|
||||
)
|
||||
|
||||
var streamingTransport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
MaxIdleConns: 200,
|
||||
MaxIdleConnsPerHost: 100,
|
||||
MaxConnsPerHost: 200,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ResponseHeaderTimeout: 60 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
DisableKeepAlives: true,
|
||||
ForceAttemptHTTP2: false,
|
||||
TLSNextProto: make(map[string]func(string, *tls.Conn) http.RoundTripper),
|
||||
}
|
||||
|
||||
type CachedTorrent struct {
|
||||
*types.Torrent
|
||||
AddedOn time.Time `json:"added_on"`
|
||||
@@ -81,9 +98,8 @@ type Cache struct {
|
||||
|
||||
listingDebouncer *utils.Debouncer[bool]
|
||||
// monitors
|
||||
repairRequest sync.Map
|
||||
failedToReinsert sync.Map
|
||||
downloadLinkRequests sync.Map
|
||||
repairRequest sync.Map
|
||||
failedToReinsert sync.Map
|
||||
|
||||
// repair
|
||||
repairChan chan RepairRequest
|
||||
@@ -108,6 +124,7 @@ type Cache struct {
|
||||
config config.Debrid
|
||||
customFolders []string
|
||||
mounter *rclone.Mount
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
func NewDebridCache(dc config.Debrid, client types.Client, mounter *rclone.Mount) *Cache {
|
||||
@@ -153,6 +170,16 @@ func NewDebridCache(dc config.Debrid, client types.Client, mounter *rclone.Mount
|
||||
|
||||
}
|
||||
_log := logger.New(fmt.Sprintf("%s-webdav", client.Name()))
|
||||
if dc.Proxy != "" {
|
||||
|
||||
}
|
||||
transport := streamingTransport
|
||||
request.SetProxy(transport, dc.Proxy)
|
||||
httpClient := &http.Client{
|
||||
Transport: transport,
|
||||
Timeout: 0,
|
||||
}
|
||||
|
||||
c := &Cache{
|
||||
dir: filepath.Join(cfg.Path, "cache", dc.Name), // path to save cache files
|
||||
|
||||
@@ -171,7 +198,8 @@ func NewDebridCache(dc config.Debrid, client types.Client, mounter *rclone.Mount
|
||||
customFolders: customFolders,
|
||||
mounter: mounter,
|
||||
|
||||
ready: make(chan struct{}),
|
||||
ready: make(chan struct{}),
|
||||
httpClient: httpClient,
|
||||
}
|
||||
|
||||
c.listingDebouncer = utils.NewDebouncer[bool](100*time.Millisecond, func(refreshRclone bool) {
|
||||
@@ -225,7 +253,6 @@ func (c *Cache) Reset() {
|
||||
c.invalidDownloadLinks = sync.Map{}
|
||||
c.repairRequest = sync.Map{}
|
||||
c.failedToReinsert = sync.Map{}
|
||||
c.downloadLinkRequests = sync.Map{}
|
||||
|
||||
// 5. Rebuild the listing debouncer
|
||||
c.listingDebouncer = utils.NewDebouncer[bool](
|
||||
@@ -904,3 +931,7 @@ func (c *Cache) Logger() zerolog.Logger {
|
||||
func (c *Cache) GetConfig() config.Debrid {
|
||||
return c.config
|
||||
}
|
||||
|
||||
func (c *Cache) Download(req *http.Request) (*http.Response, error) {
|
||||
return c.httpClient.Do(req)
|
||||
}
|
||||
|
||||
@@ -36,31 +36,15 @@ func (c *Cache) GetDownloadLink(torrentName, filename, fileLink string) (string,
|
||||
return dl, nil
|
||||
}
|
||||
|
||||
if req, inFlight := c.downloadLinkRequests.Load(fileLink); inFlight {
|
||||
// Wait for the other request to complete and use its result
|
||||
result := req.(*downloadLinkRequest)
|
||||
return result.Wait()
|
||||
}
|
||||
|
||||
// Create a new request object
|
||||
req := newDownloadLinkRequest()
|
||||
c.downloadLinkRequests.Store(fileLink, req)
|
||||
|
||||
dl, err := c.fetchDownloadLink(torrentName, filename, fileLink)
|
||||
if err != nil {
|
||||
req.Complete("", err)
|
||||
c.downloadLinkRequests.Delete(fileLink)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if dl == nil || dl.DownloadLink == "" {
|
||||
err = fmt.Errorf("download link is empty for %s in torrent %s", filename, torrentName)
|
||||
req.Complete("", err)
|
||||
c.downloadLinkRequests.Delete(fileLink)
|
||||
return "", err
|
||||
}
|
||||
req.Complete(dl.DownloadLink, err)
|
||||
c.downloadLinkRequests.Delete(fileLink)
|
||||
return dl.DownloadLink, err
|
||||
}
|
||||
|
||||
@@ -102,10 +86,11 @@ func (c *Cache) fetchDownloadLink(torrentName, filename, fileLink string) (*type
|
||||
}
|
||||
|
||||
c.logger.Trace().Msgf("Getting download link for %s(%s)", filename, file.Link)
|
||||
downloadLink, err := c.client.GetDownloadLink(ct.Torrent, &file)
|
||||
downloadLink, account, err := c.client.GetDownloadLink(ct.Torrent, &file)
|
||||
if err != nil {
|
||||
if errors.Is(err, utils.HosterUnavailableError) {
|
||||
c.logger.Trace().
|
||||
Str("account", account.Username).
|
||||
Str("filename", filename).
|
||||
Str("torrent_id", ct.Id).
|
||||
Msg("Hoster unavailable, attempting to reinsert torrent")
|
||||
@@ -120,7 +105,7 @@ func (c *Cache) fetchDownloadLink(torrentName, filename, fileLink string) (*type
|
||||
return nil, fmt.Errorf("file %s not found in reinserted torrent %s", filename, torrentName)
|
||||
}
|
||||
// Retry getting the download link
|
||||
downloadLink, err = c.client.GetDownloadLink(ct.Torrent, &file)
|
||||
downloadLink, account, err = c.client.GetDownloadLink(ct.Torrent, &file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("retry failed to get download link: %w", err)
|
||||
}
|
||||
@@ -140,7 +125,7 @@ func (c *Cache) fetchDownloadLink(torrentName, filename, fileLink string) (*type
|
||||
}
|
||||
|
||||
// Set link to cache
|
||||
go c.client.Accounts().SetDownloadLink(fileLink, downloadLink)
|
||||
go c.client.Accounts().SetDownloadLink(account, downloadLink)
|
||||
return downloadLink, nil
|
||||
}
|
||||
|
||||
@@ -153,7 +138,7 @@ func (c *Cache) GetFileDownloadLinks(t CachedTorrent) {
|
||||
|
||||
func (c *Cache) checkDownloadLink(link string) (string, error) {
|
||||
|
||||
dl, err := c.client.Accounts().GetDownloadLink(link)
|
||||
dl, _, err := c.client.Accounts().GetDownloadLink(link)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -168,7 +153,7 @@ func (c *Cache) MarkDownloadLinkAsInvalid(link, downloadLink, reason string) {
|
||||
// Remove the download api key from active
|
||||
if reason == "bandwidth_exceeded" {
|
||||
// Disable the account
|
||||
_, account, err := c.client.Accounts().GetDownloadLinkWithAccount(link)
|
||||
account, err := c.client.Accounts().GetAccountFromLink(link)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -243,14 +243,10 @@ func (c *Cache) refreshDownloadLinks(ctx context.Context) {
|
||||
}
|
||||
defer c.downloadLinksRefreshMu.Unlock()
|
||||
|
||||
links, err := c.client.GetDownloadLinks()
|
||||
|
||||
if err != nil {
|
||||
if err := c.client.RefreshDownloadLinks(); err != nil {
|
||||
c.logger.Error().Err(err).Msg("Failed to get download links")
|
||||
return
|
||||
}
|
||||
|
||||
c.client.Accounts().SetDownloadLinks(links)
|
||||
|
||||
c.logger.Debug().Msgf("Refreshed download %d links", c.client.Accounts().GetLinksCount())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user