refactor: consolidate download domain into download package
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package download
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/mathismqn/godeez/internal/config"
|
||||
"github.com/mathismqn/godeez/internal/deezer"
|
||||
"github.com/mathismqn/godeez/internal/fsutil"
|
||||
"github.com/mathismqn/godeez/internal/store"
|
||||
)
|
||||
|
||||
type Downloader struct {
|
||||
appConfig *config.Config
|
||||
store *store.Store
|
||||
kind deezer.Kind
|
||||
deezerClient *deezer.Client
|
||||
|
||||
hashIndexOnce sync.Once
|
||||
hashIndex *hashIndex
|
||||
hashIndexErr error
|
||||
}
|
||||
|
||||
func New(appConfig *config.Config, st *store.Store, kind deezer.Kind) *Downloader {
|
||||
return &Downloader{
|
||||
appConfig: appConfig,
|
||||
store: st,
|
||||
kind: kind,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Downloader) Run(ctx context.Context, opts Options, id string) error {
|
||||
if err := d.initDeezerClient(ctx, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resource, outputDir, err := d.prepareResource(ctx, id, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.downloadAllTracks(ctx, resource, opts, outputDir)
|
||||
}
|
||||
|
||||
func (d *Downloader) initDeezerClient(ctx context.Context, opts Options) error {
|
||||
var err error
|
||||
d.deezerClient, err = deezer.NewClient(ctx, d.appConfig.ARLCookie)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !d.deezerClient.Session.Premium && (opts.Quality == "mp3_320" || opts.Quality == "flac") {
|
||||
return fmt.Errorf("premium account required for '%s' quality", opts.Quality)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Downloader) prepareResource(ctx context.Context, id string, opts Options) (deezer.Resource, string, error) {
|
||||
resource, err := d.deezerClient.FetchResource(ctx, d.kind, id)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to fetch resource: %w", err)
|
||||
}
|
||||
|
||||
tracks := resource.GetTracks()
|
||||
if len(tracks) == 0 {
|
||||
if d.kind == deezer.KindTrack {
|
||||
return nil, "", fmt.Errorf("track with ID %s not found", id)
|
||||
}
|
||||
return nil, "", fmt.Errorf("%s has no tracks", d.kind)
|
||||
}
|
||||
|
||||
if d.kind == deezer.KindArtist && len(tracks) > opts.Limit {
|
||||
resource.SetTracks(tracks[:opts.Limit])
|
||||
}
|
||||
|
||||
outputDir := resource.GetOutputDir(d.appConfig.OutputDir)
|
||||
if err := fsutil.EnsureDir(outputDir); err != nil {
|
||||
return nil, "", fmt.Errorf("failed to create output directory: %w", err)
|
||||
}
|
||||
|
||||
return resource, outputDir, nil
|
||||
}
|
||||
|
||||
func (d *Downloader) downloadAllTracks(ctx context.Context, resource deezer.Resource, opts Options, outputDir string) error {
|
||||
tracks := resource.GetTracks()
|
||||
startTime := time.Now()
|
||||
|
||||
if d.kind != deezer.KindTrack {
|
||||
fmt.Printf("%s\n\nStarting download...\n\n", resourceInfo(resource))
|
||||
}
|
||||
|
||||
progress := newProgressTracker(len(tracks), d.kind)
|
||||
|
||||
for i, track := range tracks {
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
sp := progress.startDownload(i, track)
|
||||
result := d.downloadTrack(ctx, resource, track, opts, outputDir)
|
||||
sp.Stop()
|
||||
|
||||
if result.err != nil && errors.Is(result.err, context.Canceled) {
|
||||
return result.err
|
||||
}
|
||||
|
||||
progress.handleResult(i, track, result)
|
||||
}
|
||||
|
||||
progress.printSummary(outputDir, time.Since(startTime))
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user