Fix duplicate links for files
This commit is contained in:
@@ -27,10 +27,6 @@ const (
|
||||
WebDavUseOriginalNameNoExt WebDavFolderNaming = "original_no_ext"
|
||||
)
|
||||
|
||||
type DownloadLinkCache struct {
|
||||
Link string `json:"download_link"`
|
||||
}
|
||||
|
||||
type PropfindResponse struct {
|
||||
Data []byte
|
||||
GzippedData []byte
|
||||
@@ -112,8 +108,6 @@ func (c *Cache) setTorrent(t *CachedTorrent) {
|
||||
c.torrentsNames[c.GetTorrentFolder(t.Torrent)] = t
|
||||
c.torrentsMutex.Unlock()
|
||||
|
||||
c.refreshListings()
|
||||
|
||||
go func() {
|
||||
if err := c.SaveTorrent(t); err != nil {
|
||||
c.logger.Debug().Err(err).Msgf("Failed to save torrent %s", t.Id)
|
||||
@@ -224,6 +218,19 @@ func (c *Cache) load() (map[string]*CachedTorrent, error) {
|
||||
}
|
||||
if len(ct.Files) != 0 {
|
||||
// We can assume the torrent is complete
|
||||
|
||||
// Make sure no file has a duplicate link
|
||||
linkStore := make(map[string]bool)
|
||||
for _, f := range ct.Files {
|
||||
if _, ok := linkStore[f.Link]; ok {
|
||||
// Duplicate link, refresh the torrent
|
||||
ct = *c.refreshTorrent(&ct)
|
||||
break
|
||||
} else {
|
||||
linkStore[f.Link] = true
|
||||
}
|
||||
}
|
||||
|
||||
ct.IsComplete = true
|
||||
torrents[ct.Id] = &ct
|
||||
}
|
||||
@@ -369,7 +376,7 @@ func (c *Cache) sync(torrents []*types.Torrent) error {
|
||||
return // Channel closed, exit goroutine
|
||||
}
|
||||
|
||||
if err := c.ProcessTorrent(t, true); err != nil {
|
||||
if err := c.ProcessTorrent(t, false); err != nil {
|
||||
c.logger.Error().Err(err).Str("torrent", t.Name).Msg("sync error")
|
||||
atomic.AddInt64(&errorCount, 1)
|
||||
}
|
||||
@@ -402,6 +409,7 @@ func (c *Cache) sync(torrents []*types.Torrent) error {
|
||||
// Wait for all workers to complete
|
||||
wg.Wait()
|
||||
|
||||
c.refreshListings()
|
||||
c.logger.Info().Msgf("Sync complete: %d torrents processed, %d errors", len(torrents), errorCount)
|
||||
return nil
|
||||
}
|
||||
@@ -412,13 +420,16 @@ func (c *Cache) ProcessTorrent(t *types.Torrent, refreshRclone bool) error {
|
||||
return fmt.Errorf("failed to update torrent: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ct := &CachedTorrent{
|
||||
Torrent: t,
|
||||
LastRead: time.Now(),
|
||||
IsComplete: len(t.Files) > 0,
|
||||
}
|
||||
c.setTorrent(ct)
|
||||
|
||||
if refreshRclone {
|
||||
c.refreshListings()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -447,7 +458,6 @@ func (c *Cache) GetDownloadLink(torrentId, filename, fileLink string) string {
|
||||
file = ct.Files[filename]
|
||||
}
|
||||
}
|
||||
|
||||
c.logger.Trace().Msgf("Getting download link for %s", ct.Name)
|
||||
link, err := c.client.GetDownloadLink(ct.Torrent, &file)
|
||||
if err != nil {
|
||||
@@ -463,6 +473,39 @@ func (c *Cache) GetDownloadLink(torrentId, filename, fileLink string) string {
|
||||
return file.DownloadLink
|
||||
}
|
||||
|
||||
func (c *Cache) GenerateDownloadLinks(t *CachedTorrent) {
|
||||
if err := c.client.GenerateDownloadLinks(t.Torrent); err != nil {
|
||||
c.logger.Error().Err(err).Msg("Failed to generate download links")
|
||||
}
|
||||
for _, file := range t.Files {
|
||||
c.updateDownloadLink(file)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := c.SaveTorrent(t); err != nil {
|
||||
c.logger.Debug().Err(err).Msgf("Failed to save torrent %s", t.Id)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *Cache) AddTorrent(t *types.Torrent) error {
|
||||
if len(t.Files) == 0 {
|
||||
if err := c.client.UpdateTorrent(t); err != nil {
|
||||
return fmt.Errorf("failed to update torrent: %w", err)
|
||||
}
|
||||
}
|
||||
ct := &CachedTorrent{
|
||||
Torrent: t,
|
||||
LastRead: time.Now(),
|
||||
IsComplete: len(t.Files) > 0,
|
||||
}
|
||||
c.setTorrent(ct)
|
||||
c.refreshListings()
|
||||
go c.GenerateDownloadLinks(ct)
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (c *Cache) updateDownloadLink(file types.File) {
|
||||
c.downloadLinksMutex.Lock()
|
||||
defer c.downloadLinksMutex.Unlock()
|
||||
@@ -489,6 +532,8 @@ func (c *Cache) DeleteTorrent(id string) {
|
||||
delete(c.torrentsNames, t.Name)
|
||||
|
||||
c.removeFromDB(id)
|
||||
|
||||
c.refreshListings()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,9 +545,10 @@ func (c *Cache) DeleteTorrents(ids []string) {
|
||||
if t, ok := c.torrents[id]; ok {
|
||||
delete(c.torrents, id)
|
||||
delete(c.torrentsNames, c.GetTorrentFolder(t.Torrent))
|
||||
c.removeFromDB(id)
|
||||
go c.removeFromDB(id)
|
||||
}
|
||||
}
|
||||
c.refreshListings()
|
||||
}
|
||||
|
||||
func (c *Cache) removeFromDB(torrentId string) {
|
||||
|
||||
@@ -18,7 +18,7 @@ func (c *Cache) RefreshXml() error {
|
||||
return fmt.Errorf("failed to refresh XML for %s: %v", parent, err)
|
||||
}
|
||||
}
|
||||
c.logger.Trace().Msgf("Refreshed XML cache for %s", c.client.GetName())
|
||||
c.logger.Debug().Msgf("Refreshed XML cache for %s", c.client.GetName())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -74,12 +74,6 @@ func getTorrentFiles(t *types.Torrent, data TorrentInfo, validate bool) map[stri
|
||||
_link = data.Links[idx]
|
||||
}
|
||||
|
||||
if a, ok := t.Files[name]; ok {
|
||||
a.Link = _link
|
||||
files[name] = a
|
||||
continue
|
||||
}
|
||||
|
||||
file := types.File{
|
||||
Name: name,
|
||||
Path: name,
|
||||
@@ -268,17 +262,15 @@ func (r *RealDebrid) DeleteTorrent(torrentId string) {
|
||||
|
||||
func (r *RealDebrid) GenerateDownloadLinks(t *types.Torrent) error {
|
||||
url := fmt.Sprintf("%s/unrestrict/link/", r.Host)
|
||||
files := make(map[string]types.File)
|
||||
for _, f := range t.Files {
|
||||
if f.DownloadLink != "" {
|
||||
// Or check the generated link
|
||||
continue
|
||||
}
|
||||
payload := gourl.Values{
|
||||
"link": {f.Link},
|
||||
}
|
||||
req, _ := http.NewRequest(http.MethodPost, url, strings.NewReader(payload.Encode()))
|
||||
resp, err := r.client.MakeRequest(req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
var data UnrestrictResponse
|
||||
@@ -287,8 +279,9 @@ func (r *RealDebrid) GenerateDownloadLinks(t *types.Torrent) error {
|
||||
}
|
||||
f.DownloadLink = data.Download
|
||||
f.Generated = time.Now()
|
||||
t.Files[f.Name] = f
|
||||
files[f.Name] = f
|
||||
}
|
||||
t.Files = files
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ func (q *QBit) ProcessFiles(torrent *Torrent, debridTorrent *debrid.Torrent, arr
|
||||
if ok {
|
||||
q.logger.Info().Msgf("Using internal webdav for %s", debridTorrent.Debrid)
|
||||
// Use webdav to download the file
|
||||
err := cache.ProcessTorrent(debridTorrent, true)
|
||||
err := cache.AddTorrent(debridTorrent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -13,12 +13,14 @@ import (
|
||||
|
||||
type WebDav struct {
|
||||
Handlers []*Handler
|
||||
ready chan struct{}
|
||||
}
|
||||
|
||||
func New() *WebDav {
|
||||
svc := service.GetService()
|
||||
w := &WebDav{
|
||||
Handlers: make([]*Handler, 0),
|
||||
ready: make(chan struct{}),
|
||||
}
|
||||
for name, c := range svc.Debrid.Caches {
|
||||
h := NewHandler(name, c, logger.NewLogger(fmt.Sprintf("%s-webdav", name)))
|
||||
@@ -38,6 +40,22 @@ func (wd *WebDav) Routes() http.Handler {
|
||||
wr := chi.NewRouter()
|
||||
wr.Use(wd.commonMiddleware)
|
||||
|
||||
// Create a readiness check middleware
|
||||
readinessMiddleware := func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
select {
|
||||
case <-wd.ready:
|
||||
// WebDAV is ready, proceed
|
||||
next.ServeHTTP(w, r)
|
||||
default:
|
||||
// WebDAV is still initializing
|
||||
w.Header().Set("Retry-After", "10")
|
||||
http.Error(w, "WebDAV service is initializing, please try again shortly", http.StatusServiceUnavailable)
|
||||
}
|
||||
})
|
||||
}
|
||||
wr.Use(readinessMiddleware)
|
||||
|
||||
wd.setupRootHandler(wr)
|
||||
wd.mountHandlers(wr)
|
||||
|
||||
@@ -65,6 +83,9 @@ func (wd *WebDav) Start(ctx context.Context) error {
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(errChan)
|
||||
|
||||
// Signal that WebDAV is ready
|
||||
close(wd.ready)
|
||||
}()
|
||||
|
||||
// Collect all errors
|
||||
|
||||
Reference in New Issue
Block a user