diff --git a/go.mod b/go.mod index 0df7973..c7aad35 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/cenkalti/dominantcolor v1.0.3 github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1 github.com/dweymouth/fyne-advanced-list v0.0.0-20250211191927-58ea85eec72c - github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64 github.com/dweymouth/fyne-tooltip v0.3.0 github.com/dweymouth/go-jellyfin v0.0.0-20250531151636-29591764f0a0 github.com/godbus/dbus/v5 v5.1.0 @@ -17,6 +16,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.7 github.com/pelletier/go-toml/v2 v2.0.8 github.com/quarckster/go-mpris-server v1.0.3 + github.com/supersonic-app/fyne-lyrics v0.0.0-20250614151306-b1880a70a410 github.com/supersonic-app/go-mpv v0.1.0 github.com/supersonic-app/go-subsonic v0.0.0-20241224013245-9b2841f3711d github.com/supersonic-app/go-upnpcast v0.0.0-20250330154256-b957204209a5 diff --git a/go.sum b/go.sum index a76ed23..5a8cf7e 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,6 @@ github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1 h1:mGvOb3zxl4vCLv+ github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1/go.mod h1:ZNCLJfehvEf34B7BbLKjgpsL9lyW7q938w/GY1XgV4E= github.com/dweymouth/fyne-advanced-list v0.0.0-20250211191927-58ea85eec72c h1:UXwfQ1CzSe7l8CSPr/Fyu0LViv0oRUDy3SEUafnSxdQ= github.com/dweymouth/fyne-advanced-list v0.0.0-20250211191927-58ea85eec72c/go.mod h1:Idgzr4LYzve8IPHF1stLO1bdGQZnDKt/bT9WfJflCGw= -github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64 h1:RUIrnGY034rDMlcOui/daurwX5b+52KdUKhH9aXaDSg= -github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64/go.mod h1:3YrjFDHMlhCsSZ/OvmJCxWm9QHSgOVWZBxnraZz9Z7c= github.com/dweymouth/fyne-tooltip v0.3.0 h1:NKCyTkh9NtvnTsiHtTOtaJzRDOFYP8AckQ2tyhOh6JY= github.com/dweymouth/fyne-tooltip v0.3.0/go.mod h1:m04ShLW/Tp6LXrNieTumApvNgo7YSB+wi+jZTN+kDBU= github.com/dweymouth/fyne/v2 v2.3.0-rc1.0.20250406173843-f5cb002423a5 h1:/gxlRSmndtF8QVxV3oFjlozm2clkMlLBlfiKFtehH+M= @@ -115,6 +113,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/supersonic-app/fyne-lyrics v0.0.0-20250614151306-b1880a70a410 h1:wuDHCo6SU6r0KMm0EuI5FGVJCuLK4hcuPcMKmln8oCA= +github.com/supersonic-app/fyne-lyrics v0.0.0-20250614151306-b1880a70a410/go.mod h1:XvGBPgXWkKrK+5OsoVkTcTZmwZac1Sj6miEn8q6uA20= github.com/supersonic-app/go-mpv v0.1.0 h1:U+cCnLQxmpqx5mY6nMlC0J4uIdCCXUbAjpjS04XkFu8= github.com/supersonic-app/go-mpv v0.1.0/go.mod h1:1bQz6kBQumJopXEbkiqoLxIXLy7F7yWFBvknvpAtIC0= github.com/supersonic-app/go-subsonic v0.0.0-20241224013245-9b2841f3711d h1:70+Nn7yh+cfeKqqXVTdpneFqXuvrBLyP7U6GVUsjTU4= diff --git a/ui/browsing/nowplayingpage.go b/ui/browsing/nowplayingpage.go index 30a2435..7bd3563 100644 --- a/ui/browsing/nowplayingpage.go +++ b/ui/browsing/nowplayingpage.go @@ -39,6 +39,7 @@ type NowPlayingPage struct { // volatile state nowPlaying mediaprovider.MediaItem nowPlayingID string + curLyrics *mediaprovider.Lyrics curLyricsID string // id of track currently shown in lyrics curRelatedID string // id of track currrently used to populate related list totalTime float64 @@ -177,13 +178,20 @@ func NewNowPlayingPage( a.relatedList.OnShowTrackInfo = func(track *mediaprovider.Track) { a.contr.ShowTrackInfoDialog(track) } - a.lyricsViewer = widgets.NewLyricsViewer() + a.lyricsViewer = widgets.NewLyricsViewer(a.onSeekToLyricLine) a.statusLabel = widget.NewLabel(lang.L("Stopped")) a.Reload() return a } +func (a *NowPlayingPage) onSeekToLyricLine(lineNum int) { + if a.curLyrics != nil && len(a.curLyrics.Lines) > lineNum-1 { + time := a.curLyrics.Lines[lineNum-1].Start + a.pm.SeekSeconds(time) + } +} + func (a *NowPlayingPage) CreateRenderer() fyne.WidgetRenderer { if a.container == nil { initialTab := 0 @@ -341,6 +349,7 @@ func (a *NowPlayingPage) updateLyrics() { } if a.nowPlaying == nil || a.nowPlaying.Metadata().Type == mediaprovider.MediaItemTypeRadioStation { a.lyricsViewer.SetLyrics(nil) + a.curLyrics = nil a.curLyricsID = "" return } @@ -350,6 +359,7 @@ func (a *NowPlayingPage) updateLyrics() { a.lyricsLoading.Start() // set the widget to an empty (not nil) lyric during fetch // to keep it from showing "Lyrics not available" + a.lyricsViewer.DisableTapToSeek() a.lyricsViewer.SetLyrics(&mediaprovider.Lyrics{Synced: true, Lines: []mediaprovider.LyricLine{{Text: ""}}}) tr, _ := a.nowPlaying.(*mediaprovider.Track) @@ -376,7 +386,9 @@ func (a *NowPlayingPage) fetchLyrics(ctx context.Context, song *mediaprovider.Tr default: fyne.Do(func() { a.lyricsLoading.Stop() + a.lyricsViewer.EnableTapToSeek() a.lyricsViewer.SetLyrics(lyrics) + a.curLyrics = lyrics if lyrics != nil { a.lyricsViewer.OnSeeked(a.lastPlayPos) } diff --git a/ui/widgets/lyricsviewer.go b/ui/widgets/lyricsviewer.go index e8c1904..ffce8dd 100644 --- a/ui/widgets/lyricsviewer.go +++ b/ui/widgets/lyricsviewer.go @@ -5,9 +5,9 @@ import ( "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/lang" "fyne.io/fyne/v2/widget" - fynelyrics "github.com/dweymouth/fyne-lyrics" "github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/ui/theme" + fynelyrics "github.com/supersonic-app/fyne-lyrics" ) type LyricsViewer struct { @@ -23,21 +23,36 @@ type LyricsViewer struct { // for the current lyrics firstUpdate bool + onSeekToLine func(int) + container *fyne.Container isEmpty bool } -func NewLyricsViewer() *LyricsViewer { +func NewLyricsViewer(onSeekToLine func(int)) *LyricsViewer { l := &LyricsViewer{ noLyricsMsg: container.NewCenter(NewInfoMessage( lang.L("Lyrics not available"), "")), - isEmpty: true, + isEmpty: true, + onSeekToLine: onSeekToLine, } l.ExtendBaseWidget(l) l.container = container.NewStack(l.noLyricsMsg) return l } +func (l *LyricsViewer) DisableTapToSeek() { + if l.viewer != nil { + l.viewer.OnLyricTapped = nil + } +} + +func (l *LyricsViewer) EnableTapToSeek() { + if l.viewer != nil { + l.viewer.OnLyricTapped = l.onSeekToLine + } +} + func (l *LyricsViewer) SetLyrics(lyrics *mediaprovider.Lyrics) { l.lyrics = lyrics l.nextLyricLine = 0 @@ -55,6 +70,7 @@ func (l *LyricsViewer) SetLyrics(lyrics *mediaprovider.Lyrics) { l.viewer = fynelyrics.NewLyricsViewer() l.viewer.ActiveLyricPosition = fynelyrics.ActiveLyricPositionUpperMiddle l.viewer.InactiveLyricColorName = theme.ColorNameInactiveLyric + l.viewer.OnLyricTapped = l.onSeekToLine } lines := make([]string, len(lyrics.Lines)) for i, line := range lyrics.Lines {