add LyricsProvider / GetLyrics
This commit is contained in:
@@ -154,6 +154,10 @@ type SupportsSharing interface {
|
|||||||
CanShareArtists() bool
|
CanShareArtists() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LyricsProvider interface {
|
||||||
|
GetLyrics(track *Track) (*Lyrics, error)
|
||||||
|
}
|
||||||
|
|
||||||
type JukeboxProvider interface {
|
type JukeboxProvider interface {
|
||||||
JukeboxStart() error
|
JukeboxStart() error
|
||||||
JukeboxStop() error
|
JukeboxStop() error
|
||||||
|
|||||||
@@ -120,6 +120,18 @@ type PlaylistWithTracks struct {
|
|||||||
Tracks []*Track
|
Tracks []*Track
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Lyrics struct {
|
||||||
|
Title string
|
||||||
|
Artist string
|
||||||
|
Synced bool
|
||||||
|
Lines []LyricLine
|
||||||
|
}
|
||||||
|
|
||||||
|
type LyricLine struct {
|
||||||
|
Text string
|
||||||
|
Start float64 // seconds
|
||||||
|
}
|
||||||
|
|
||||||
type ContentType int
|
type ContentType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -345,6 +346,53 @@ func (s *subsonicMediaProvider) RescanLibrary() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LyricsProvider interface
|
||||||
|
var _ mediaprovider.LyricsProvider = (*subsonicMediaProvider)(nil)
|
||||||
|
|
||||||
|
func (s *subsonicMediaProvider) GetLyrics(track *mediaprovider.Track) (*mediaprovider.Lyrics, error) {
|
||||||
|
ext, err := s.client.GetOpenSubsonicExtensions()
|
||||||
|
supportsSynced := err == nil &&
|
||||||
|
slices.ContainsFunc(ext, func(ext *subsonic.OpenSubsonicExtension) bool {
|
||||||
|
return ext.Name == subsonic.SongLyricsExtension
|
||||||
|
})
|
||||||
|
if supportsSynced {
|
||||||
|
lyrics, err := s.client.GetLyricsBySongId(track.ID)
|
||||||
|
if err != nil || len(lyrics.StructuredLyrics) == 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lyric := lyrics.StructuredLyrics[0]
|
||||||
|
mpLyrics := &mediaprovider.Lyrics{
|
||||||
|
Title: lyric.DisplayTitle,
|
||||||
|
Artist: lyric.DisplayArtist,
|
||||||
|
Synced: lyric.Synced,
|
||||||
|
}
|
||||||
|
for _, line := range lyric.Lines {
|
||||||
|
mpLyrics.Lines = append(mpLyrics.Lines, mediaprovider.LyricLine{
|
||||||
|
Text: line.Text,
|
||||||
|
Start: float64(line.Start) / 1000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return mpLyrics, nil
|
||||||
|
}
|
||||||
|
// fallback to legacy getLyrics endpoint
|
||||||
|
lyrics, err := s.client.GetLyrics(track.Name, track.ArtistNames[0])
|
||||||
|
if err != nil || lyrics == nil || lyrics.Text == "" {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mpLyrics := &mediaprovider.Lyrics{
|
||||||
|
Title: lyrics.Title,
|
||||||
|
Artist: lyrics.Artist,
|
||||||
|
Synced: false,
|
||||||
|
}
|
||||||
|
lines := strings.Split(lyrics.Text, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
mpLyrics.Lines = append(mpLyrics.Lines, mediaprovider.LyricLine{
|
||||||
|
Text: line,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return mpLyrics, nil
|
||||||
|
}
|
||||||
|
|
||||||
func toTrack(ch *subsonic.Child) *mediaprovider.Track {
|
func toTrack(ch *subsonic.Child) *mediaprovider.Track {
|
||||||
if ch == nil {
|
if ch == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user