feat: send word-by-word and translated lyrics to clients
This commit is contained in:
1 parent
e2364b171e
commit
a38d6ca3e2
10 files changed
+71
-11
No files matched your search
@@ -126,9 +126,18 @@ func (s *server) nowPlaying(p *room.NowPlaying) *protocol.NowPlaying {
|
||||
DurationMs: p.Entry.Prep.Duration.Milliseconds(),
|
||||
Gain: p.Entry.Prep.Gain,
|
||||
Lyric: p.Entry.Prep.Lyric,
|
||||
LyricWords: optional(p.Entry.Prep.LyricWords),
|
||||
LyricTrans: optional(p.Entry.Prep.LyricTrans),
|
||||
}
|
||||
}
|
||||
|
||||
func optional(s string) *string {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *server) mediaURL(t track.Track) string {
|
||||
if media.Stored(t.Source) {
|
||||
return s.StorageURL + "/" + media.AudioObject(media.Key(t.ID))
|
||||
|
||||
@@ -71,6 +71,16 @@ func TestSnapshotDTO(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNowPlayingCarriesWordAndTranslatedLyrics(t *testing.T) {
|
||||
s := &server{}
|
||||
entry := sunnyEntry
|
||||
entry.Prep.LyricWords, entry.Prep.LyricTrans = "[1000,500](1000,500,0)故", "[00:01.00]The story"
|
||||
got := s.nowPlaying(&room.NowPlaying{Entry: entry})
|
||||
if got.LyricWords == nil || *got.LyricWords != entry.Prep.LyricWords || got.LyricTrans == nil || *got.LyricTrans != entry.Prep.LyricTrans {
|
||||
t.Errorf("lyricWords = %v, lyricTrans = %v", got.LyricWords, got.LyricTrans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEventDTO(t *testing.T) {
|
||||
s := &server{}
|
||||
sentAt := time.UnixMilli(1760000000456)
|
||||
|
||||
@@ -27,11 +27,13 @@ type Source struct {
|
||||
}
|
||||
|
||||
type sourceSong struct {
|
||||
id string
|
||||
meta track.Meta
|
||||
lyric string
|
||||
audio []byte
|
||||
reject string
|
||||
id string
|
||||
meta track.Meta
|
||||
lyric string
|
||||
lyricWords string
|
||||
lyricTrans string
|
||||
audio []byte
|
||||
reject string
|
||||
}
|
||||
|
||||
type sourcePlaylist struct {
|
||||
@@ -56,6 +58,16 @@ func (s *Source) Add(id string, m track.Meta, lyric string, audio []byte) {
|
||||
s.songs = append(s.songs, sourceSong{id: id, meta: m, lyric: lyric, audio: audio})
|
||||
}
|
||||
|
||||
func (s *Source) SetLyrics(id, words, trans string) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for i := range s.songs {
|
||||
if s.songs[i].id == id {
|
||||
s.songs[i].lyricWords, s.songs[i].lyricTrans = words, trans
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Source) Reject(id, reason string) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
@@ -164,7 +176,7 @@ func (s *Source) Resolve(_ context.Context, id string) (port.Resolved, error) {
|
||||
case song.reject != "":
|
||||
return port.Resolved{}, &port.RejectedError{Err: errors.New(song.reject)}
|
||||
}
|
||||
return port.Resolved{Meta: song.meta, Lyric: song.lyric, Audio: io.NopCloser(bytes.NewReader(song.audio))}, nil
|
||||
return port.Resolved{Meta: song.meta, Lyric: song.lyric, LyricWords: song.lyricWords, LyricTrans: song.lyricTrans, Audio: io.NopCloser(bytes.NewReader(song.audio))}, nil
|
||||
}
|
||||
|
||||
func (s *Source) PlayURL(_ context.Context, id string) (string, error) {
|
||||
|
||||
@@ -69,6 +69,20 @@ func checkDecodeWarning(t *testing.T, logs *bytes.Buffer, tr track.Track, decode
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunSavesWordAndTranslatedLyrics(t *testing.T) {
|
||||
source := porttest.NewSource(track.NetEase)
|
||||
source.Add("186016", meta, "[00:01.00]故事", []byte("不是音频"))
|
||||
source.SetLyrics("186016", "[1000,500](1000,500,0)故", "[00:01.00]The story")
|
||||
tracks, err := run(t, source, sunny)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := track.Prepared{Duration: meta.Duration, Gain: 1, Lyric: "[00:01.00]故事", LyricWords: "[1000,500](1000,500,0)故", LyricTrans: "[00:01.00]The story"}
|
||||
if got, _ := tracks.row(sunny); got.Result != want {
|
||||
t.Errorf("准备结果 = %+v,期望 %+v", got.Result, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunFallsBackWhenAudioCannotBeAnalyzed(t *testing.T) {
|
||||
source := porttest.NewSource(track.NetEase)
|
||||
source.Add("186016", meta, "", []byte("不是音频"))
|
||||
|
||||
@@ -156,6 +156,7 @@ func contractSources() sources {
|
||||
"[00:01.00]故事的小黄花", porttest.SilentWAV(269500*time.Millisecond))
|
||||
netease.Add("185811", track.Meta{Title: "七里香", Artist: "周杰伦", Album: "七里香", CoverURL: "https://p1.music.126.net/qilixiang.jpg", PageURL: "https://music.163.com/#/song?id=185811", Duration: 299 * time.Second},
|
||||
"", porttest.SilentWAV(299*time.Second))
|
||||
netease.SetLyrics("185811", "[1000,500](1000,500,0)窗", "[00:01.00]Window")
|
||||
netease.Add("1100", track.Meta{Title: "片头", Artist: "无名", PageURL: "https://music.163.com/#/song?id=1100", Duration: 15 * time.Second},
|
||||
"", porttest.SilentWAV(15*time.Second))
|
||||
netease.Add("404", track.Meta{Title: "不能播放的歌", Artist: "无名", PageURL: "https://music.163.com/#/song?id=404", Duration: time.Minute}, "", nil)
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ Authorization: Bearer $alice
|
||||
{"kind": "event", "type": "playback.updated", "term": 1, "seq": 13, "data": {"nowPlaying": {
|
||||
"entry": {"id": "2", "track": {"source": "netease", "id": "185811"}, "meta": {"title": "七里香", "artist": "周杰伦", "album": "七里香", "coverUrl": "https://p1.music.126.net/qilixiang.jpg", "pageUrl": "https://music.163.com/#/song?id=185811", "durationMs": 299000},
|
||||
"by": {"id": "$aliceId", "name": "$aliceName", "avatarHash": ""}, "auto": false, "likes": 1, "status": "ready"},
|
||||
"mediaUrl": "/media/netease/185811", "startedAtMs": 1, "durationMs": 299000, "gain": 1, "lyric": ""}}}
|
||||
"mediaUrl": "/media/netease/185811", "startedAtMs": 1, "durationMs": 299000, "gain": 1, "lyric": "", "lyricWords": "[1000,500](1000,500,0)窗", "lyricTrans": "[00:01.00]Window"}}}
|
||||
-- receive alice --
|
||||
{"kind": "response", "type": "playback.voteSkip", "id": "v1", "data": {"votes": 1, "required": 1, "skipped": true}}
|
||||
|
||||
|
||||
Reference in new issue
Block a user