Skip to content

Commit 5e3793a

Browse files
committed
DRY downloader checker
Fix post rebase Remove redeclarations
1 parent 29b1b60 commit 5e3793a

File tree

2 files changed

+67
-61
lines changed

2 files changed

+67
-61
lines changed

src/config/config.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ type Config struct {
2222
Persist bool
2323
System string `env:"EXPLO_SYSTEM"`
2424
Debug bool `env:"DEBUG" env-default:"false"`
25-
<<<<<<< HEAD
2625
LogLevel string `env:"LOG_LEVEL" env-default:"INFO"`
27-
=======
28-
>>>>>>> 2065c16 (Remove timeout from main.go)
2926
}
3027

3128
type Flags struct {
@@ -71,6 +68,8 @@ type Lidarr struct {
7168
APIKey string `env:"LIDARR_API_KEY"`
7269
Retry int `env:"LIDARR_RETRY" env-default:"5"` // Number of times to check search status before skipping the track
7370
DownloadAttempts int `env:"LIDARR_DL_ATTEMPTS" env-default:"3"` // Max number of files to attempt downloading per track
71+
LidarrDir string `env:"LIDARR_DIR" env-default:"/lidarr/"`
72+
MigrateDL bool `env:"MIGRATE_DOWNLOADS" env-default:"false"` // Move downloads from SlskdDir to DownloadDir
7473
Timeout time.Duration `env:"LIDARR_TIMEOUT" env-default:"20s"`
7574
Scheme string `env:"LIDARR_SCHEME" env-default:"http"`
7675
URL string `env:"LIDARR_URL"`
@@ -143,6 +142,10 @@ type Listenbrainz struct {
143142
}
144143

145144
func (cfg *Config) ReadEnv() {
145+
}
146+
147+
func ReadEnv() Config {
148+
var cfg Config
146149

147150
// Try to read from .env file first
148151
err := cleanenv.ReadConfig(cfg.Flags.CfgPath, cfg)

src/downloader/lidarr.go

Lines changed: 61 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ package downloader
22

33
import (
44
"bytes"
5-
"context"
65
"encoding/json"
76
"fmt"
8-
"log"
97
"net/url"
108
"strings"
119
"time"
1210

1311
cfg "explo/src/config"
12+
"explo/src/debug"
1413
"explo/src/models"
1514
"explo/src/util"
1615
)
@@ -174,15 +173,15 @@ type RootFolder struct {
174173
DefaultQualityProfileId int `json:"defaultQualityProfileId"`
175174
}
176175

177-
func NewLidarr(cfg cfg.Lidarr, discovery, downloadDir string, httpClient *util.HttpClient) *Lidarr { // init downloader cfg for lidarr
178-
return &Lidarr{
176+
func NewLidarr(cfg cfg.Lidarr, discovery, downloadDir string, httpClient *util.HttpClient) Lidarr { // init downloader cfg for lidarr
177+
return Lidarr{
179178
DownloadDir: downloadDir,
180179
HttpClient: httpClient,
181180
Cfg: cfg,
182181
}
183182
}
184183

185-
func (c *Lidarr) QueryTrack(track *models.Track) error {
184+
func (c Lidarr) QueryTrack(track *models.Track) error {
186185

187186
album, err := c.findBestAlbumMatch(track)
188187
if err != nil {
@@ -211,15 +210,12 @@ func (c *Lidarr) QueryTrack(track *models.Track) error {
211210
return nil
212211
}
213212

214-
func (c *Lidarr) GetTrack(track *models.Track) error {
215-
ctx := context.Background()
213+
func (c Lidarr) GetTrack(track *models.Track) error {
216214

217215
if track.Present {
218216
return nil
219217
}
220218

221-
c.startQueueWorker(ctx, track)
222-
223219
// Get the defaults from the root dir
224220
queryURL := fmt.Sprintf("%s://%s/api/v1/rootfolder?apiKey=%s", c.Cfg.Scheme, c.Cfg.URL, c.Cfg.APIKey)
225221

@@ -273,7 +269,7 @@ func (c *Lidarr) GetTrack(track *models.Track) error {
273269
return nil
274270
}
275271

276-
func (c *Lidarr) findBestAlbumMatch(track *models.Track) (*Album, error) {
272+
func (c Lidarr) findBestAlbumMatch(track *models.Track) (*Album, error) {
277273
escQuery := url.PathEscape(fmt.Sprintf("%s - %s", track.Album, track.MainArtist))
278274
queryURL := fmt.Sprintf("%s://%s/api/v1/album/lookup?apiKey=%s&term=%s", c.Cfg.Scheme, c.Cfg.URL, c.Cfg.APIKey, escQuery)
279275

@@ -305,66 +301,73 @@ func (c *Lidarr) findBestAlbumMatch(track *models.Track) (*Album, error) {
305301
return &topMatch, nil
306302
}
307303

308-
func (c *Lidarr) startQueueWorker(ctx context.Context, track *models.Track) {
309-
go func() {
310-
ticker := time.NewTicker(5 * time.Minute)
311-
defer ticker.Stop()
312-
313-
for {
314-
select {
315-
case <-ctx.Done():
316-
log.Println("Queue worker stopped")
317-
return
318-
case <-ticker.C:
319-
if err := c.monitorQueue(track); err != nil {
320-
log.Printf("Queue worker error: %v", err)
321-
}
322-
}
323-
}
324-
}()
304+
func (c Lidarr) MonitorDownloads(tracks []*models.Track) error {
305+
monitorCfg := MonitorConfig{
306+
CheckInterval: 1 * time.Minute,
307+
MonitorDuration: 15 * time.Minute,
308+
MigrateDownload: c.Cfg.MigrateDL,
309+
FromDir: c.Cfg.LidarrDir,
310+
ToDir: c.DownloadDir,
311+
}
312+
err := Monitor(
313+
tracks,
314+
c.getDownloadStatus,
315+
func(t *models.Track, id string) { c.cleanupTrack(t, id) },
316+
moveDownload,
317+
monitorCfg,
318+
)
319+
if err != nil {
320+
return err
321+
}
322+
return nil
325323
}
326324

327-
func (c *Lidarr) monitorQueue(track *models.Track) error {
328-
queryURL := fmt.Sprintf("%s://%s/api/v1/queue?apiKey=%s", c.Cfg.Scheme, c.Cfg.URL, c.Cfg.APIKey)
325+
func (c Lidarr) getDownloadStatus() (DownloadStatus, error) {
326+
reqParams := "/api/v0/transfers/downloads"
329327

330-
body, err := c.HttpClient.MakeRequest("GET", queryURL, nil, nil)
328+
body, err := c.HttpClient.MakeRequest("GET", c.Cfg.URL+reqParams, nil, nil)
331329
if err != nil {
332-
return fmt.Errorf("failed to lookup tracks: %w", err)
330+
return nil, err
333331
}
334332

335-
var queue LidarrQueue
336-
if err = util.ParseResp(body, &queue); err != nil {
337-
return fmt.Errorf("failed to unmarshal query lidarr body: %w", err)
333+
var status DownloadStatus
334+
if err := util.ParseResp(body, &status); err != nil {
335+
return nil, err
338336
}
337+
return status, nil
338+
}
339339

340-
for _, record := range queue.Records {
341-
// skip invalid or incomplete entries
342-
if record.Size == 0 || record.SizeLeft == 0 {
343-
continue
344-
}
345-
346-
// Check if download is older than 15 minutes and has not progressed
347-
age := time.Since(record.Added)
348-
349-
if age > 15*time.Minute && record.Size == record.SizeLeft {
350-
log.Printf("Removing stale download: %s (no progress in %v)", record.Title, age)
340+
func (c Lidarr) cleanupTrack(track *models.Track, fileID string) {
341+
if err := c.deleteSearch(track.ID); err != nil {
342+
debug.Debug(fmt.Sprintf("[slskd] failed to delete search request: %v", err))
343+
}
344+
if err := c.deleteDownload(track.MainArtistID, fileID); err != nil {
345+
debug.Debug(fmt.Sprintf("[slskd] failed to delete download: %v", err))
346+
}
347+
}
351348

352-
deleteURL := fmt.Sprintf("%s://%s/api/v1/queue/%v?apiKey=%s", c.Cfg.Scheme, c.Cfg.URL, record.ID, c.Cfg.APIKey)
349+
func (c Lidarr) deleteSearch(ID string) error {
350+
reqParams := fmt.Sprintf("/api/v0/searches/%s", ID)
353351

354-
_, err = c.HttpClient.MakeRequest("DELETE", deleteURL, nil, nil)
355-
if err != nil {
356-
return fmt.Errorf("failed to delete record %d from queue: %v", record.ID, err)
357-
}
358-
continue
359-
}
352+
_, err := c.HttpClient.MakeRequest("DELETE", c.Cfg.URL+reqParams, nil, nil)
353+
if err != nil {
354+
return err
355+
}
356+
return nil
357+
}
360358

361-
if record.SizeLeft == 0 && record.TrackHasFileCount > 0 {
362-
log.Printf("Marking downloaded tracks from album %d as present", record.AlbumID)
359+
func (c Lidarr) deleteDownload(user, ID string) error {
360+
reqParams := fmt.Sprintf("/api/v0/transfers/downloads/%s/%s", user, ID)
363361

364-
if track.Album == record.Artist[0].Album.ForeignAlbumID {
365-
track.Present = true
366-
}
367-
}
362+
// cancel download
363+
if _, err := c.HttpClient.MakeRequest("DELETE", c.Cfg.URL+reqParams+"?remove=false", nil, nil); err != nil {
364+
return fmt.Errorf("soft delete failed: %s", err.Error())
365+
}
366+
time.Sleep(1 * time.Second) // Small buffer between soft and hard delete
367+
// delete download
368+
if _, err := c.HttpClient.MakeRequest("DELETE", c.Cfg.URL+reqParams+"?remove=true", nil, nil); err != nil {
369+
return fmt.Errorf("hard delete failed: %s", err.Error())
368370
}
371+
369372
return nil
370373
}

0 commit comments

Comments
 (0)