Ability to download tracks
- Adding the option to download the selected track or tracks. When the download is clicked it opens a dialog that lets you choose where you want to save the track and the file name (by default the file name is the track number, the track name and the extension, example "03 - my song.mp3") If there are many tracks selected it will open one dialog for each track - Next steps: download an album and a playlist using zip
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package mediaprovider
|
||||
|
||||
import "image"
|
||||
import (
|
||||
"image"
|
||||
"io"
|
||||
)
|
||||
|
||||
type AlbumFilter struct {
|
||||
MinYear int
|
||||
@@ -83,4 +86,6 @@ type MediaProvider interface {
|
||||
DeletePlaylist(id string) error
|
||||
|
||||
Scrobble(trackID string, submission bool) error
|
||||
|
||||
DownloadTrack(trackID string) (io.Reader, error)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package subsonic
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
"sync"
|
||||
@@ -249,6 +250,10 @@ func (s *subsonicMediaProvider) SetRating(params mediaprovider.RatingFavoritePar
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) DownloadTrack(trackID string) (io.Reader, error) {
|
||||
return s.client.Download(trackID)
|
||||
}
|
||||
|
||||
func toTrack(ch *subsonic.Child) *mediaprovider.Track {
|
||||
if ch == nil {
|
||||
return nil
|
||||
|
||||
@@ -7,7 +7,7 @@ require (
|
||||
fyne.io/x/fyne v0.0.0-20230611151101-afdcd6b92cf3
|
||||
github.com/20after4/configdir v0.1.1
|
||||
github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20230513020020-0790f53c2868
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20230614154319-792d18c75fb4
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/pelletier/go-toml v1.9.3
|
||||
github.com/zalando/go-keyring v0.2.1
|
||||
|
||||
@@ -80,6 +80,8 @@ github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee h1:ZGyJ6wp7CAfT31
|
||||
github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee/go.mod h1:Ov0ieN90M7i+0k3OxhA/g1dozGs+UcPHDsMKqPgRDk0=
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20230513020020-0790f53c2868 h1:403Dden/cdQyDM8ydonHLxTBPjgQXZ76PUfmBG92+Dw=
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20230513020020-0790f53c2868/go.mod h1:fUez6NFiEJiQTZizZ1BThZr5GJXAbigzGYjEPNm4tdI=
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20230614154319-792d18c75fb4 h1:cuyvB4GjTMBHKJwMJ/LFpuKfSVXuCheNj6fgxBa3m1Y=
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20230614154319-792d18c75fb4/go.mod h1:fUez6NFiEJiQTZizZ1BThZr5GJXAbigzGYjEPNm4tdI=
|
||||
github.com/eclipse/paho.mqtt.golang v1.3.5/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
||||
@@ -3,7 +3,10 @@ package controller
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dweymouth/supersonic/backend"
|
||||
@@ -113,6 +116,7 @@ func (m *Controller) ConnectTracklistActions(tracklist *widgets.Tracklist) {
|
||||
tracklist.OnColumnVisibilityMenuShown = func(pop *widget.PopUp) {
|
||||
m.ClosePopUpOnEscape(pop)
|
||||
}
|
||||
tracklist.OnShowDownloadDialog = m.ShowDownloadDialog
|
||||
}
|
||||
|
||||
func (m *Controller) ConnectAlbumGridActions(grid *widgets.GridView) {
|
||||
@@ -516,3 +520,49 @@ func (c *Controller) SetTrackRatings(trackIDs []string, rating int) {
|
||||
c.App.PlaybackManager.OnTrackRatingChanged(id, rating)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) ShowDownloadDialog(track *mediaprovider.Track) {
|
||||
parts := strings.Split(track.FilePath, "/")
|
||||
fileName := parts[len(parts)-1]
|
||||
|
||||
dg := dialog.NewFileSave(
|
||||
func(file fyne.URIWriteCloser, err error) {
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if file == nil {
|
||||
return
|
||||
}
|
||||
|
||||
filePath := file.URI().Path()
|
||||
go c.downloadTrack(track.ID, filePath)
|
||||
},
|
||||
c.MainWindow)
|
||||
dg.SetFileName(fileName)
|
||||
dg.Show()
|
||||
}
|
||||
|
||||
func (c *Controller) downloadTrack(trackID, filePath string) {
|
||||
reader, err := c.App.ServerManager.Server.DownloadTrack(trackID)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
saveDir, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer saveDir.Close()
|
||||
|
||||
_, err = io.Copy(saveDir, reader)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Saved song to: %s\n", saveDir.Name())
|
||||
}
|
||||
|
||||
+17
-6
@@ -70,12 +70,13 @@ type Tracklist struct {
|
||||
DisableSorting bool
|
||||
|
||||
// user action callbacks
|
||||
OnPlayTrackAt func(int)
|
||||
OnPlaySelection func(tracks []*mediaprovider.Track, shuffle bool)
|
||||
OnAddToQueue func(trackIDs []*mediaprovider.Track)
|
||||
OnAddToPlaylist func(trackIDs []string)
|
||||
OnSetFavorite func(trackIDs []string, fav bool)
|
||||
OnSetRating func(trackIDs []string, rating int)
|
||||
OnPlayTrackAt func(int)
|
||||
OnPlaySelection func(tracks []*mediaprovider.Track, shuffle bool)
|
||||
OnAddToQueue func(trackIDs []*mediaprovider.Track)
|
||||
OnAddToPlaylist func(trackIDs []string)
|
||||
OnSetFavorite func(trackIDs []string, fav bool)
|
||||
OnSetRating func(trackIDs []string, rating int)
|
||||
OnShowDownloadDialog func(track *mediaprovider.Track)
|
||||
|
||||
OnShowArtistPage func(artistID string)
|
||||
OnShowAlbumPage func(albumID string)
|
||||
@@ -508,6 +509,10 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
|
||||
t.OnAddToPlaylist(t.SelectedTrackIDs())
|
||||
}
|
||||
}))
|
||||
t.ctxMenu.Items = append(t.ctxMenu.Items,
|
||||
fyne.NewMenuItem("Download", func() {
|
||||
t.onDownload(t.selectedTracks())
|
||||
}))
|
||||
t.ctxMenu.Items = append(t.ctxMenu.Items, fyne.NewMenuItemSeparator())
|
||||
t.ctxMenu.Items = append(t.ctxMenu.Items,
|
||||
fyne.NewMenuItem("Set favorite", func() {
|
||||
@@ -582,6 +587,12 @@ func (t *Tracklist) onAlbumTapped(albumID string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tracklist) onDownload(tracks []*mediaprovider.Track) {
|
||||
for _, track := range tracks {
|
||||
t.OnShowDownloadDialog(track)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tracklist) findTrackByID(id string) *mediaprovider.Track {
|
||||
idx := sharedutil.Find(t.tracks, func(tr *trackModel) bool {
|
||||
return tr.track.ID == id
|
||||
|
||||
Reference in New Issue
Block a user