mirror of
https://github.com/AynaLivePlayer/AynaLivePlayer.git
synced 2025-12-14 05:58:17 +08:00
rewrite using IoC and DI
This commit is contained in:
397
controller/core/playlist.go
Normal file
397
controller/core/playlist.go
Normal file
@@ -0,0 +1,397 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/event"
|
||||
"AynaLivePlayer/config"
|
||||
"AynaLivePlayer/controller"
|
||||
"AynaLivePlayer/model"
|
||||
"AynaLivePlayer/provider"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type PlaylistController struct {
|
||||
PlaylistPath string
|
||||
provider controller.IProviderController
|
||||
History controller.IPlaylist `ini:"-"`
|
||||
Current controller.IPlaylist `ini:"-"`
|
||||
Default controller.IPlaylist `ini:"-"`
|
||||
Playlists []controller.IPlaylist `ini:"-"`
|
||||
DefaultIndex int
|
||||
CurrentPlaylistRandom bool
|
||||
DefaultPlaylistRandom bool
|
||||
}
|
||||
|
||||
func NewPlaylistController(
|
||||
provider controller.IProviderController) controller.IPlaylistController {
|
||||
pc := &PlaylistController{
|
||||
PlaylistPath: "playlist.json",
|
||||
provider: provider,
|
||||
History: NewPlaylist("history"),
|
||||
Default: NewPlaylist("default"),
|
||||
Current: NewPlaylist("current"),
|
||||
Playlists: make([]controller.IPlaylist, 0),
|
||||
DefaultIndex: 0,
|
||||
CurrentPlaylistRandom: false,
|
||||
DefaultPlaylistRandom: true,
|
||||
}
|
||||
config.LoadConfig(pc)
|
||||
if pc.DefaultIndex < 0 || pc.DefaultIndex >= len(pc.Playlists) {
|
||||
pc.DefaultIndex = 0
|
||||
lg.Warn("playlist index did not find")
|
||||
}
|
||||
go func() {
|
||||
_ = pc.SetDefault(pc.DefaultIndex)
|
||||
}()
|
||||
return pc
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) Name() string {
|
||||
return "Playlists"
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) OnLoad() {
|
||||
var metas = []model.Meta{
|
||||
{
|
||||
"netease",
|
||||
"2382819181",
|
||||
},
|
||||
{"netease",
|
||||
"4987059624",
|
||||
},
|
||||
{"local",
|
||||
"list1",
|
||||
},
|
||||
}
|
||||
_ = config.LoadJson(pc.PlaylistPath, &metas)
|
||||
for _, m := range metas {
|
||||
p := NewPlaylist(fmt.Sprintf("%s-%s", m.Name, m.Id))
|
||||
p.Model().Meta = m
|
||||
pc.Playlists = append(pc.Playlists, p)
|
||||
}
|
||||
if pc.CurrentPlaylistRandom {
|
||||
pc.Current.Model().Mode = model.PlaylistModeRandom
|
||||
}
|
||||
if pc.DefaultPlaylistRandom {
|
||||
pc.Default.Model().Mode = model.PlaylistModeRandom
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) OnSave() {
|
||||
var metas = make([]model.Meta, 0)
|
||||
for _, pl := range pc.Playlists {
|
||||
metas = append(metas, pl.Model().Meta)
|
||||
}
|
||||
_ = config.SaveJson(pc.PlaylistPath, &metas)
|
||||
|
||||
if pc.Current.Model().Mode == model.PlaylistModeRandom {
|
||||
pc.CurrentPlaylistRandom = true
|
||||
} else {
|
||||
pc.CurrentPlaylistRandom = false
|
||||
}
|
||||
if pc.Default.Model().Mode == model.PlaylistModeRandom {
|
||||
pc.DefaultPlaylistRandom = true
|
||||
} else {
|
||||
pc.DefaultPlaylistRandom = false
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) Size() int {
|
||||
return len(pc.Playlists)
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) GetHistory() controller.IPlaylist {
|
||||
return pc.History
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) GetDefault() controller.IPlaylist {
|
||||
return pc.Default
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) GetCurrent() controller.IPlaylist {
|
||||
return pc.Current
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) AddToHistory(media *model.Media) {
|
||||
lg.Tracef("add media %s (%s) to history", media.Title, media.Artist)
|
||||
media = media.Copy()
|
||||
// reset url for future use
|
||||
media.Url = ""
|
||||
if pc.History.Size() >= 1024 {
|
||||
pc.History.Replace([]*model.Media{})
|
||||
}
|
||||
media.User = controller.HistoryUser
|
||||
pc.History.Push(media)
|
||||
return
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) Get(index int) controller.IPlaylist {
|
||||
if index < 0 || index >= len(pc.Playlists) {
|
||||
lg.Warnf("playlist.index=%d not found", index)
|
||||
return nil
|
||||
}
|
||||
return pc.Playlists[index]
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) Add(pname string, uri string) controller.IPlaylist {
|
||||
lg.Infof("try add playlist %s with provider %s", uri, pname)
|
||||
id, err := provider.FormatPlaylistUrl(pname, uri)
|
||||
if err != nil || id == "" {
|
||||
lg.Warnf("fail to format %s playlist id for %s", uri, pname)
|
||||
return nil
|
||||
}
|
||||
p := NewPlaylist(fmt.Sprintf("%s-%s", pname, id))
|
||||
p.Model().Meta = model.Meta{
|
||||
Name: pname,
|
||||
Id: id,
|
||||
}
|
||||
pc.Playlists = append(pc.Playlists, p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) Remove(index int) controller.IPlaylist {
|
||||
lg.Infof("Try to remove playlist.index=%d", index)
|
||||
if index < 0 || index >= len(pc.Playlists) {
|
||||
lg.Warnf("playlist.index=%d not found", index)
|
||||
return nil
|
||||
}
|
||||
if index == pc.DefaultIndex {
|
||||
lg.Info("Delete current system playlist, reset system playlist to index = 0")
|
||||
_ = pc.SetDefault(0)
|
||||
}
|
||||
if index < pc.DefaultIndex {
|
||||
lg.Debugf("Delete playlist before system playlist (index=%d), reduce system playlist index by 1", pc.DefaultIndex)
|
||||
pc.DefaultIndex = pc.DefaultIndex - 1
|
||||
}
|
||||
pl := pc.Playlists[index]
|
||||
pc.Playlists = append(pc.Playlists[:index], pc.Playlists[index+1:]...)
|
||||
return pl
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) SetDefault(index int) error {
|
||||
lg.Infof("try set system playlist to playlist.id=%d", index)
|
||||
if index < 0 || index >= len(pc.Playlists) {
|
||||
lg.Warn("playlist.index=%d not found", index)
|
||||
return errors.New("playlist.index not found")
|
||||
}
|
||||
err := pc.provider.PreparePlaylist(pc.Playlists[index])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pl := pc.Playlists[index].Model().Copy()
|
||||
pc.DefaultIndex = index
|
||||
controller.ApplyUser(pl.Medias, controller.PlaylistUser)
|
||||
pc.Default.Replace(pl.Medias)
|
||||
pc.Default.Model().Name = pl.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pc *PlaylistController) PreparePlaylistByIndex(index int) error {
|
||||
lg.Infof("try prepare playlist.id=%d", index)
|
||||
if index < 0 || index >= len(pc.Playlists) {
|
||||
lg.Warn("playlist.id=%d not found", index)
|
||||
return nil
|
||||
}
|
||||
return pc.provider.PreparePlaylist(pc.Playlists[index])
|
||||
}
|
||||
|
||||
type corePlaylist struct {
|
||||
model.Playlist
|
||||
Index int
|
||||
Lock sync.RWMutex
|
||||
eventManager *event.Manager
|
||||
}
|
||||
|
||||
func NewPlaylist(name string) controller.IPlaylist {
|
||||
return &corePlaylist{
|
||||
Index: 0,
|
||||
Playlist: model.Playlist{
|
||||
Name: name,
|
||||
Medias: make([]*model.Media, 0),
|
||||
Mode: model.PlaylistModeNormal,
|
||||
Meta: model.Meta{},
|
||||
},
|
||||
eventManager: event.MainManager.NewChildManager(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Model() *model.Playlist {
|
||||
return &p.Playlist
|
||||
}
|
||||
|
||||
func (p *corePlaylist) EventManager() *event.Manager {
|
||||
return p.eventManager
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Name() string {
|
||||
return p.Playlist.Name
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Size() int {
|
||||
return p.Playlist.Size()
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Get(index int) *model.Media {
|
||||
if index < 0 || index >= p.Playlist.Size() {
|
||||
return nil
|
||||
}
|
||||
return p.Playlist.Medias[index]
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Pop() *model.Media {
|
||||
lg.Info("[Playlists] %s pop first media", p.Playlist)
|
||||
if p.Size() == 0 {
|
||||
return nil
|
||||
}
|
||||
p.Lock.Lock()
|
||||
index := 0
|
||||
if p.Mode == model.PlaylistModeRandom {
|
||||
index = rand.Intn(p.Size())
|
||||
}
|
||||
m := p.Medias[index]
|
||||
for i := index; i > 0; i-- {
|
||||
p.Medias[i] = p.Medias[i-1]
|
||||
}
|
||||
p.Medias = p.Medias[1:]
|
||||
p.Lock.Unlock()
|
||||
if m == nil {
|
||||
lg.Warn("[Playlists] pop first media failed, no media left in the playlist")
|
||||
return nil
|
||||
}
|
||||
p.eventManager.CallA(
|
||||
model.EventPlaylistUpdate,
|
||||
model.PlaylistUpdateEvent{Playlist: p.Playlist.Copy()},
|
||||
)
|
||||
return m
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Replace(medias []*model.Media) {
|
||||
lg.Infof("[Playlists] %s replace all media", &p.Playlist)
|
||||
p.Lock.Lock()
|
||||
p.Playlist.Medias = medias
|
||||
p.Index = 0
|
||||
p.Lock.Unlock()
|
||||
p.eventManager.CallA(
|
||||
model.EventPlaylistUpdate,
|
||||
model.PlaylistUpdateEvent{Playlist: p.Playlist.Copy()},
|
||||
)
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Push(media *model.Media) {
|
||||
p.Insert(-1, media)
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Insert(index int, media *model.Media) {
|
||||
lg.Infof("[Playlists]insert media into new index %d at %s ", index, p.Playlist)
|
||||
lg.Debugf("media=%s %v", media.Title, media.Meta)
|
||||
e := event.Event{
|
||||
Id: model.EventPlaylistPreInsert,
|
||||
Cancelled: false,
|
||||
Data: model.PlaylistInsertEvent{
|
||||
Playlist: p.Playlist.Copy(),
|
||||
Index: index,
|
||||
Media: media,
|
||||
},
|
||||
}
|
||||
p.eventManager.Call(&e)
|
||||
if e.Cancelled {
|
||||
lg.Info("[Playlists] media insertion 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.Medias = append(p.Medias, nil)
|
||||
for i := p.Size() - 1; i > index; i-- {
|
||||
p.Medias[i] = p.Medias[i-1]
|
||||
}
|
||||
p.Medias[index] = media
|
||||
p.Lock.Unlock()
|
||||
p.eventManager.CallA(
|
||||
model.EventPlaylistUpdate,
|
||||
model.PlaylistUpdateEvent{Playlist: p.Playlist.Copy()},
|
||||
)
|
||||
p.eventManager.CallA(
|
||||
model.EventPlaylistInsert,
|
||||
model.PlaylistInsertEvent{
|
||||
Playlist: p.Playlist.Copy(),
|
||||
Index: index,
|
||||
Media: media,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Delete(index int) *model.Media {
|
||||
lg.Infof("from media at index %d from %s", index, p.Playlist)
|
||||
if index >= p.Size() || index < 0 {
|
||||
p.Lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
m := p.Medias[index]
|
||||
p.Lock.Lock()
|
||||
// todo: @5 delete optimization
|
||||
p.Medias = append(p.Medias[:index], p.Medias[index+1:]...)
|
||||
p.Lock.Unlock()
|
||||
if m == nil {
|
||||
lg.Warnf("media at index %d does not exist", index)
|
||||
}
|
||||
p.eventManager.CallA(
|
||||
model.EventPlaylistUpdate,
|
||||
model.PlaylistUpdateEvent{Playlist: p.Playlist.Copy()})
|
||||
return m
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Move(src int, dst int) {
|
||||
lg.Infof("from media from index %d to %d", src, dst)
|
||||
if src >= p.Size() || src < 0 {
|
||||
lg.Warnf("media at index %d does not exist", src)
|
||||
return
|
||||
}
|
||||
p.Lock.Lock()
|
||||
if dst >= p.Size() {
|
||||
dst = p.Size() - 1
|
||||
}
|
||||
if dst < 0 {
|
||||
dst = 0
|
||||
}
|
||||
if dst == src {
|
||||
p.Lock.Unlock()
|
||||
return
|
||||
}
|
||||
step := 1
|
||||
if dst < src {
|
||||
step = -1
|
||||
}
|
||||
tmp := p.Medias[src]
|
||||
for i := src; i != dst; i += step {
|
||||
p.Medias[i] = p.Medias[i+step]
|
||||
}
|
||||
p.Medias[dst] = tmp
|
||||
p.Lock.Unlock()
|
||||
p.eventManager.CallA(
|
||||
model.EventPlaylistUpdate,
|
||||
model.PlaylistUpdateEvent{Playlist: p.Playlist.Copy()})
|
||||
}
|
||||
|
||||
func (p *corePlaylist) Next() *model.Media {
|
||||
lg.Infof("[Playlists] %s get next media with random=%t", p, p.Mode == model.PlaylistModeRandom)
|
||||
if p.Size() == 0 {
|
||||
lg.Warn("[Playlists] get next media failed, no media left in the playlist")
|
||||
return nil
|
||||
}
|
||||
var index int
|
||||
index = p.Index
|
||||
if p.Mode == model.PlaylistModeRandom {
|
||||
p.Index = rand.Intn(p.Size())
|
||||
} else {
|
||||
p.Index = (p.Index + 1) % p.Size()
|
||||
}
|
||||
m := p.Medias[index]
|
||||
return m
|
||||
}
|
||||
Reference in New Issue
Block a user