Initial commit

This commit is contained in:
Aynakeya
2022-06-21 13:02:22 -07:00
commit 9f75839ebc
161 changed files with 18766 additions and 0 deletions

94
controller/api.go Normal file
View File

@@ -0,0 +1,94 @@
package controller
import (
"AynaLivePlayer/player"
"AynaLivePlayer/provider"
)
func PlayNext() {
l().Info("try to play next possible media")
if UserPlaylist.Size() == 0 && SystemPlaylist.Size() == 0 {
return
}
var media *player.Media
if UserPlaylist.Size() != 0 {
media = UserPlaylist.Pop()
} else if SystemPlaylist.Size() != 0 {
media = SystemPlaylist.Next()
}
Play(media)
}
func Play(media *player.Media) {
l().Info("prepare media")
err := PrepareMedia(media)
if err != nil {
l().Warn("prepare media failed. try play next")
PlayNext()
return
}
if err := MainPlayer.Play(media); err != nil {
l().Warn("play failed", err)
}
CurrentLyric.Reload(media.Lyric)
// reset
media.Url = ""
}
func Add(keyword string, user interface{}) {
medias, err := Search(keyword)
if err != nil {
l().Warnf("search for %s, got error %s", keyword, err)
return
}
if len(medias) == 0 {
l().Info("search for %s, got no result", keyword)
return
}
media := medias[0]
media.User = user
l().Infof("add media %s (%s)", media.Title, media.Artist)
UserPlaylist.Insert(-1, media)
}
func AddWithProvider(keyword string, pname string, user interface{}) {
medias, err := provider.Search(pname, keyword)
if err != nil {
l().Warnf("search for %s, got error %s", keyword, err)
return
}
if len(medias) == 0 {
l().Info("search for %s, got no result", keyword)
}
media := medias[0]
media.User = user
l().Info("add media %s (%s)", media.Title, media.Artist)
UserPlaylist.Insert(-1, media)
}
func Seek(position float64, absolute bool) {
if err := MainPlayer.Seek(position, absolute); err != nil {
l().Warnf("seek to position %f (%t) failed, %s", position, absolute, err)
}
}
func Toggle() (b bool) {
var err error
if MainPlayer.IsPaused() {
err = MainPlayer.Unpause()
b = false
} else {
err = MainPlayer.Pause()
b = true
}
if err != nil {
l().Warn("toggle failed", err)
}
return
}
func SetVolume(volume float64) {
if MainPlayer.SetVolume(volume) != nil {
l().Warnf("set mpv volume to %f failed", volume)
}
}

28
controller/command.go Normal file
View File

@@ -0,0 +1,28 @@
package controller
import (
"AynaLivePlayer/event"
"AynaLivePlayer/liveclient"
"strings"
)
var Commands []DanmuCommandExecutor
type DanmuCommandExecutor interface {
Match(command string) bool
Execute(command string, args []string, danmu *liveclient.DanmuMessage)
}
func AddCommand(executors ...DanmuCommandExecutor) {
Commands = append(Commands, executors...)
}
func danmuCommandHandler(event *event.Event) {
danmu := event.Data.(*liveclient.DanmuMessage)
args := strings.Split(danmu.Message, " ")
for _, cmd := range Commands {
if cmd.Match(args[0]) {
cmd.Execute(args[0], args[1:], danmu)
}
}
}

View File

@@ -0,0 +1,25 @@
package controller
import (
"AynaLivePlayer/liveclient"
"strings"
)
var CommandDiange = &Diange{}
type Diange struct {
}
func (d Diange) Match(command string) bool {
for _, c := range []string{"点歌"} {
if command == c {
return true
}
}
return false
}
func (d Diange) Execute(command string, args []string, danmu *liveclient.DanmuMessage) {
keyword := strings.Join(args, " ")
Add(keyword, &danmu.User)
}

133
controller/controller.go Normal file
View File

