more progress on radios

This commit is contained in:
Drew Weymouth
2024-06-01 12:18:28 -07:00
parent 77d21717f6
commit bfa3dc9892
8 changed files with 70 additions and 11 deletions
@@ -424,6 +424,7 @@ func (s *subsonicMediaProvider) GetRadioStations() ([]*mediaprovider.RadioStatio
} }
return sharedutil.MapSlice(rs, func(rs *subsonic.InternetRadioStation) *mediaprovider.RadioStation { return sharedutil.MapSlice(rs, func(rs *subsonic.InternetRadioStation) *mediaprovider.RadioStation {
return &mediaprovider.RadioStation{ return &mediaprovider.RadioStation{
// TODO - subsonic library is missing ID in its radiostation object. add it
ID: "radio-" + strings.ReplaceAll(rs.Name, " ", ""), ID: "radio-" + strings.ReplaceAll(rs.Name, " ", ""),
Name: rs.Name, Name: rs.Name,
HomePageURL: rs.HomePageUrl, HomePageURL: rs.HomePageUrl,
+25
View File
@@ -235,6 +235,31 @@ func (p *playbackEngine) LoadTracks(tracks []*mediaprovider.Track, insertQueueMo
return nil return nil
} }
func (p *playbackEngine) LoadRadioStation(radio *mediaprovider.RadioStation, insertMode InsertQueueMode) {
if insertMode == Replace {
p.player.Stop()
p.nowPlayingIdx = -1
p.playQueue = nil
}
needToSetNext := insertMode == InsertNext || (insertMode == Append && p.nowPlayingIdx == len(p.playQueue)-1)
insertIdx := len(p.playQueue)
if insertMode == InsertNext {
insertIdx = p.nowPlayingIdx + 1
}
new := make([]mediaprovider.MediaItem, len(p.playQueue)+1)
firstHalf := p.playQueue[:insertIdx]
copy(new, firstHalf)
new[len(firstHalf)] = radio
copy(new[len(firstHalf)+1:], p.playQueue[insertIdx:])
p.playQueue = new
if needToSetNext {
p.setNextTrack(p.nowPlayingIdx + 1)
}
p.invokeNoArgCallbacks(p.onQueueChange)
}
// Stop playback and clear the play queue. // Stop playback and clear the play queue.
func (p *playbackEngine) StopAndClearPlayQueue() { func (p *playbackEngine) StopAndClearPlayQueue() {
changed := len(p.playQueue) > 0 changed := len(p.playQueue) > 0
+4
View File
@@ -182,6 +182,10 @@ func (p *PlaybackManager) PlaySimilarSongs(id string) {
}) })
} }
func (p *PlaybackManager) LoadRadioStation(station *mediaprovider.RadioStation, queueMode InsertQueueMode) {
p.engine.LoadRadioStation(station, queueMode)
}
func (p *PlaybackManager) fetchAndPlayTracks(fetchFn func() ([]*mediaprovider.Track, error)) { func (p *PlaybackManager) fetchAndPlayTracks(fetchFn func() ([]*mediaprovider.Track, error)) {
if songs, err := fetchFn(); err != nil { if songs, err := fetchFn(); err != nil {
log.Printf("error fetching tracks: %s", err.Error()) log.Printf("error fetching tracks: %s", err.Error())
+4 -2
View File
@@ -140,11 +140,13 @@ func (b *BrowsingPane) AddSettingsMenuSeparator() {
fyne.NewMenuItemSeparator()) fyne.NewMenuItemSeparator())
} }
func (b *BrowsingPane) AddNavigationButton(icon fyne.Resource, pageName controller.PageName, action func()) { func (b *BrowsingPane) AddNavigationButton(icon fyne.Resource, pageName controller.PageName, action func()) *widget.Button {
// make a copy of the icon, because it can change the color // make a copy of the icon, because it can change the color
browsingPaneIcon := theme.NewThemedResource(icon) browsingPaneIcon := theme.NewThemedResource(icon)
b.navBtnsContainer.Add(widget.NewButtonWithIcon("", browsingPaneIcon, action)) btn := widget.NewButtonWithIcon("", browsingPaneIcon, action)
b.navBtnsContainer.Add(btn)
b.navBtnsPageMap[pageName] = browsingPaneIcon b.navBtnsPageMap[pageName] = browsingPaneIcon
return btn
} }
func (b *BrowsingPane) DisableNavigationButtons() { func (b *BrowsingPane) DisableNavigationButtons() {
+16 -9
View File
@@ -5,6 +5,7 @@ import (
"net/url" "net/url"
"strings" "strings"
"github.com/dweymouth/supersonic/backend"
"github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/backend/mediaprovider"
"github.com/dweymouth/supersonic/sharedutil" "github.com/dweymouth/supersonic/sharedutil"
"github.com/dweymouth/supersonic/ui/controller" "github.com/dweymouth/supersonic/ui/controller"
@@ -25,6 +26,7 @@ type RadiosPage struct {
contr *controller.Controller contr *controller.Controller
rp mediaprovider.RadioProvider rp mediaprovider.RadioProvider
pm *backend.PlaybackManager
radios []*mediaprovider.RadioStation radios []*mediaprovider.RadioStation
list *RadioList list *RadioList
@@ -33,19 +35,24 @@ type RadiosPage struct {
searcher *widgets.SearchEntry searcher *widgets.SearchEntry
} }
func NewRadiosPage(contr *controller.Controller, rp mediaprovider.RadioProvider) *RadiosPage { func NewRadiosPage(contr *controller.Controller, rp mediaprovider.RadioProvider, pm *backend.PlaybackManager) *RadiosPage {
return newRadiosPage(contr, rp, "", 0) return newRadiosPage(contr, rp, pm, "", 0)
} }
func newRadiosPage(contr *controller.Controller, rp mediaprovider.RadioProvider, searchText string, scrollPos float32) *RadiosPage { func newRadiosPage(contr *controller.Controller, rp mediaprovider.RadioProvider, pm *backend.PlaybackManager, searchText string, scrollPos float32) *RadiosPage {
a := &RadiosPage{ a := &RadiosPage{
contr: contr, contr: contr,
rp: rp, rp: rp,
pm: pm,
titleDisp: widget.NewRichTextWithText("Internet Radio Stations"), titleDisp: widget.NewRichTextWithText("Internet Radio Stations"),
} }
a.ExtendBaseWidget(a) a.ExtendBaseWidget(a)
a.titleDisp.Segments[0].(*widget.TextSegment).Style.SizeName = theme.SizeNameHeadingText a.titleDisp.Segments[0].(*widget.TextSegment).Style.SizeName = theme.SizeNameHeadingText
a.list = NewRadioList() a.list = NewRadioList()
a.list.OnPlay = func(station *mediaprovider.RadioStation) {
pm.LoadRadioStation(station, backend.Replace)
pm.PlayFromBeginning()
}
a.searcher = widgets.NewSearchEntry() a.searcher = widgets.NewSearchEntry()
a.searcher.PlaceHolder = "Search page" a.searcher.PlaceHolder = "Search page"
a.searcher.OnSearched = a.onSearched a.searcher.OnSearched = a.onSearched
@@ -105,9 +112,7 @@ func (a *RadiosPage) Scroll(amount float32) {
} }
func (a *RadiosPage) Route() controller.Route { func (a *RadiosPage) Route() controller.Route {
// TODO return controller.RadiosRoute()
//return controller.RadiosRoute()
return controller.Route{}
} }
func (a *RadiosPage) Reload() { func (a *RadiosPage) Reload() {
@@ -118,6 +123,7 @@ func (a *RadiosPage) Save() SavedPage {
return &savedrRadiosPage{ return &savedrRadiosPage{
contr: a.contr, contr: a.contr,
rp: a.rp, rp: a.rp,
pm: a.pm,
searchText: a.searcher.Entry.Text, searchText: a.searcher.Entry.Text,
scrollPos: a.list.list.GetScrollOffset(), scrollPos: a.list.list.GetScrollOffset(),
} }
@@ -126,12 +132,13 @@ func (a *RadiosPage) Save() SavedPage {
type savedrRadiosPage struct { type savedrRadiosPage struct {
contr *controller.Controller contr *controller.Controller
rp mediaprovider.RadioProvider rp mediaprovider.RadioProvider
pm *backend.PlaybackManager
searchText string searchText string
scrollPos float32 scrollPos float32
} }
func (s *savedrRadiosPage) Restore() Page { func (s *savedrRadiosPage) Restore() Page {
return newRadiosPage(s.contr, s.rp, s.searchText, s.scrollPos) return newRadiosPage(s.contr, s.rp, s.pm, s.searchText, s.scrollPos)
} }
func (a *RadiosPage) buildContainer() { func (a *RadiosPage) buildContainer() {
@@ -150,7 +157,7 @@ func (a *RadiosPage) CreateRenderer() fyne.WidgetRenderer {
type RadioList struct { type RadioList struct {
widget.BaseWidget widget.BaseWidget
OnPlay func(string) OnPlay func(*mediaprovider.RadioStation)
radios []*mediaprovider.RadioStation radios []*mediaprovider.RadioStation
@@ -228,7 +235,7 @@ func (g *RadioList) SetRadios(radios []*mediaprovider.RadioStation) {
func (a *RadioList) onPlayRadio(item *mediaprovider.RadioStation) { func (a *RadioList) onPlayRadio(item *mediaprovider.RadioStation) {
if a.OnPlay != nil { if a.OnPlay != nil {
a.OnPlay(item.ID) a.OnPlay(item)
} }
} }
+4
View File
@@ -55,6 +55,10 @@ func (r Router) CreatePage(rte controller.Route) Page {
return NewPlaylistsPage(r.Controller, r.widgetPool, &r.App.Config.PlaylistsPage, r.App.ServerManager.Server) return NewPlaylistsPage(r.Controller, r.widgetPool, &r.App.Config.PlaylistsPage, r.App.ServerManager.Server)
case controller.Tracks: case controller.Tracks:
return NewTracksPage(r.Controller, &r.App.Config.TracksPage, r.widgetPool, r.App.ServerManager.Server, r.App.ImageManager) return NewTracksPage(r.Controller, &r.App.Config.TracksPage, r.widgetPool, r.App.ServerManager.Server, r.App.ImageManager)
case controller.Radios:
var rp mediaprovider.RadioProvider
rp, _ = r.App.ServerManager.Server.(mediaprovider.RadioProvider)
return NewRadiosPage(r.Controller, rp, r.App.PlaybackManager)
} }
return nil return nil
} }
+5
View File
@@ -15,6 +15,7 @@ const (
Playlist Playlist
Playlists Playlists
Tracks Tracks
Radios
) )
type Route struct { type Route struct {
@@ -61,6 +62,10 @@ func ArtistsRoute() Route {
return Route{Page: Artists} return Route{Page: Artists}
} }
func RadiosRoute() Route {
return Route{Page: Radios}
}
func NowPlayingRoute(highlightedTrackID string) Route { func NowPlayingRoute(highlightedTrackID string) Route {
return Route{Page: NowPlaying, Arg: highlightedTrackID} return Route{Page: NowPlaying, Arg: highlightedTrackID}
} }
+11
View File
@@ -53,6 +53,9 @@ type MainWindow struct {
theme *theme.MyTheme theme *theme.MyTheme
haveSystemTray bool haveSystemTray bool
container *fyne.Container container *fyne.Container
// needs to bes shown/hidden when switching between servers based on whether they support radio
radioBtn *widget.Button
} }
func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, app *backend.App, size fyne.Size) MainWindow { func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, app *backend.App, size fyne.Size) MainWindow {
@@ -183,6 +186,11 @@ func (m *MainWindow) RunOnServerConnectedTasks(app *backend.App, displayAppName
} }
m.App.Config.Application.LastCheckedVersion = t m.App.Config.Application.LastCheckedVersion = t
} }
_, supportsRadio := m.App.ServerManager.Server.(mediaprovider.RadioProvider)
m.radioBtn.Hidden = !supportsRadio
m.radioBtn.Refresh()
m.App.SaveConfigFile() m.App.SaveConfigFile()
} }
@@ -265,6 +273,9 @@ func (m *MainWindow) addNavigationButtons() {
m.BrowsingPane.AddNavigationButton(theme.TracksIcon, controller.Tracks, func() { m.BrowsingPane.AddNavigationButton(theme.TracksIcon, controller.Tracks, func() {
m.Router.NavigateTo(controller.TracksRoute()) m.Router.NavigateTo(controller.TracksRoute())
}) })
m.radioBtn = m.BrowsingPane.AddNavigationButton(theme.TracksIcon /*todo*/, controller.Radios, func() {
m.Router.NavigateTo(controller.RadiosRoute())
})
} }
func (m *MainWindow) addShortcuts() { func (m *MainWindow) addShortcuts() {