mirror of
https://github.com/AynaLivePlayer/AynaLivePlayer.git
synced 2025-12-10 12:18:13 +08:00
197 lines
4.2 KiB
Go
197 lines
4.2 KiB
Go
package player
|
|
|
|
import (
|
|
"AynaLivePlayer/event"
|
|
"AynaLivePlayer/logger"
|
|
"github.com/sirupsen/logrus"
|
|
"math/rand"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const MODULE_PLAYLIST = "Player.Playlist"
|
|
|
|
func init() {
|
|
rand.Seed(time.Now().UnixNano())
|
|
}
|
|
|
|
type PlaylistConfig struct {
|
|
RandomNext bool
|
|
}
|
|
|
|
type Playlist struct {
|
|
Index int
|
|
Name string
|
|
Config PlaylistConfig
|
|
Playlist []*Media
|
|
Handler *event.Handler
|
|
Meta interface{}
|
|
Lock sync.RWMutex
|
|
}
|
|
|
|
func NewPlaylist(name string, config PlaylistConfig) *Playlist {
|
|
return &Playlist{
|
|
Index: 0,
|
|
Name: name,
|
|
Config: config,
|
|
Playlist: make([]*Media, 0),
|
|
Handler: event.NewHandler(),
|
|
}
|
|
}
|
|
|
|
func (p *Playlist) l() *logrus.Entry {
|
|
return logger.Logger.WithFields(logrus.Fields{
|
|
"Module": MODULE_PLAYLIST,
|
|
"Name": p.Name,
|
|
})
|
|
}
|
|
|
|
func (p *Playlist) Size() int {
|
|
p.l().Tracef("getting size=%d", len(p.Playlist))
|
|
return len(p.Playlist)
|
|
}
|
|
|
|
func (p *Playlist) Pop() *Media {
|
|
p.l().Infof("pop first media")
|
|
if p.Size() == 0 {
|
|
p.l().Warn("pop first media failed, no media left in the playlist")
|
|
return nil
|
|
}
|
|
p.Lock.Lock()
|
|
index := 0
|
|
if p.Config.RandomNext {
|
|
index = rand.Intn(p.Size())
|
|
}
|
|
media := p.Playlist[index]
|
|
for i := index; i > 0; i-- {
|
|
p.Playlist[i] = p.Playlist[i-1]
|
|
}
|
|
p.Playlist = p.Playlist[1:]
|
|
p.Lock.Unlock()
|
|
defer p.Handler.CallA(EventPlaylistUpdate, PlaylistUpdateEvent{Playlist: p})
|
|
return media
|
|
}
|
|
|
|
func (p *Playlist) Replace(medias []*Media) {
|
|
p.Lock.Lock()
|
|
p.Playlist = medias
|
|
p.Index = 0
|
|
p.Lock.Unlock()
|
|
p.Handler.CallA(EventPlaylistUpdate, PlaylistUpdateEvent{Playlist: p})
|
|
return
|
|
}
|
|
|
|
func (p *Playlist) Push(media *Media) {
|
|
p.Insert(-1, media)
|
|
return
|
|
}
|
|
|
|
// Insert runtime in O(n) but i don't care
|
|
func (p *Playlist) Insert(index int, media *Media) {
|
|
p.l().Infof("insert new meida to index %d", index)
|
|
p.l().Debugf("media= %s", media.Title)
|
|
e := event.Event{
|
|
Id: EventPlaylistPreInsert,
|
|
Cancelled: false,
|
|
Data: PlaylistInsertEvent{
|
|
Playlist: p,
|
|
Index: index,
|
|
Media: media,
|
|
},
|
|
}
|
|
p.Handler.Call(&e)
|
|
if e.Cancelled {
|
|
p.l().Info("insert new media has been cancelled by handler")
|
|
return
|
|
}
|
|
p.Lock.Lock()
|
|
if index > p.Size() {
|
|
index = p.Size()
|
|
}
|
|
if index < 0 {
|
|
index = p.Size() + index + 1
|
|
}
|
|
p.Playlist = append(p.Playlist, nil)
|
|
for i := p.Size() - 1; i > index; i-- {
|
|
p.Playlist[i] = p.Playlist[i-1]
|
|
}
|
|
p.Playlist[index] = media
|
|
p.Lock.Unlock()
|
|
defer func() {
|
|
p.Handler.Call(&event.Event{
|
|
Id: EventPlaylistInsert,
|
|
Cancelled: false,
|
|
Data: PlaylistInsertEvent{
|
|
Playlist: p,
|
|
Index: index,
|
|
Media: media,
|
|
},
|
|
})
|
|
p.Handler.CallA(EventPlaylistUpdate, PlaylistUpdateEvent{Playlist: p})
|
|
}()
|
|
}
|
|
|
|
func (p *Playlist) Delete(index int) {
|
|
p.l().Infof("from media at index %d", index)
|
|
p.Lock.Lock()
|
|
if index >= p.Size() || index < 0 {
|
|
p.l().Warnf("media at index %d does not exist", index)
|
|
p.Lock.Unlock()
|
|
return
|
|
}
|
|
// todo: @5 delete optimization
|
|
p.Playlist = append(p.Playlist[:index], p.Playlist[index+1:]...)
|
|
p.Lock.Unlock()
|
|
defer p.Handler.CallA(EventPlaylistUpdate, PlaylistUpdateEvent{Playlist: p})
|
|
}
|
|
|
|
func (p *Playlist) Move(src int, dest int) {
|
|
p.l().Infof("from media from index %d to %d", src, dest)
|
|
p.Lock.Lock()
|
|
if src >= p.Size() || src < 0 {
|
|
p.l().Warnf("media at index %d does not exist", src)
|
|
p.Lock.Unlock()
|
|
return
|
|
}
|
|
if dest >= p.Size() {
|
|
dest = p.Size() - 1
|
|
}
|
|
if dest < 0 {
|
|
dest = 0
|
|
}
|
|
if dest == src {
|
|
p.l().Warn("src and dest are same, operation not perform")
|
|
p.Lock.Unlock()
|
|
return
|
|
}
|
|
step := 1
|
|
if dest < src {
|
|
step = -1
|
|
}
|
|
tmp := p.Playlist[src]
|
|
for i := src; i != dest; i += step {
|
|
p.Playlist[i] = p.Playlist[i+step]
|
|
}
|
|
p.Playlist[dest] = tmp
|
|
p.Lock.Unlock()
|
|
defer p.Handler.CallA(EventPlaylistUpdate, PlaylistUpdateEvent{Playlist: p})
|
|
}
|
|
|
|
func (p *Playlist) Next() *Media {
|
|
p.l().Infof("get next media with random=%t", p.Config.RandomNext)
|
|
if p.Size() == 0 {
|
|
p.l().Info("get next media failed, no media left in the playlist")
|
|
return nil
|
|
}
|
|
var index int
|
|
index = p.Index
|
|
if p.Config.RandomNext {
|
|
p.Index = rand.Intn(p.Size())
|
|
} else {
|
|
p.Index = (p.Index + 1) % p.Size()
|
|
}
|
|
p.l().Tracef("return index %d, new index %d", index, p.Index)
|
|
defer p.Handler.CallA(EventPlaylistUpdate, PlaylistUpdateEvent{Playlist: p})
|
|
return p.Playlist[index]
|
|
}
|