@@ -0,0 +1,133 @@
package controller
import (
"AynaLivePlayer/config"
"AynaLivePlayer/event"
"AynaLivePlayer/liveclient"
"AynaLivePlayer/logger"
"AynaLivePlayer/player"
"AynaLivePlayer/provider"
"AynaLivePlayer/util"
"fmt"
"github.com/sirupsen/logrus"
"strconv"
)
const MODULE_CONTROLLER = "Controller"
func l() *logrus.Entry {
return logger.Logger.WithField("Module", MODULE_CONTROLLER)
}
func Initialize() {
AddCommand(CommandDiange)
MainPlayer.ObserveProperty("idle-active", handleMpvIdlePlayNext)
UserPlaylist.Handler.RegisterA(player.EventPlaylistInsert, "controller.playnextwhenadd", handlePlaylistAdd)
MainPlayer.ObserveProperty("time-pos", handleLyricUpdate)
MainPlayer.Start()
}
func Destroy() {
MainPlayer.Stop()
}
func SetDanmuClient(roomId string) {
ResetDanmuClient()
l().Infof("setting live client for %s", roomId)
room, err := strconv.Atoi(roomId)
if err != nil {
l().Warn("parse room id error", err)
return
}
if !util.StringSliceContains(config.LiveRoom.History, roomId) {
config.LiveRoom.History = append(config.LiveRoom.History, roomId)
}
LiveClient = liveclient.NewBilibili(room)
LiveClient.Handler().Register(&event.EventHandler{
EventId: liveclient.EventMessageReceive,
Name: "controller.commandexecutor",
Handler: danmuCommandHandler,
})
l().Infof("setting live client for %s success", roomId)
}
func StartDanmuClient() {
LiveClient.Connect()
}
func ResetDanmuClient() {
if LiveClient != nil {
l().Infof("disconnect from current live client %s", LiveClient.ClientName())
LiveClient.Disconnect()
LiveClient.Handler().UnregisterAll()
LiveClient = nil
}
}
func AddPlaylist(pname string, uri string) *player.Playlist {
l().Infof("try add playlist %s with provider %s", uri, pname)
id, err := provider.FormatPlaylistUrl(pname, uri)
if err != nil || id == "" {
l().Warnf("fail to format %s playlist id for %s", uri, pname)
return nil
}
p := player.NewPlaylist(fmt.Sprintf("%s-%s", pname, id), player.PlaylistConfig{})
p.Meta = provider.Meta{
Name: pname,
Id: id,
}
PlaylistManager = append(PlaylistManager, p)
config.Player.Playlists = append(config.Player.Playlists, id)
config.Player.PlaylistsProvider = append(config.Player.PlaylistsProvider, pname)
return p
}
func RemovePlaylist(index int) {
l().Infof("Try to remove playlist.index=%d", index)
if index < 0 || index >= len(PlaylistManager) {
l().Warnf("playlist.index=%d not found", index)
return
}
if index == config.Player.PlaylistIndex {
l().Info("Delete current system playlist, reset system playlist to index = 0")
SetSystemPlaylist(0)
}
if index < config.Player.PlaylistIndex {
l().Debugf("Delete playlist before system playlist (index=%d), reduce system playlist index by 1", config.Player.PlaylistIndex)
config.Player.PlaylistIndex = config.Player.PlaylistIndex - 1
}
PlaylistManager = append(PlaylistManager[:index], PlaylistManager[index+1:]...)
config.Player.Playlists = append(config.Player.Playlists[:index], config.Player.Playlists[index+1:]...)
config.Player.PlaylistsProvider = append(config.Player.PlaylistsProvider[:index], config.Player.PlaylistsProvider[index+1:]...)
}
func SetSystemPlaylist(index int) {
l().Infof("try set system playlist to playlist.id=%d", index)
if index < 0 || index >= len(PlaylistManager) {
l().Warn("playlist.index=%d not found", index)
return
}
err := PreparePlaylist(PlaylistManager[index])
if err != nil {
return
}
medias := PlaylistManager[index].Playlist
config.Player.PlaylistIndex = index
ApplyUser(medias, player.PlaylistUser)
SystemPlaylist.Replace(medias)
}
func PreparePlaylistByIndex(index int) {
l().Infof("try prepare playlist.id=%d", index)
if index < 0 || index >= len(PlaylistManager) {
l().Warn("playlist.id=%d not found", index)
return
}
err := PreparePlaylist(PlaylistManager[index])
if err != nil {
return
}
}

View File

@@ -0,0 +1,10 @@
package controller
import (
"fmt"
"testing"
)
func TestController(t *testing.T) {
fmt.Println(LiveClient == nil)
}

55
controller/global.go Normal file
View File

