mirror of
https://github.com/AynaLivePlayer/AynaLivePlayer.git
synced 2025-12-14 14:08:22 +08:00
Merge 1.0.x branch (#8)
* rewrite * update submodule * make width height configurable * update dependency * update * update file * update dep * fix basic config layout * update plugin management * more stuff * add blacklist * fix todo * fix windows gethandle * update windows update guide * update windows build guide * include go mod tidy in script * update todo * fix source session * fix text output * add plugin play duration control * fix id diange not working * update todo * update version number
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
package adapter
|
||||
|
||||
import "AynaLivePlayer/core/model"
|
||||
|
||||
type IApplication interface {
|
||||
Version() model.VersionInfo
|
||||
LatestVersion() model.VersionInfo
|
||||
CheckUpdate() error
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/event"
|
||||
"AynaLivePlayer/core/model"
|
||||
)
|
||||
|
||||
type LiveClientCtor func(id string, ev *event.Manager, log ILogger) (LiveClient, error)
|
||||
|
||||
type LiveClient interface {
|
||||
ClientName() string
|
||||
RoomName() string
|
||||
Connect() bool
|
||||
Disconnect() bool
|
||||
Status() bool
|
||||
EventManager() *event.Manager
|
||||
}
|
||||
|
||||
type ILiveRoom interface {
|
||||
Client() LiveClient
|
||||
Model() *model.LiveRoom // should return mutable model (not a copy)
|
||||
Identifier() string
|
||||
DisplayName() string
|
||||
Status() bool
|
||||
EventManager() *event.Manager
|
||||
}
|
||||
|
||||
type LiveRoomExecutor interface {
|
||||
Match(command string) bool
|
||||
Execute(command string, args []string, danmu *model.DanmuMessage)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package adapter
|
||||
|
||||
type LogLevel uint32
|
||||
|
||||
const (
|
||||
LogLevelError LogLevel = iota
|
||||
LogLevelWarn
|
||||
LogLevelInfo
|
||||
LogLevelDebug
|
||||
)
|
||||
|
||||
type ILogger interface {
|
||||
Debug(args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Warn(args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
WithModule(prefix string) ILogger
|
||||
SetLogLevel(level LogLevel)
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/event"
|
||||
"AynaLivePlayer/core/model"
|
||||
)
|
||||
|
||||
type PlayerCtor func(ev *event.Manager, log ILogger) IPlayer
|
||||
|
||||
type IPlayer interface {
|
||||
// Start the player
|
||||
Start()
|
||||
// Stop the player
|
||||
Stop()
|
||||
// Play play a media
|
||||
Play(media *model.Media) error
|
||||
// GetPlaying get playing media
|
||||
// if player is idle, return nil
|
||||
GetPlaying() *model.Media
|
||||
// IsPaused return true if player is paused
|
||||
IsPaused() bool
|
||||
// Pause pause player
|
||||
Pause() error
|
||||
// Unpause unpause player
|
||||
Unpause() error
|
||||
// SetVolume set volume
|
||||
SetVolume(volume float64) error
|
||||
// IsIdle return true if player is playing anything
|
||||
IsIdle() bool
|
||||
// Seek to position, if absolute is true, position is absolute time, otherwise position is relative time
|
||||
Seek(position float64, absolute bool) error
|
||||
// SetWindowHandle set window handle for video output
|
||||
SetWindowHandle(handle uintptr) error
|
||||
// ObserveProperty observe player property change
|
||||
ObserveProperty(property model.PlayerProperty, name string, handler event.HandlerFunc) error
|
||||
// GetAudioDeviceList get audio device list
|
||||
GetAudioDeviceList() ([]model.AudioDevice, error)
|
||||
// SetAudioDevice set audio device
|
||||
SetAudioDevice(device string) error
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/event"
|
||||
"AynaLivePlayer/core/model"
|
||||
)
|
||||
|
||||
type IPlaylist interface {
|
||||
Identifier() string // must unique for each playlist
|
||||
Model() *model.Playlist // mutable model (not a copy)
|
||||
EventManager() *event.Manager
|
||||
DisplayName() string
|
||||
Size() int
|
||||
Get(index int) *model.Media
|
||||
Pop() *model.Media
|
||||
Replace(medias []*model.Media)
|
||||
Push(media *model.Media)
|
||||
Insert(index int, media *model.Media)
|
||||
Delete(index int) *model.Media
|
||||
Move(src int, dst int)
|
||||
Next() *model.Media
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package adapter
|
||||
|
||||
import "AynaLivePlayer/core/model"
|
||||
|
||||
type MediaProviderConfig map[string]string
|
||||
type MediaProviderCtor func(config MediaProviderConfig) MediaProvider
|
||||
|
||||
type MediaProvider interface {
|
||||
GetName() string
|
||||
MatchMedia(keyword string) *model.Media
|
||||
GetPlaylist(playlist *model.Meta) ([]*model.Media, error)
|
||||
FormatPlaylistUrl(uri string) string
|
||||
Search(keyword string) ([]*model.Media, error)
|
||||
UpdateMedia(media *model.Media) error
|
||||
UpdateMediaUrl(media *model.Media) error
|
||||
UpdateMediaLyric(media *model.Media) error
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/event"
|
||||
"AynaLivePlayer/core/model"
|
||||
)
|
||||
|
||||
// IControlBridge is the interface for all controller and
|
||||
// all system use cases.
|
||||
type IControlBridge interface {
|
||||
App() IApplication
|
||||
LiveRooms() ILiveRoomController
|
||||
PlayControl() IPlayController
|
||||
Playlists() IPlaylistController
|
||||
Provider() IProviderController
|
||||
Plugin() IPluginController
|
||||
LoadPlugins(plugins ...Plugin)
|
||||
Logger() ILogger
|
||||
CloseAndSave()
|
||||
}
|
||||
|
||||
type ILiveRoomController interface {
|
||||
Size() int
|
||||
Get(index int) ILiveRoom
|
||||
GetRoomStatus(index int) bool
|
||||
Connect(index int) error
|
||||
Disconnect(index int) error
|
||||
AddRoom(clientName, roomId string) (*model.LiveRoom, error)
|
||||
DeleteRoom(index int) error
|
||||
AddDanmuCommand(executor LiveRoomExecutor)
|
||||
GetAllClientNames() []string
|
||||
}
|
||||
|
||||
type IProviderController interface {
|
||||
GetPriority() []string
|
||||
PrepareMedia(media *model.Media) error
|
||||
MediaMatch(keyword string) *model.Media
|
||||
Search(keyword string) ([]*model.Media, error)
|
||||
SearchWithProvider(keyword string, provider string) ([]*model.Media, error)
|
||||
PreparePlaylist(playlist IPlaylist) error
|
||||
}
|
||||
|
||||
type IPluginController interface {
|
||||
LoadPlugin(plugin Plugin)
|
||||
LoadPlugins(plugins ...Plugin)
|
||||
ClosePlugins()
|
||||
}
|
||||
|
||||
type IPlaylistController interface {
|
||||
Size() int
|
||||
GetHistory() IPlaylist
|
||||
AddToHistory(media *model.Media)
|
||||
GetDefault() IPlaylist
|
||||
GetCurrent() IPlaylist
|
||||
Get(index int) IPlaylist
|
||||
Add(pname string, uri string) (IPlaylist, error)
|
||||
Remove(index int) (IPlaylist, error)
|
||||
SetDefault(index int) error
|
||||
PreparePlaylistByIndex(index int) error
|
||||
}
|
||||
|
||||
type IPlayControlConfig struct {
|
||||
SkipPlaylist bool
|
||||
AutoNextWhenFail bool
|
||||
}
|
||||
|
||||
type IPlayController interface {
|
||||
EventManager() *event.Manager
|
||||
GetPlaying() *model.Media
|
||||
GetPlayer() IPlayer
|
||||
PlayNext()
|
||||
Play(media *model.Media) error
|
||||
Add(keyword string, user interface{})
|
||||
AddWithProvider(keyword string, provider string, user interface{})
|
||||
Seek(position float64, absolute bool)
|
||||
Toggle() bool
|
||||
SetVolume(volume float64)
|
||||
Destroy()
|
||||
GetCurrentAudioDevice() string
|
||||
GetAudioDevices() []model.AudioDevice
|
||||
SetAudioDevice(device string)
|
||||
GetLyric() ILyricLoader
|
||||
Config() *IPlayControlConfig
|
||||
}
|
||||
|
||||
type ILyricLoader interface {
|
||||
EventManager() *event.Manager
|
||||
Get() *model.Lyric
|
||||
Reload(lyric string)
|
||||
Update(time float64)
|
||||
}
|
||||
@@ -1,54 +1,56 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/event"
|
||||
"AynaLivePlayer/core/model"
|
||||
)
|
||||
//const (
|
||||
// EventPlay event.EventId = "player.play"
|
||||
// EventPlayed event.EventId = "player.played"
|
||||
// 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"
|
||||
//)
|
||||
|
||||
const (
|
||||
EventPlay event.EventId = "player.play"
|
||||
EventPlayed event.EventId = "player.played"
|
||||
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"
|
||||
)
|
||||
const ErrorUpdate = "update.error"
|
||||
|
||||
func EventPlayerPropertyUpdate(property model.PlayerProperty) event.EventId {
|
||||
return event.EventId("player.property.update." + string(property))
|
||||
type ErrorUpdateEvent struct {
|
||||
Error error
|
||||
}
|
||||
|
||||
type PlaylistInsertEvent struct {
|
||||
Playlist *model.Playlist
|
||||
Index int
|
||||
Media *model.Media
|
||||
}
|
||||
|
||||
type PlaylistUpdateEvent struct {
|
||||
Playlist *model.Playlist // Playlist is a copy of the playlist
|
||||
}
|
||||
|
||||
type PlayEvent struct {
|
||||
Media *model.Media
|
||||
}
|
||||
|
||||
type LyricUpdateEvent struct {
|
||||
Lyrics *model.Lyric
|
||||
Time float64
|
||||
Lyric *model.LyricContext
|
||||
}
|
||||
|
||||
type LyricReloadEvent struct {
|
||||
Lyrics *model.Lyric
|
||||
}
|
||||
|
||||
type PlayerPropertyUpdateEvent struct {
|
||||
Property model.PlayerProperty
|
||||
Value model.PlayerPropertyValue
|
||||
}
|
||||
|
||||
type LiveRoomStatusUpdateEvent struct {
|
||||
RoomTitle string
|
||||
Status bool
|
||||
}
|
||||
//
|
||||
//func EventPlayerPropertyUpdate(property model.PlayerProperty) event.EventId {
|
||||
// return event.EventId("player.property.update." + string(property))
|
||||
//}
|
||||
//
|
||||
//type PlaylistInsertEvent struct {
|
||||
// Playlist *model.Playlist
|
||||
// Index int
|
||||
// Media *model.Media
|
||||
//}
|
||||
//
|
||||
//type PlaylistUpdateEvent struct {
|
||||
// Playlist *model.Playlist // Playlist is a copy of the playlist
|
||||
//}
|
||||
//
|
||||
//type PlayEvent struct {
|
||||
// Media *model.Media
|
||||
//}
|
||||
//
|
||||
//type LyricUpdateEvent struct {
|
||||
// Lyrics *model.Lyric
|
||||
// Time float64
|
||||
// Lyric *model.LyricContext
|
||||
//}
|
||||
//
|
||||
//type LyricReloadEvent struct {
|
||||
// Lyrics *model.Lyric
|
||||
//}
|
||||
//
|
||||
//type PlayerPropertyUpdateEvent struct {
|
||||
// Property model.PlayerProperty
|
||||
// Value model.PlayerPropertyValue
|
||||
//}
|
||||
//
|
||||
//type LiveRoomStatusUpdateEvent struct {
|
||||
// RoomTitle string
|
||||
// Status bool
|
||||
//}
|
||||
|
||||
@@ -1,16 +1,73 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/event"
|
||||
"AynaLivePlayer/core/adapter"
|
||||
"AynaLivePlayer/core/model"
|
||||
liveroomsdk "github.com/AynaLivePlayer/liveroom-sdk"
|
||||
)
|
||||
|
||||
const (
|
||||
LiveRoomStatusChange event.EventId = "liveclient.status.change"
|
||||
LiveRoomMessageReceive event.EventId = "liveclient.message.receive"
|
||||
)
|
||||
//const (
|
||||
// LiveRoomStatusChange event.EventId = "liveclient.status.change"
|
||||
// LiveRoomMessageReceive event.EventId = "liveclient.message.receive"
|
||||
//)
|
||||
//
|
||||
//type StatusChangeEvent struct {
|
||||
// Connected bool
|
||||
// Client adapter.LiveClient
|
||||
//}
|
||||
|
||||
type StatusChangeEvent struct {
|
||||
Connected bool
|
||||
Client adapter.LiveClient
|
||||
const LiveRoomAddCmd = "cmd.liveroom.add"
|
||||
|
||||
type LiveRoomAddCmdEvent struct {
|
||||
Title string
|
||||
Provider string
|
||||
RoomKey string
|
||||
}
|
||||
|
||||
const LiveRoomProviderUpdate = "update.liveroom.provider"
|
||||
|
||||
type LiveRoomProviderUpdateEvent struct {
|
||||
Providers []model.LiveRoomProviderInfo
|
||||
}
|
||||
|
||||
const LiveRoomRemoveCmd = "cmd.liveroom.remove"
|
||||
|
||||
type LiveRoomRemoveCmdEvent struct {
|
||||
Identifier string
|
||||
}
|
||||
|
||||
const LiveRoomRoomsUpdate = "update.liveroom.rooms"
|
||||
|
||||
type LiveRoomRoomsUpdateEvent struct {
|
||||
Rooms []model.LiveRoom
|
||||
}
|
||||
|
||||
const LiveRoomStatusUpdate = "update.liveroom.status"
|
||||
|
||||
type LiveRoomStatusUpdateEvent struct {
|
||||
Room model.LiveRoom
|
||||
}
|
||||
|
||||
const LiveRoomConfigChangeCmd = "cmd.liveroom.config.change"
|
||||
|
||||
type LiveRoomConfigChangeCmdEvent struct {
|
||||
Identifier string
|
||||
Config model.LiveRoomConfig
|
||||
}
|
||||
|
||||
const LiveRoomOperationCmd = "cmd.liveroom.operation"
|
||||
|
||||
type LiveRoomOperationCmdEvent struct {
|
||||
Identifier string
|
||||
SetConnect bool // connect or disconnect
|
||||
}
|
||||
|
||||
const LiveRoomOperationFinish = "update.liveroom.operation"
|
||||
|
||||
type LiveRoomOperationFinishEvent struct {
|
||||
}
|
||||
|
||||
const LiveRoomMessageReceive = "update.liveroom.message"
|
||||
|
||||
type LiveRoomMessageReceiveEvent struct {
|
||||
Message *liveroomsdk.Message
|
||||
}
|
||||
|
||||
37
core/events/player_control.go
Normal file
37
core/events/player_control.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/core/model"
|
||||
)
|
||||
|
||||
const PlayerVolumeChangeCmd = "cmd.player.op.change_volume"
|
||||
|
||||
type PlayerVolumeChangeCmdEvent struct {
|
||||
Volume float64 // Volume from 0-100
|
||||
}
|
||||
|
||||
const PlayerPlayCmd = "cmd.player.op.play"
|
||||
|
||||
type PlayerPlayCmdEvent struct {
|
||||
Media model.Media
|
||||
}
|
||||
|
||||
const PlayerSeekCmd = "cmd.player.op.seek"
|
||||
|
||||
type PlayerSeekCmdEvent struct {
|
||||
Position float64
|
||||
// Absolute is the seek mode.
|
||||
// if absolute = true : position is the time in second
|
||||
// if absolute = false: position is in percentage eg 0.1 0.2
|
||||
Absolute bool
|
||||
}
|
||||
|
||||
const PlayerToggleCmd = "cmd.player.op.toggle"
|
||||
|
||||
type PlayerToggleCmdEvent struct {
|
||||
}
|
||||
|
||||
const PlayerPlayNextCmd = "cmd.player.op.next"
|
||||
|
||||
type PlayerPlayNextCmdEvent struct {
|
||||
}
|
||||
23
core/events/player_lyric.go
Normal file
23
core/events/player_lyric.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package events
|
||||
|
||||
import "github.com/AynaLivePlayer/miaosic"
|
||||
|
||||
const PlayerLyricRequestCmd = "cmd.player.lyric.request"
|
||||
|
||||
type PlayerLyricRequestCmdEvent struct {
|
||||
}
|
||||
|
||||
const PlayerLyricReload = "update.player.lyric.reload"
|
||||
|
||||
type PlayerLyricReloadEvent struct {
|
||||
Lyrics miaosic.Lyrics
|
||||
}
|
||||
|
||||
const PlayerLyricPosUpdate = "update.player.lyric.pos"
|
||||
|
||||
type PlayerLyricPosUpdateEvent struct {
|
||||
Time float64
|
||||
CurrentIndex int // -1 means no lyric
|
||||
CurrentLine miaosic.LyricLine
|
||||
Total int // total lyric count
|
||||
}
|
||||
46
core/events/player_property.go
Normal file
46
core/events/player_property.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package events
|
||||
|
||||
import "AynaLivePlayer/core/model"
|
||||
|
||||
const PlayerPlayingUpdate = "update.player.playing"
|
||||
|
||||
type PlayerPlayingUpdateEvent struct {
|
||||
Media model.Media
|
||||
Removed bool // if no media is playing, removed is true
|
||||
}
|
||||
|
||||
const PlayerPropertyPauseUpdate = "update.player.property.pause"
|
||||
|
||||
type PlayerPropertyPauseUpdateEvent struct {
|
||||
Paused bool
|
||||
}
|
||||
|
||||
const PlayerPropertyPercentPosUpdate = "update.player.property.percent_pos"
|
||||
|
||||
type PlayerPropertyPercentPosUpdateEvent struct {
|
||||
PercentPos float64
|
||||
}
|
||||
|
||||
const PlayerPropertyIdleActiveUpdate = "update.player.property.idle_active"
|
||||
|
||||
type PlayerPropertyIdleActiveUpdateEvent struct {
|
||||
IsIdle bool
|
||||
}
|
||||
|
||||
const PlayerPropertyTimePosUpdate = "update.player.property.time_pos"
|
||||
|
||||
type PlayerPropertyTimePosUpdateEvent struct {
|
||||
TimePos float64 // Time in seconds
|
||||
}
|
||||
|
||||
const PlayerPropertyDurationUpdate = "update.player.property.duration"
|
||||
|
||||
type PlayerPropertyDurationUpdateEvent struct {
|
||||
Duration float64 // Duration in seconds
|
||||
}
|
||||
|
||||
const PlayerPropertyVolumeUpdate = "update.player.property.volume"
|
||||
|
||||
type PlayerPropertyVolumeUpdateEvent struct {
|
||||
Volume float64 // Volume from 0-100
|
||||
}
|
||||
22
core/events/player_videoplayer.go
Normal file
22
core/events/player_videoplayer.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package events
|
||||
|
||||
import "AynaLivePlayer/core/model"
|
||||
|
||||
const PlayerVideoPlayerSetWindowHandleCmd = "cmd.player.videoplayer.set_window_handle"
|
||||
|
||||
type PlayerVideoPlayerSetWindowHandleCmdEvent struct {
|
||||
Handle uintptr
|
||||
}
|
||||
|
||||
const PlayerSetAudioDeviceCmd = "cmd.player.set_audio_device"
|
||||
|
||||
type PlayerSetAudioDeviceCmdEvent struct {
|
||||
Device string
|
||||
}
|
||||
|
||||
const PlayerAudioDeviceUpdate = "update.player.audio_device"
|
||||
|
||||
type PlayerAudioDeviceUpdateEvent struct {
|
||||
Current string
|
||||
Devices []model.AudioDevice
|
||||
}
|
||||
81
core/events/playlist.go
Normal file
81
core/events/playlist.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/core/model"
|
||||
"AynaLivePlayer/pkg/event"
|
||||
)
|
||||
|
||||
func PlaylistDetailUpdate(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("update.playlist.detail." + id)
|
||||
}
|
||||
|
||||
type PlaylistDetailUpdateEvent struct {
|
||||
Medias []model.Media
|
||||
}
|
||||
|
||||
func PlaylistMoveCmd(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("cmd.playlist.move." + id)
|
||||
}
|
||||
|
||||
type PlaylistMoveCmdEvent struct {
|
||||
From int
|
||||
To int
|
||||
}
|
||||
|
||||
func PlaylistDeleteCmd(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("cmd.playlist.delete." + id)
|
||||
}
|
||||
|
||||
type PlaylistDeleteCmdEvent struct {
|
||||
Index int
|
||||
}
|
||||
|
||||
func PlaylistInsertCmd(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("cmd.playlist.insert." + id)
|
||||
}
|
||||
|
||||
type PlaylistInsertCmdEvent struct {
|
||||
Position int // position to insert, -1 means last one
|
||||
Media model.Media
|
||||
}
|
||||
|
||||
func PlaylistInsertUpdate(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("update.playlist.insert." + id)
|
||||
}
|
||||
|
||||
type PlaylistInsertUpdateEvent struct {
|
||||
Position int // position to insert, -1 means last one
|
||||
Media model.Media
|
||||
}
|
||||
|
||||
func PlaylistNextCmd(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("cmd.playlist.next." + id)
|
||||
}
|
||||
|
||||
type PlaylistNextCmdEvent struct {
|
||||
Remove bool // remove the media after next
|
||||
}
|
||||
|
||||
func PlaylistNextUpdate(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("update.playlist.next." + id)
|
||||
}
|
||||
|
||||
type PlaylistNextUpdateEvent struct {
|
||||
Media model.Media
|
||||
}
|
||||
|
||||
func PlaylistModeChangeCmd(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("cmd.playlist.mode." + id)
|
||||
}
|
||||
|
||||
type PlaylistModeChangeCmdEvent struct {
|
||||
Mode model.PlaylistMode
|
||||
}
|
||||
|
||||
func PlaylistModeChangeUpdate(id model.PlaylistID) event.EventId {
|
||||
return event.EventId("update.playlist.mode." + id)
|
||||
}
|
||||
|
||||
type PlaylistModeChangeUpdateEvent struct {
|
||||
Mode model.PlaylistMode
|
||||
}
|
||||
54
core/events/playlists.go
Normal file
54
core/events/playlists.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/core/model"
|
||||
)
|
||||
|
||||
const PlaylistManagerSetSystemCmd = "cmd.playlist.manager.set.system"
|
||||
|
||||
type PlaylistManagerSetSystemCmdEvent struct {
|
||||
PlaylistID string
|
||||
}
|
||||
|
||||
const PlaylistManagerSystemUpdate = "update.playlist.manager.system"
|
||||
|
||||
type PlaylistManagerSystemUpdateEvent struct {
|
||||
Info model.PlaylistInfo
|
||||
}
|
||||
|
||||
const PlaylistManagerRefreshCurrentCmd = "cmd.playlist.manager.refresh.current"
|
||||
|
||||
type PlaylistManagerRefreshCurrentCmdEvent struct {
|
||||
PlaylistID string
|
||||
}
|
||||
|
||||
const PlaylistManagerGetCurrentCmd = "cmd.playlist.manager.get.current"
|
||||
|
||||
type PlaylistManagerGetCurrentCmdEvent struct {
|
||||
PlaylistID string
|
||||
}
|
||||
|
||||
const PlaylistManagerCurrentUpdate = "update.playlist.manager.current"
|
||||
|
||||
type PlaylistManagerCurrentUpdateEvent struct {
|
||||
Medias []model.Media
|
||||
}
|
||||
|
||||
const PlaylistManagerInfoUpdate = "update.playlist.manager.info"
|
||||
|
||||
type PlaylistManagerInfoUpdateEvent struct {
|
||||
Playlists []model.PlaylistInfo
|
||||
}
|
||||
|
||||
const PlaylistManagerAddPlaylistCmd = "cmd.playlist.manager.add"
|
||||
|
||||
type PlaylistManagerAddPlaylistCmdEvent struct {
|
||||
Provider string
|
||||
URL string
|
||||
}
|
||||
|
||||
const PlaylistManagerRemovePlaylistCmd = "cmd.playlist.manager.remove"
|
||||
|
||||
type PlaylistManagerRemovePlaylistCmdEvent struct {
|
||||
PlaylistID string
|
||||
}
|
||||
7
core/events/provider.go
Normal file
7
core/events/provider.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package events
|
||||
|
||||
const MediaProviderUpdate = "update.media.provider.update"
|
||||
|
||||
type MediaProviderUpdateEvent struct {
|
||||
Providers []string
|
||||
}
|
||||
18
core/events/search.go
Normal file
18
core/events/search.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/core/model"
|
||||
)
|
||||
|
||||
const SearchCmd = "cmd.search"
|
||||
|
||||
type SearchCmdEvent struct {
|
||||
Keyword string
|
||||
Provider string
|
||||
}
|
||||
|
||||
const SearchResultUpdate = "update.search_result"
|
||||
|
||||
type SearchResultUpdateEvent struct {
|
||||
Medias []model.Media
|
||||
}
|
||||
@@ -1,40 +1,26 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
import "github.com/AynaLivePlayer/liveroom-sdk"
|
||||
|
||||
type LiveRoomConfig struct {
|
||||
AutoConnect bool `json:"auto_connect"`
|
||||
}
|
||||
|
||||
type LiveRoom struct {
|
||||
ClientName string
|
||||
ID string
|
||||
Title string
|
||||
AutoConnect bool
|
||||
AutoReconnect bool
|
||||
LiveRoom liveroom.LiveRoom `json:"live_room"`
|
||||
Config LiveRoomConfig `json:"config"`
|
||||
Title string `json:"title"`
|
||||
Status bool `json:"-"`
|
||||
}
|
||||
|
||||
func (r *LiveRoom) String() string {
|
||||
return fmt.Sprintf("<LiveRooms %s:%s>", r.ClientName, r.ID)
|
||||
func (r *LiveRoom) DisplayName() string {
|
||||
if r.Title != "" {
|
||||
return r.Title
|
||||
}
|
||||
return r.LiveRoom.Identifier()
|
||||
}
|
||||
|
||||
func (r *LiveRoom) Identifier() string {
|
||||
return fmt.Sprintf("%s_%s", r.ClientName, r.ID)
|
||||
}
|
||||
|
||||
type UserMedal struct {
|
||||
Name string
|
||||
Level int
|
||||
RoomID string
|
||||
}
|
||||
|
||||
type DanmuUser struct {
|
||||
Uid string
|
||||
Username string
|
||||
Medal UserMedal
|
||||
Admin bool
|
||||
Privilege int
|
||||
}
|
||||
|
||||
type DanmuMessage struct {
|
||||
User DanmuUser
|
||||
Message string
|
||||
type LiveRoomProviderInfo struct {
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
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 {
|
||||
Now *LyricLine
|
||||
Index int
|
||||
Total int
|
||||
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, "")
|
||||
if len(lrc) > 0 && lrc[len(lrc)-1] == '\r' {
|
||||
lrc = lrc[:len(lrc)-1]
|
||||
}
|
||||
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) findIndexV1(time float64) int {
|
||||
for i := 0; i < len(l.Lyrics)-1; i++ {
|
||||
if l.Lyrics[i].Time <= time && time < l.Lyrics[i+1].Time {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (l *Lyric) findIndex(time float64) int {
|
||||
start := 0
|
||||
end := len(l.Lyrics) - 1
|
||||
mid := (start + end) / 2
|
||||
for start < end {
|
||||
if l.Lyrics[mid].Time <= time && time < l.Lyrics[mid+1].Time {
|
||||
return mid
|
||||
}
|
||||
if l.Lyrics[mid].Time > time {
|
||||
end = mid
|
||||
} else {
|
||||
start = mid
|
||||
}
|
||||
mid = (start + end) / 2
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (l *Lyric) Find(time float64) *LyricLine {
|
||||
idx := l.findIndex(time)
|
||||
if idx == -1 {
|
||||
return nil
|
||||
}
|
||||
return l.Lyrics[idx]
|
||||
}
|
||||
|
||||
func (l *Lyric) FindContext(time float64, prev int, next int) *LyricContext {
|
||||
prev = -prev
|
||||
idx := l.findIndex(time)
|
||||
if idx == -1 {
|
||||
return nil
|
||||
}
|
||||
if (idx + prev) < 0 {
|
||||
prev = -idx
|
||||
}
|
||||
if (idx + 1 + next) > len(l.Lyrics) {
|
||||
next = len(l.Lyrics) - idx - 1
|
||||
}
|
||||
return &LyricContext{
|
||||
Now: l.Lyrics[idx],
|
||||
Index: idx,
|
||||
Total: len(l.Lyrics),
|
||||
Prev: l.Lyrics[idx+prev : idx],
|
||||
Next: l.Lyrics[idx+1 : idx+1+next],
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/magiconair/properties/assert"
|
||||
"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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLyricFindV2(t *testing.T) {
|
||||
lryic := LoadLyric(testLyric)
|
||||
for i := 0.0; i < 170; i += 0.01 {
|
||||
assert.Equal(t, lryic.Find(i), lryic.Find(i))
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,37 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/AynaLivePlayer/liveroom-sdk"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
)
|
||||
|
||||
type Picture struct {
|
||||
Url string
|
||||
Data []byte
|
||||
type User struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (p Picture) Exists() bool {
|
||||
return p.Url != "" || p.Data != nil
|
||||
}
|
||||
var PlaylistUser = User{Name: "Playlists"}
|
||||
var SystemUser = User{Name: "System"}
|
||||
|
||||
type Media struct {
|
||||
Title string
|
||||
Artist string
|
||||
Cover Picture
|
||||
Album string
|
||||
Lyric string
|
||||
Url string
|
||||
Header map[string]string
|
||||
User interface{}
|
||||
Meta interface{}
|
||||
Info miaosic.MediaInfo
|
||||
User interface{}
|
||||
}
|
||||
|
||||
func (m *Media) ToUser() *User {
|
||||
if u, ok := m.User.(*User); ok {
|
||||
func (m *Media) IsLiveRoomUser() bool {
|
||||
_, ok := m.User.(liveroom.User)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m *Media) ToUser() User {
|
||||
if u, ok := m.User.(User); ok {
|
||||
return u
|
||||
}
|
||||
return &User{Name: m.DanmuUser().Username}
|
||||
return User{Name: m.DanmuUser().Username}
|
||||
}
|
||||
|
||||
func (m *Media) DanmuUser() *DanmuUser {
|
||||
if u, ok := m.User.(*DanmuUser); ok {
|
||||
func (m *Media) DanmuUser() liveroom.User {
|
||||
if u, ok := m.User.(liveroom.User); ok {
|
||||
return u
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Media) Copy() *Media {
|
||||
newMedia := &Media{}
|
||||
copier.Copy(newMedia, m)
|
||||
return newMedia
|
||||
return liveroom.User{}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
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)
|
||||
}
|
||||
@@ -4,15 +4,3 @@ 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"
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package model
|
||||
|
||||
import "fmt"
|
||||
import "github.com/AynaLivePlayer/miaosic"
|
||||
|
||||
type PlaylistMode int
|
||||
|
||||
@@ -10,28 +10,22 @@ const (
|
||||
PlaylistModeRepeat
|
||||
)
|
||||
|
||||
type Playlist struct {
|
||||
Title string // can be same, display name
|
||||
Medias []*Media
|
||||
Mode PlaylistMode
|
||||
Meta Meta
|
||||
type PlaylistID string
|
||||
|
||||
const (
|
||||
PlaylistIDPlayer PlaylistID = "player"
|
||||
PlaylistIDSystem PlaylistID = "system"
|
||||
PlaylistIDHistory PlaylistID = "history"
|
||||
)
|
||||
|
||||
type PlaylistInfo struct {
|
||||
Meta miaosic.MetaData
|
||||
Title string
|
||||
}
|
||||
|
||||
func (p Playlist) String() string {
|
||||
return fmt.Sprintf("<Playlist %s len:%d>", p.Title, len(p.Medias))
|
||||
}
|
||||
|
||||
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{
|
||||
Title: p.Title,
|
||||
Medias: medias,
|
||||
Mode: p.Mode,
|
||||
Meta: p.Meta,
|
||||
func (p PlaylistInfo) DisplayName() string {
|
||||
if p.Title != "" {
|
||||
return p.Title
|
||||
}
|
||||
return p.Meta.ID()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package adapter
|
||||
package model
|
||||
|
||||
type Plugin interface {
|
||||
Name() string
|
||||
@@ -1,16 +0,0 @@
|
||||
package model
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Meta struct {
|
||||
Name string
|
||||
Id string
|
||||
}
|
||||
|
||||
func (m Meta) String() string {
|
||||
return fmt.Sprintf("<Meta %s:%s>", m.Name, m.Id)
|
||||
}
|
||||
|
||||
func (m Meta) Identifier() string {
|
||||
return fmt.Sprintf("%s_%s", m.Name, m.Id)
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package model
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func ApplyUser(medias []*Media, user interface{}) {
|
||||
for _, m := range medias {
|
||||
m.User = user
|
||||
}
|
||||
}
|
||||
|
||||
func ToSpMedia(media *Media, user *User) *Media {
|
||||
media = media.Copy()
|
||||
media.User = user
|
||||
return media
|
||||
}
|
||||
Reference in New Issue
Block a user