navidrome/core/archiver.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

94 lines
2.0 KiB
Go
Raw Normal View History

package core
import (
"archive/zip"
"context"
"fmt"
"io"
"os"
"path/filepath"
"github.com/Masterminds/squirrel"
"github.com/deluan/navidrome/log"
"github.com/deluan/navidrome/model"
)
type Archiver interface {
Zip(ctx context.Context, id string, w io.Writer) error
}
func NewArchiver(ds model.DataStore) Archiver {
return &archiver{ds: ds}
}
type archiver struct {
ds model.DataStore
}
func (a *archiver) Zip(ctx context.Context, id string, out io.Writer) error {
mfs, err := a.loadTracks(ctx, id)
if err != nil {
log.Error(ctx, "Error loading media", "id", id, err)
return err
}
z := zip.NewWriter(out)
for _, mf := range mfs {
_ = a.addFileToZip(ctx, z, mf)
}
err = z.Close()
if err != nil {
log.Error(ctx, "Error closing zip file", "id", id, err)
}
return err
}
func (a *archiver) addFileToZip(ctx context.Context, z *zip.Writer, mf model.MediaFile) error {
_, file := filepath.Split(mf.Path)
2020-08-04 19:38:32 +02:00
w, err := z.CreateHeader(&zip.FileHeader{
Name: fmt.Sprintf("%s/%s", mf.Album, file),
Modified: mf.UpdatedAt,
Method: zip.Store,
})
if err != nil {
log.Error(ctx, "Error creating zip entry", "file", mf.Path, err)
return err
}
f, err := os.Open(mf.Path)
defer func() { _ = f.Close() }()
if err != nil {
log.Error(ctx, "Error opening file for zipping", "file", mf.Path, err)
return err
}
_, err = io.Copy(w, f)
if err != nil {
log.Error(ctx, "Error zipping file", "file", mf.Path, err)
return err
}
return nil
}
func (a *archiver) loadTracks(ctx context.Context, id string) (model.MediaFiles, error) {
exist, err := a.ds.Album(ctx).Exists(id)
if err != nil {
return nil, err
}
if exist {
return a.ds.MediaFile(ctx).FindByAlbum(id)
}
exist, err = a.ds.Artist(ctx).Exists(id)
if err != nil {
return nil, err
}
if exist {
return a.ds.MediaFile(ctx).GetAll(model.QueryOptions{
Sort: "album",
Filters: squirrel.Eq{"album_artist_id": id},
})
}
mf, err := a.ds.MediaFile(ctx).Get(id)
if err != nil {
return nil, err
}
return model.MediaFiles{*mf}, nil
}