2024-11-15 13:39:56 +00:00
|
|
|
package qbittorrent
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"log/slog"
|
|
|
|
"os"
|
|
|
|
"path"
|
2024-12-15 21:43:04 +00:00
|
|
|
"slices"
|
2024-11-15 13:39:56 +00:00
|
|
|
|
|
|
|
"git.kmsign.ru/royalcat/tstor/pkg/qbittorrent"
|
|
|
|
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
|
|
|
)
|
|
|
|
|
2024-11-24 17:33:44 +00:00
|
|
|
func (d *Daemon) Cleanup(ctx context.Context, run bool) ([]string, error) {
|
2024-11-15 13:39:56 +00:00
|
|
|
d.log.Info(ctx, "cleanup started")
|
|
|
|
|
2024-12-15 21:43:04 +00:00
|
|
|
torrentInfos, err := d.client.qb.Torrent().GetTorrents(ctx, &qbittorrent.TorrentOption{})
|
|
|
|
if err != nil {
|
|
|
|
d.log.Error(ctx, "failed to get torrents", rlog.Error(err))
|
|
|
|
return nil, fmt.Errorf("failed to get torrents: %w", err)
|
|
|
|
}
|
|
|
|
daemonsHashes := []string{}
|
|
|
|
for _, info := range torrentInfos {
|
|
|
|
daemonsHashes = append(daemonsHashes, info.Hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
dataDirs, err := os.ReadDir(d.dataDir)
|
|
|
|
if err != nil {
|
|
|
|
d.log.Error(ctx, "failed to read data directory", slog.String("path", d.dataDir), rlog.Error(err))
|
|
|
|
return nil, fmt.Errorf("failed to read data directory: %w", err)
|
|
|
|
}
|
|
|
|
dataHashes := []string{}
|
|
|
|
for _, entry := range dataDirs {
|
|
|
|
dataHashes = append(dataHashes, entry.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
hashToDelete := make([]string, 0, 5)
|
|
|
|
|
|
|
|
for _, v := range dataHashes {
|
|
|
|
if !slices.Contains(daemonsHashes, v) {
|
|
|
|
hashToDelete = append(hashToDelete, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d.log.Info(ctx, "marked torrents to delete",
|
|
|
|
slog.Int("count", len(hashToDelete)),
|
|
|
|
slog.Any("infohashes", hashToDelete),
|
|
|
|
)
|
|
|
|
|
|
|
|
if !run {
|
|
|
|
d.log.Info(ctx, "dry run, skipping deletion")
|
|
|
|
return hashToDelete, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, hash := range hashToDelete {
|
|
|
|
d.log.Info(ctx, "deleting stale torrent data", slog.String("infohash", hash))
|
|
|
|
err := os.RemoveAll(path.Join(d.dataDir, hash))
|
|
|
|
if err != nil {
|
|
|
|
d.log.Error(ctx, "failed to delete torrent data", slog.String("infohash", hash), rlog.Error(err))
|
|
|
|
return nil, fmt.Errorf("failed to delete torrent data: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return hashToDelete, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Daemon) CleanupUnregistred(ctx context.Context, run bool) ([]string, error) {
|
|
|
|
d.log.Info(ctx, "cleanup started")
|
|
|
|
|
2024-11-15 13:39:56 +00:00
|
|
|
torrentInfos, err := d.client.qb.Torrent().GetTorrents(ctx, &qbittorrent.TorrentOption{})
|
|
|
|
if err != nil {
|
|
|
|
d.log.Error(ctx, "failed to get torrents", rlog.Error(err))
|
|
|
|
return nil, fmt.Errorf("failed to get torrents: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
torrentToDelete := make([]string, 0, 5)
|
|
|
|
|
|
|
|
for _, info := range torrentInfos {
|
|
|
|
if d.registeredTorrents.Contains(info.Hash) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
d.log.Info(ctx, "torrent not found in registry", slog.String("infohash", info.Hash))
|
|
|
|
torrentToDelete = append(torrentToDelete, info.Hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
d.log.Info(ctx, "marked torrents to delete",
|
|
|
|
slog.Int("count", len(torrentToDelete)),
|
|
|
|
slog.Any("infohashes", torrentToDelete),
|
|
|
|
)
|
|
|
|
|
2024-11-24 17:33:44 +00:00
|
|
|
if !run {
|
2024-11-15 13:39:56 +00:00
|
|
|
d.log.Info(ctx, "dry run, skipping deletion")
|
|
|
|
return torrentToDelete, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err = d.client.qb.Torrent().DeleteTorrents(ctx, torrentToDelete, true)
|
|
|
|
if err != nil {
|
|
|
|
d.log.Error(ctx, "failed to delete torrents", slog.Any("infohashes", torrentToDelete), rlog.Error(err))
|
|
|
|
return nil, fmt.Errorf("failed to delete torrents: %w", err)
|
|
|
|
}
|
|
|
|
d.log.Info(ctx, "torrents deleted from qbittorrent", slog.Int("count", len(torrentToDelete)))
|
|
|
|
|
|
|
|
for _, hash := range torrentToDelete {
|
|
|
|
torrentPath := path.Join(d.dataDir, hash)
|
|
|
|
_, err := os.Stat(torrentPath)
|
|
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
d.log.Error(ctx, "failed to get torrent path", slog.String("path", torrentPath), rlog.Error(err))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
d.log.Warn(ctx, "leftover data for torrent detected, cleaning up", slog.String("infohash", hash), slog.String("path", torrentPath))
|
|
|
|
}
|
|
|
|
|
|
|
|
return torrentToDelete, nil
|
|
|
|
}
|