mirror of
https://github.com/AynaLivePlayer/AynaLivePlayer.git
synced 2025-12-17 15:38:18 +08:00
rewrite using IoC and DI
This commit is contained in:
52
model/event.go
Normal file
52
model/event.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/event"
|
||||
)
|
||||
|
||||
const (
|
||||
EventPlay event.EventId = "player.play"
|
||||
EventPlaylistPreInsert event.EventId = "playlist.insert.pre"
|
||||
EventPlaylistInsert event.EventId = "playlist.insert.after"
|
||||
EventPlaylistUpdate event.EventId = "playlist.update"
|
||||
EventLyricUpdate event.EventId = "lyric.update"
|
||||
EventLyricReload event.EventId = "lyric.reload"
|
||||
)
|
||||
|
||||
func EventPlayerPropertyUpdate(property PlayerProperty) event.EventId {
|
||||
return event.EventId("player.property.update." + string(property))
|
||||
}
|
||||
|
||||
type PlaylistInsertEvent struct {
|
||||
Playlist *Playlist
|
||||
Index int
|
||||
Media *Media
|
||||
}
|
||||
|
||||
type PlaylistUpdateEvent struct {
|
||||
Playlist *Playlist // Playlist is a copy of the playlist
|
||||
}
|
||||
|
||||
type PlayEvent struct {
|
||||
Media *Media
|
||||
}
|
||||
|
||||
type LyricUpdateEvent struct {
|
||||
Lyrics *Lyric
|
||||
Time float64
|
||||
Lyric *LyricLine
|
||||
}
|
||||
|
||||
type LyricReloadEvent struct {
|
||||
Lyrics *Lyric
|
||||
}
|
||||
|
||||
type PlayerPropertyUpdateEvent struct {
|
||||
Property PlayerProperty
|
||||
Value PlayerPropertyValue
|
||||
}
|
||||
|
||||
type LiveRoomStatusUpdateEvent struct {
|
||||
RoomTitle string
|
||||
Status bool
|
||||
}
|
||||
17
model/liveroom.go
Normal file
17
model/liveroom.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
import "fmt"
|
||||
|
||||
type LiveRoom struct {
|
||||
ClientName string
|
||||
ID string
|
||||
AutoConnect bool
|
||||
}
|
||||
|
||||
func (r *LiveRoom) String() string {
|
||||
return fmt.Sprintf("<LiveRooms %s:%s>", r.ClientName, r.ID)
|
||||
}
|
||||
|
||||
func (r *LiveRoom) Title() string {
|
||||
return fmt.Sprintf("%s-%s", r.ClientName, r.ID)
|
||||
}
|
||||
84
model/lyric.go
Normal file
84
model/lyric.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/spf13/cast"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var timeTagRegex = regexp.MustCompile("\\[[0-9]+:[0-9]+(\\.[0-9]+)?\\]")
|
||||
|
||||
type LyricLine struct {
|
||||
Time float64 // in seconds
|
||||
Lyric string
|
||||
Translation string
|
||||
}
|
||||
|
||||
type LyricContext struct {
|
||||
Current *LyricLine
|
||||
Prev []*LyricLine
|
||||
Next []*LyricLine
|
||||
}
|
||||
|
||||
type Lyric struct {
|
||||
Lyrics []*LyricLine
|
||||
}
|
||||
|
||||
func LoadLyric(lyric string) *Lyric {
|
||||
tmp := make(map[float64]*LyricLine)
|
||||
times := make([]float64, 0)
|
||||
for _, line := range strings.Split(lyric, "\n") {
|
||||
lrc := timeTagRegex.ReplaceAllString(line, "")
|
||||
for _, time := range timeTagRegex.FindAllString(line, -1) {
|
||||
ts := strings.Split(time[1:len(time)-1], ":")
|
||||
t := cast.ToFloat64(ts[0])*60 + cast.ToFloat64(ts[1])
|
||||
times = append(times, t)
|
||||
tmp[t] = &LyricLine{
|
||||
Time: t,
|
||||
Lyric: lrc,
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Float64s(times)
|
||||
lrcs := make([]*LyricLine, len(times))
|
||||
for index, time := range times {
|
||||
lrcs[index] = tmp[time]
|
||||
}
|
||||
if len(lrcs) == 0 {
|
||||
lrcs = append(lrcs, &LyricLine{Time: 0, Lyric: ""})
|
||||
}
|
||||
lrcs = append(lrcs, &LyricLine{
|
||||
Time: 99999999999,
|
||||
Lyric: "",
|
||||
})
|
||||
return &Lyric{Lyrics: lrcs}
|
||||
}
|
||||
|
||||
func (l *Lyric) Find(time float64) *LyricLine {
|
||||
for i := 0; i < len(l.Lyrics)-1; i++ {
|
||||
if l.Lyrics[i].Time <= time && time < l.Lyrics[i+1].Time {
|
||||
return l.Lyrics[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Lyric) FindContext(time float64, prev int, next int) *LyricContext {
|
||||
for i := 0; i < len(l.Lyrics)-1; i++ {
|
||||
if l.Lyrics[i].Time <= time && time < l.Lyrics[i+1].Time {
|
||||
if (i + prev) < 0 {
|
||||
prev = -i
|
||||
}
|
||||
if (i + 1 + next) > len(l.Lyrics) {
|
||||
next = len(l.Lyrics) - i - 1
|
||||
}
|
||||
return &LyricContext{
|
||||
Current: l.Lyrics[i],
|
||||
Prev: l.Lyrics[i+prev : i],
|
||||
Next: l.Lyrics[i+1 : i+1+next],
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
23
model/lyric_test.go
Normal file
23
model/lyric_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testLyric = "[ti:双截棍]\n[ar:周杰伦]\n[al:范特西]\n[00:03.85]双截棍\n[00:07.14]\n[00:30.13]岩烧店的烟味弥漫隔壁是国术馆\n[00:32.57]店里面的妈妈桑茶道有三段\n[00:34.61]教拳脚武术的老板练铁沙掌耍杨家枪\n[00:37.34]硬底子功夫最擅长还会金钟罩铁步衫\n[00:39.67]他们儿子我习惯从小就耳濡目染\n[00:41.96]什么刀枪跟棍棒我都耍的有模有样\n[00:44.22]什么兵器最喜欢双截棍柔中带刚\n[00:46.73]想要去河南嵩山学少林跟武当\n[00:49.24]干什么(客)干什么(客)呼吸吐纳心自在\n[00:51.28]干什么(客)干什么(客)气沉丹田手心开\n[00:53.44]干什么(客)干什么(客)日行千里系沙袋\n[00:56.13]飞檐走壁莫奇怪去去就来\n[00:58.35]一个马步向前一记左钩拳右钩拳\n[01:01.26]一句惹毛我的人有危险一再重演\n[01:04.02]一根我不抽的菸一放好多年它一直在身边\n[01:07.28]干什么(客)干什么(客)我打开任督二脉\n[01:10.27]干什么(客)干什么(客)东亚病夫的招牌\n[01:12.75]干什么(客)干什么(客)已被我一脚踢开\n[02:32.62][01:54.69][01:15.40]快使用双截棍哼哼哈兮\n[02:34.52][01:56.63][01:18.40]快使用双截棍哼哼哈兮\n[02:36.88][01:58.98][01:20.71]习武之人切记仁者无敌\n[02:39.45][02:01.66][01:23.27]是谁在练太极风生水起\n[02:41.97][02:03.93][01:25.74]快使用双截棍哼哼哈兮\n[02:44.42][02:06.11][01:27.75]快使用双截棍哼哼哈兮\n[02:47.01][02:08.54][01:30.13]如果我有轻功飞檐走壁\n[02:49.36][02:11.03][01:32.67]为人耿直不屈一身正气\n[02:53.81]快使用双截棍哼\n[02:56.30]我用手刀防御哼\n[02:58.52]漂亮的回旋踢\n[02:59.52]"
|
||||
|
||||
func TestLyric(t *testing.T) {
|
||||
lryic := LoadLyric(testLyric)
|
||||
for _, lrc := range lryic.Lyrics {
|
||||
fmt.Println(lrc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLyricFind(t *testing.T) {
|
||||
lryic := LoadLyric(testLyric)
|
||||
fmt.Println(lryic.Find(90.4))
|
||||
for _, l := range lryic.FindContext(90.4, -2, 2).Next {
|
||||
fmt.Println(l)
|
||||
}
|
||||
}
|
||||
54
model/media.go
Normal file
54
model/media.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/liveclient"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
type Picture struct {
|
||||
Url string
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (p Picture) Exists() bool {
|
||||
return p.Url != "" || p.Data != nil
|
||||
}
|
||||
|
||||
type Media struct {
|
||||
Title string
|
||||
Artist string
|
||||
Cover Picture
|
||||
Album string
|
||||
Lyric string
|
||||
Url string
|
||||
Header map[string]string
|
||||
User interface{}
|
||||
Meta interface{}
|
||||
}
|
||||
|
||||
func (m *Media) ToUser() *User {
|
||||
if u, ok := m.User.(*User); ok {
|
||||
return u
|
||||
}
|
||||
return &User{Name: m.DanmuUser().Username}
|
||||
}
|
||||
|
||||
func (m *Media) SystemUser() *User {
|
||||
if u, ok := m.User.(*User); ok {
|
||||
return u
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Media) DanmuUser() *liveclient.DanmuUser {
|
||||
if u, ok := m.User.(*liveclient.DanmuUser); ok {
|
||||
return u
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Media) Copy() *Media {
|
||||
newMedia := &Media{}
|
||||
copier.Copy(newMedia, m)
|
||||
return newMedia
|
||||
}
|
||||
30
model/media_test.go
Normal file
30
model/media_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type A struct {
|
||||
A string
|
||||
}
|
||||
|
||||
type B struct {
|
||||
B string
|
||||
}
|
||||
|
||||
func TestStruct(t *testing.T) {
|
||||
var x interface{} = &A{A: "123"}
|
||||
y, ok := x.(*A)
|
||||
fmt.Println(y, ok)
|
||||
z, ok := x.(*B)
|
||||
fmt.Println(z, ok)
|
||||
}
|
||||
|
||||
func TestMedia_Copy(t *testing.T) {
|
||||
m := &Media{Title: "asdf", User: &User{Name: "123"}}
|
||||
m2 := m.Copy()
|
||||
fmt.Println(m, m2)
|
||||
m2.User.(*User).Name = "456"
|
||||
fmt.Println(m.User.(*User).Name, m2)
|
||||
}
|
||||
18
model/player.go
Normal file
18
model/player.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package model
|
||||
|
||||
type AudioDevice struct {
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
type PlayerPropertyValue any
|
||||
type PlayerProperty string
|
||||
|
||||
const (
|
||||
PlayerPropIdleActive PlayerProperty = "idle-active"
|
||||
PlayerPropTimePos PlayerProperty = "time-pos"
|
||||
PlayerPropDuration PlayerProperty = "duration"
|
||||
PlayerPropPercentPos PlayerProperty = "percent-pos"
|
||||
PlayerPropPause PlayerProperty = "pause"
|
||||
PlayerPropVolume PlayerProperty = "volume"
|
||||
)
|
||||
36
model/playlist.go
Normal file
36
model/playlist.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package model
|
||||
|
||||
import "fmt"
|
||||
|
||||
type PlaylistMode int
|
||||
|
||||
const (
|
||||
PlaylistModeNormal PlaylistMode = iota
|
||||
PlaylistModeRandom
|
||||
)
|
||||
|
||||
type Playlist struct {
|
||||
Name string
|
||||
Medias []*Media
|
||||
Mode PlaylistMode
|
||||
Meta Meta
|
||||
}
|
||||
|
||||
func (p Playlist) String() string {
|
||||
return fmt.Sprintf("<Playlist %s>", p.Name)
|
||||
}
|
||||
|
||||
func (p *Playlist) Size() int {
|
||||
return len(p.Medias)
|
||||
}
|
||||
|
||||
func (p *Playlist) Copy() *Playlist {
|
||||
medias := make([]*Media, len(p.Medias))
|
||||
copy(medias, p.Medias)
|
||||
return &Playlist{
|
||||
Name: p.Name,
|
||||
Medias: medias,
|
||||
Mode: p.Mode,
|
||||
Meta: p.Meta,
|
||||
}
|
||||
}
|
||||
6
model/provider.go
Normal file
6
model/provider.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
type Meta struct {
|
||||
Name string
|
||||
Id string
|
||||
}
|
||||
5
model/user.go
Normal file
5
model/user.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package model
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
}
|
||||
Reference in New Issue
Block a user