@@ -0,0 +1,55 @@
package controller
import (
"AynaLivePlayer/config"
"AynaLivePlayer/liveclient"
"AynaLivePlayer/player"
"AynaLivePlayer/provider"
"fmt"
)
var MainPlayer *player.Player
var UserPlaylist *player.Playlist
var SystemPlaylist *player.Playlist
var LiveClient liveclient.LiveClient
var PlaylistManager []*player.Playlist
var CurrentLyric *player.Lyric
func init() {
MainPlayer = player.NewPlayer()
UserPlaylist = player.NewPlaylist("user", player.PlaylistConfig{RandomNext: false})
SystemPlaylist = player.NewPlaylist("system", player.PlaylistConfig{RandomNext: config.Player.PlaylistRandom})
PlaylistManager = make([]*player.Playlist, 0)
CurrentLyric = player.NewLyric("")
loadPlaylists()
}
func loadPlaylists() {
l().Info("Loading playlists ", config.Player.Playlists, config.Player.PlaylistsProvider)
if len(config.Player.Playlists) != len(config.Player.Playlists) {
l().Warn("playlist id and provider does not have same length")
return
}
for i := 0; i < len(config.Player.Playlists); i++ {
pname := config.Player.PlaylistsProvider[i]
id := config.Player.Playlists[i]
p := player.NewPlaylist(fmt.Sprintf("%s-%s", pname, id), player.PlaylistConfig{})
p.Meta = provider.Meta{
Name: pname,
Id: id,
}
PlaylistManager = append(PlaylistManager, p)
}
if config.Player.PlaylistIndex < 0 || config.Player.PlaylistIndex >= len(config.Player.Playlists) {
l().Warn("playlist index did not find")
return
}
go func() {
c := config.Player.PlaylistIndex
err := PreparePlaylist(PlaylistManager[c])
if err != nil {
return
}
SetSystemPlaylist(c)
}()
}

28
controller/handlers.go Normal file
View File

@@ -0,0 +1,28 @@
package controller
import (
"AynaLivePlayer/event"
"github.com/aynakeya/go-mpv"
)
func handleMpvIdlePlayNext(property *mpv.EventProperty) {
isIdle := property.Data.(mpv.Node).Value.(bool)
if isIdle {
l().Info("mpv went idle, try play next")
PlayNext()
}
}
func handlePlaylistAdd(event *event.Event) {
if MainPlayer.IsIdle() {
PlayNext()
}
}
func handleLyricUpdate(property *mpv.EventProperty) {
if property.Data == nil {
return
}
t := property.Data.(mpv.Node).Value.(float64)
CurrentLyric.Update(t)
}

76
controller/provider.go Normal file
View File

@@ -0,0 +1,76 @@
package controller
import (
"AynaLivePlayer/config"
"AynaLivePlayer/player"
"AynaLivePlayer/provider"
)
func PrepareMedia(media *player.Media) error {
var err error
if media.Title == "" || media.Cover == "" {
l().Trace("fetching media info")
if err = provider.UpdateMedia(media); err != nil {
l().Warn("fail to prepare media when fetch info", err)
}
}
if media.Url == "" {
l().Trace("fetching media url")
if err = provider.UpdateMediaUrl(media); err != nil {
l().Warn("fail to prepare media when url", err)
}
}
if media.Lyric == "" {
l().Trace("fetching media lyric")
if err = provider.UpdateMediaLyric(media); err != nil {
l().Warn("fail to prepare media when lyric", err)
}
}
return err
}
func Search(keyword string) ([]*player.Media, error) {
l().Infof("Search for %s", keyword)
for _, p := range config.Provider.Priority {
if pr, ok := provider.Providers[p]; ok {
r, err := pr.Search(keyword)
if err != nil {
l().Warn("Provider %s return err", err)
continue
}
return r, err
} else {
l().Warnf("Provider %s not exist", p)
}
}
return nil, provider.ErrorNoSuchProvider
}
func SearchWithProvider(keyword string, p string) ([]*player.Media, error) {
l().Infof("Search for %s using %s", keyword, p)
if pr, ok := provider.Providers[p]; ok {
r, err := pr.Search(keyword)
return r, err
}
l().Warnf("Provider %s not exist", p)
return nil, provider.ErrorNoSuchProvider
}
func ApplyUser(medias []*player.Media, user interface{}) {
for _, m := range medias {
m.User = user
}
}
func PreparePlaylist(playlist *player.Playlist) error {
medias, err := provider.GetPlaylist(playlist.Meta.(provider.Meta))
if err != nil {
l().Warn("prepare playlist failed ", err)
return err
}
ApplyUser(medias, player.SystemUser)
playlist.Replace(medias)
return nil
}