150 lines
3.0 KiB
Go
150 lines
3.0 KiB
Go
package repair
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/sirrobot01/debrid-blackhole/internal/request"
|
|
"golang.org/x/sync/errgroup"
|
|
"runtime"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
func (r *Repair) clean(job *Job) error {
|
|
// Create a new error group
|
|
g, ctx := errgroup.WithContext(context.Background())
|
|
|
|
uniqueItems := make(map[string]string)
|
|
mu := sync.Mutex{}
|
|
|
|
// Limit concurrent goroutines
|
|
g.SetLimit(10)
|
|
|
|
for _, a := range job.Arrs {
|
|
a := a // Capture range variable
|
|
g.Go(func() error {
|
|
// Check if context was canceled
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
default:
|
|
}
|
|
|
|
items, err := r.cleanArr(job, a, "")
|
|
if err != nil {
|
|
r.logger.Error().Err(err).Msgf("Error cleaning %s", a)
|
|
return err
|
|
}
|
|
|
|
// Safely append the found items to the shared slice
|
|
if len(items) > 0 {
|
|
mu.Lock()
|
|
for k, v := range items {
|
|
uniqueItems[k] = v
|
|
}
|
|
mu.Unlock()
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
if err := g.Wait(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(uniqueItems) == 0 {
|
|
job.CompletedAt = time.Now()
|
|
job.Status = JobCompleted
|
|
|
|
go func() {
|
|
if err := request.SendDiscordMessage("repair_clean_complete", "success", job.discordContext()); err != nil {
|
|
r.logger.Error().Msgf("Error sending discord message: %v", err)
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
cache := r.deb.Caches["realdebrid"]
|
|
if cache == nil {
|
|
return fmt.Errorf("cache not found")
|
|
}
|
|
torrents := cache.GetTorrents()
|
|
|
|
dangling := make([]string, 0)
|
|
for _, t := range torrents {
|
|
if _, ok := uniqueItems[t.Name]; !ok {
|
|
dangling = append(dangling, t.Id)
|
|
}
|
|
}
|
|
|
|
r.logger.Info().Msgf("Found %d delapitated items", len(dangling))
|
|
|
|
if len(dangling) == 0 {
|
|
job.CompletedAt = time.Now()
|
|
job.Status = JobCompleted
|
|
return nil
|
|
}
|
|
|
|
client := r.deb.Clients["realdebrid"]
|
|
if client == nil {
|
|
return fmt.Errorf("client not found")
|
|
}
|
|
for _, id := range dangling {
|
|
err := client.DeleteTorrent(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Repair) cleanArr(j *Job, _arr string, tmdbId string) (map[string]string, error) {
|
|
uniqueItems := make(map[string]string)
|
|
a := r.arrs.Get(_arr)
|
|
|
|
r.logger.Info().Msgf("Starting repair for %s", a.Name)
|
|
media, err := a.GetMedia(tmdbId)
|
|
if err != nil {
|
|
r.logger.Info().Msgf("Failed to get %s media: %v", a.Name, err)
|
|
return uniqueItems, err
|
|
}
|
|
|
|
// Create a new error group
|
|
g, ctx := errgroup.WithContext(context.Background())
|
|
|
|
mu := sync.Mutex{}
|
|
|
|
// Limit concurrent goroutines
|
|
g.SetLimit(runtime.NumCPU() * 4)
|
|
|
|
for _, m := range media {
|
|
m := m // Create a new variable scoped to the loop iteration
|
|
g.Go(func() error {
|
|
// Check if context was canceled
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
default:
|
|
}
|
|
|
|
u := r.getUniquePaths(m)
|
|
for k, v := range u {
|
|
mu.Lock()
|
|
uniqueItems[k] = v
|
|
mu.Unlock()
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
if err := g.Wait(); err != nil {
|
|
return uniqueItems, err
|
|
}
|
|
|
|
r.logger.Info().Msgf("Repair completed for %s. %d unique items", a.Name, len(uniqueItems))
|
|
return uniqueItems, nil
|
|
}
|