mirror of
https://github.com/AynaLivePlayer/AynaLivePlayer.git
synced 2026-05-12 02:25:00 +08:00
2
go.mod
2
go.mod
@@ -36,7 +36,7 @@ require (
|
||||
|
||||
require (
|
||||
fyne.io/systray v1.11.0 // indirect
|
||||
github.com/AynaLivePlayer/blivedm-go v0.0.0-20240427041017-949a66917a81 // indirect
|
||||
github.com/AynaLivePlayer/blivedm-go v0.0.0-20240922031304-c497ed5617c4 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.7.1 // indirect
|
||||
github.com/XiaoMengXinX/Music163Api-Go v0.1.30 // indirect
|
||||
|
||||
18
go.sum
18
go.sum
@@ -37,14 +37,12 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
fyne.io/fyne/v2 v2.5.0 h1:lEjEIso0Vi4sJXYngIMoXOM6aUjqnPjK7pBpxRxG9aI=
|
||||
fyne.io/fyne/v2 v2.5.0/go.mod h1:9D4oT3NWeG+MLi/lP7ItZZyujHC/qqMJpoGTAYX5Uqc=
|
||||
fyne.io/fyne/v2 v2.5.1 h1:jd2mhQz0ViosZjhgR5l2bdCbc5HFqkYnTzEXX8UOC7I=
|
||||
fyne.io/fyne/v2 v2.5.1/go.mod h1:NdxEG8L7EVWo06/cYbXW11uA0X7UG8Q8j5CLebvTZi8=
|
||||
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
|
||||
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
|
||||
fyne.io/x/fyne v0.0.0-20240326131024-3ba9170cc3be h1:HBAwKsmfTO4r1Ndlksy5oXIxgWiazj0gu2qmhOmkRFU=
|
||||
fyne.io/x/fyne v0.0.0-20240326131024-3ba9170cc3be/go.mod h1:1pa3ZVIopRWNvfSG4ZrSkcZ3mJ8qoHPZv4PT8/zpn1o=
|
||||
github.com/AynaLivePlayer/blivedm-go v0.0.0-20240427041017-949a66917a81 h1:AAPbv78hgdPQ96mSfPoUARxT1ZNJ0XzezZxaVmeRCVc=
|
||||
github.com/AynaLivePlayer/blivedm-go v0.0.0-20240427041017-949a66917a81/go.mod h1:wg2vP2yIJNPJKnmFWLi8WwrRL5w3/xl8gHdzYPdesMg=
|
||||
github.com/AynaLivePlayer/blivedm-go v0.0.0-20240922031304-c497ed5617c4 h1:ERr/3E+lEvJyN+pu9UIm+kMrh4mYVXeBMCuaghSQKZc=
|
||||
github.com/AynaLivePlayer/blivedm-go v0.0.0-20240922031304-c497ed5617c4/go.mod h1:wg2vP2yIJNPJKnmFWLi8WwrRL5w3/xl8gHdzYPdesMg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
@@ -126,8 +124,8 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
|
||||
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
|
||||
github.com/go-text/render v0.1.0 h1:osrmVDZNHuP1RSu3pNG7Z77Sd2xSbcb/xWytAj9kyVs=
|
||||
github.com/go-text/render v0.1.0/go.mod h1:jqEuNMenrmj6QRnkdpeaP0oKGFLDNhDkVKwGjsWWYU4=
|
||||
github.com/go-text/render v0.1.1-0.20240418202334-dd62631dae9b h1:daoFn+Aw8EIQZO9kYWwHL01FqwwpCl2nTeVEYbsgRHk=
|
||||
github.com/go-text/render v0.1.1-0.20240418202334-dd62631dae9b/go.mod h1:jqEuNMenrmj6QRnkdpeaP0oKGFLDNhDkVKwGjsWWYU4=
|
||||
github.com/go-text/typesetting v0.1.0 h1:vioSaLPYcHwPEPLT7gsjCGDCoYSbljxoHJzMnKwVvHw=
|
||||
github.com/go-text/typesetting v0.1.0/go.mod h1:d22AnmeKq/on0HNv73UFriMKc4Ez6EqZAofLhAzpSzI=
|
||||
github.com/go-text/typesetting-utils v0.0.0-20240329101916-eee87fb235a3 h1:levTnuLLUmpavLGbJYLJA7fQnKeS7P1eCdAlM+vReXk=
|
||||
@@ -292,8 +290,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/rymdport/portal v0.2.2 h1:P2Q/4k673zxdFAsbD8EESZ7psfuO6/4jNu6EDrDICkM=
|
||||
github.com/rymdport/portal v0.2.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||
github.com/rymdport/portal v0.2.6 h1:HWmU3gORu7vWcpr7VSwUS2Xx1HtJXVcUuTqEZcMEsIg=
|
||||
github.com/rymdport/portal v0.2.6/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
"AynaLivePlayer/internal/playlist"
|
||||
"AynaLivePlayer/internal/plugins"
|
||||
"AynaLivePlayer/internal/source"
|
||||
"AynaLivePlayer/internal/sysmediacontrol"
|
||||
"AynaLivePlayer/internal/updater"
|
||||
"AynaLivePlayer/pkg/config"
|
||||
"AynaLivePlayer/plugin/diange"
|
||||
"AynaLivePlayer/plugin/durationmgmt"
|
||||
"AynaLivePlayer/plugin/qiege"
|
||||
@@ -30,11 +32,15 @@ func Initialize() {
|
||||
wshub.NewWsHub(),
|
||||
)
|
||||
updater.Initialize()
|
||||
//sysmediacontrol.InitSystemMediaControl()
|
||||
if config.General.EnableSMC {
|
||||
sysmediacontrol.InitSystemMediaControl()
|
||||
}
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
//sysmediacontrol.Destroy()
|
||||
if config.General.EnableSMC {
|
||||
sysmediacontrol.Destroy()
|
||||
}
|
||||
liveroom.StopAndSave()
|
||||
playlist.Close()
|
||||
plugins.ClosePlugins()
|
||||
|
||||
@@ -7,14 +7,34 @@ import (
|
||||
"AynaLivePlayer/pkg/event"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var rng *rand.Rand
|
||||
|
||||
func init() {
|
||||
rng = rand.New(rand.NewSource(time.Now().Unix()))
|
||||
}
|
||||
|
||||
type playlist struct {
|
||||
Index int
|
||||
playlistId model.PlaylistID
|
||||
mode model.PlaylistMode
|
||||
Medias []model.Media
|
||||
Lock sync.RWMutex
|
||||
Index int
|
||||
playlistId model.PlaylistID
|
||||
mode model.PlaylistMode
|
||||
Medias []model.Media
|
||||
randomIndex []int
|
||||
Lock sync.RWMutex
|
||||
}
|
||||
|
||||
// resetRandomIndex reset the random index
|
||||
// this function is not locked, should be called in a locked context
|
||||
func (p *playlist) resetRandomIndex() {
|
||||
p.randomIndex = make([]int, p.Size())
|
||||
for i := 0; i < p.Size(); i++ {
|
||||
p.randomIndex[i] = i
|
||||
}
|
||||
rand.Shuffle(p.Size(), func(i, j int) {
|
||||
p.randomIndex[i], p.randomIndex[j] = p.randomIndex[j], p.randomIndex[i]
|
||||
})
|
||||
}
|
||||
|
||||
func newPlaylist(id model.PlaylistID) *playlist {
|
||||
@@ -41,10 +61,11 @@ func newPlaylist(id model.PlaylistID) *playlist {
|
||||
pl.Next(event.Data.(events.PlaylistNextCmdEvent).Remove)
|
||||
})
|
||||
global.EventManager.RegisterA(events.PlaylistModeChangeCmd(id), "internal.playlist.mode", func(event *event.Event) {
|
||||
if pl.mode == model.PlaylistModeRandom {
|
||||
pl.Index = 0
|
||||
}
|
||||
pl.Lock.Lock()
|
||||
pl.mode = event.Data.(events.PlaylistModeChangeCmdEvent).Mode
|
||||
pl.Index = 0
|
||||
pl.resetRandomIndex()
|
||||
pl.Lock.Unlock()
|
||||
log.Infof("Playlist %s mode changed to %d", id, pl.mode)
|
||||
global.EventManager.CallA(events.PlaylistModeChangeUpdate(id), events.PlaylistModeChangeUpdateEvent{
|
||||
Mode: pl.mode,
|
||||
@@ -57,6 +78,7 @@ func newPlaylist(id model.PlaylistID) *playlist {
|
||||
}
|
||||
pl.Index = index
|
||||
})
|
||||
pl.resetRandomIndex()
|
||||
return pl
|
||||
}
|
||||
|
||||
@@ -74,6 +96,7 @@ func (p *playlist) Replace(medias []model.Media) {
|
||||
p.Lock.Lock()
|
||||
p.Medias = medias
|
||||
p.Index = 0
|
||||
p.resetRandomIndex()
|
||||
p.Lock.Unlock()
|
||||
global.EventManager.CallA(events.PlaylistDetailUpdate(p.playlistId), events.PlaylistDetailUpdateEvent{
|
||||
Medias: p.CopyMedia(),
|
||||
@@ -93,6 +116,7 @@ func (p *playlist) Insert(index int, media model.Media) {
|
||||
p.Medias[i] = p.Medias[i-1]
|
||||
}
|
||||
p.Medias[index] = media
|
||||
p.resetRandomIndex()
|
||||
p.Lock.Unlock()
|
||||
global.EventManager.CallA(events.PlaylistInsertUpdate(p.playlistId), events.PlaylistInsertUpdateEvent{
|
||||
Position: index,
|
||||
@@ -111,6 +135,10 @@ func (p *playlist) Delete(index int) {
|
||||
}
|
||||
// todo: @5 delete optimization
|
||||
p.Medias = append(p.Medias[:index], p.Medias[index+1:]...)
|
||||
if p.Index >= p.Size() {
|
||||
p.Index = 0
|
||||
}
|
||||
p.resetRandomIndex()
|
||||
p.Lock.Unlock()
|
||||
global.EventManager.CallA(events.PlaylistDetailUpdate(p.playlistId), events.PlaylistDetailUpdateEvent{
|
||||
Medias: p.CopyMedia(),
|
||||
@@ -157,38 +185,46 @@ func (p *playlist) Next(delete bool) {
|
||||
}
|
||||
var index int
|
||||
index = p.Index
|
||||
// add guard
|
||||
// add guard, i don't know why this is needed
|
||||
// but it seems to fix a bug
|
||||
if index >= p.Size() {
|
||||
index = 0
|
||||
}
|
||||
if (index == 0) && p.mode == model.PlaylistModeRandom {
|
||||
p.resetRandomIndex()
|
||||
}
|
||||
var m model.Media
|
||||
if p.mode == model.PlaylistModeRandom {
|
||||
p.Index = rand.Intn(p.Size())
|
||||
} else if p.mode == model.PlaylistModeNormal {
|
||||
p.Index = (p.Index + 1) % p.Size()
|
||||
m = p.Medias[p.randomIndex[index]]
|
||||
} else {
|
||||
p.Index = index
|
||||
}
|
||||
m := p.Medias[index]
|
||||
// fix race condition
|
||||
currentSize := p.Size() - 1
|
||||
if delete {
|
||||
if p.mode == model.PlaylistModeRandom {
|
||||
if currentSize == 0 {
|
||||
p.Index = 0
|
||||
} else {
|
||||
p.Index = rand.Intn(currentSize)
|
||||
}
|
||||
} else if p.mode == model.PlaylistModeNormal {
|
||||
p.Index = index
|
||||
} else {
|
||||
p.Index = index
|
||||
}
|
||||
m = p.Medias[index]
|
||||
}
|
||||
//// fix race condition
|
||||
//currentSize := p.Size() - 1
|
||||
//if delete {
|
||||
// if p.mode == model.PlaylistModeRandom {
|
||||
// if currentSize == 0 {
|
||||
// p.Index = 0
|
||||
// } else {
|
||||
// p.Index = rand.Intn(currentSize)
|
||||
// }
|
||||
// } else if p.mode == model.PlaylistModeNormal {
|
||||
// p.Index = index
|
||||
// } else {
|
||||
// p.Index = index
|
||||
// }
|
||||
//}
|
||||
p.Lock.Unlock()
|
||||
global.EventManager.CallA(events.PlaylistNextUpdate(p.playlistId), events.PlaylistNextUpdateEvent{
|
||||
Media: m,
|
||||
})
|
||||
if delete {
|
||||
p.Delete(index)
|
||||
if p.mode == model.PlaylistModeRandom {
|
||||
p.Delete(p.randomIndex[index])
|
||||
} else {
|
||||
p.Delete(index)
|
||||
}
|
||||
} else {
|
||||
p.Index = (p.Index + 1) % p.Size()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@ import (
|
||||
"AynaLivePlayer/global"
|
||||
"AynaLivePlayer/pkg/config"
|
||||
"AynaLivePlayer/pkg/event"
|
||||
"AynaLivePlayer/pkg/logger"
|
||||
"github.com/go-ole/go-ole"
|
||||
"github.com/saltosystems/winrt-go"
|
||||
"github.com/saltosystems/winrt-go/windows/foundation"
|
||||
"github.com/saltosystems/winrt-go/windows/media"
|
||||
"github.com/saltosystems/winrt-go/windows/media/playback"
|
||||
"github.com/saltosystems/winrt-go/windows/storage/streams"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -35,6 +37,8 @@ var (
|
||||
media.SignatureSystemMediaTransportControls,
|
||||
media.SignatureSystemMediaTransportControlsButtonPressedEventArgs,
|
||||
)
|
||||
timelineProps *media.SystemMediaTransportControlsTimelineProperties
|
||||
log logger.ILogger
|
||||
)
|
||||
|
||||
func must[T any](t T, err error) T {
|
||||
@@ -60,6 +64,7 @@ func withMusicProperties(f func(updater *media.SystemMediaTransportControlsDispl
|
||||
|
||||
func InitSystemMediaControl() {
|
||||
_ = ole.RoInitialize(1)
|
||||
log = global.Logger.WithPrefix("SMTC")
|
||||
|
||||
sptr, _ := syscall.UTF16PtrFromString("Aynakeya." + config.ProgramName)
|
||||
syscall.SyscallN(SetCurrentProcessExplicitAppUserModelID, uintptr(unsafe.Pointer(sptr)))
|
||||
@@ -74,6 +79,7 @@ func InitSystemMediaControl() {
|
||||
_ = smtc.SetIsNextEnabled(true)
|
||||
_ = smtc.SetIsPreviousEnabled(true)
|
||||
_ = smtc.SetPlaybackStatus(media.MediaPlaybackStatusPlaying)
|
||||
|
||||
withDisplayUpdater(func(updater *media.SystemMediaTransportControlsDisplayUpdater) {
|
||||
_ = updater.SetType(media.MediaPlaybackTypeMusic)
|
||||
})
|
||||
@@ -83,13 +89,87 @@ func InitSystemMediaControl() {
|
||||
withMusicProperties(func(updater *media.SystemMediaTransportControlsDisplayUpdater, properties *media.MusicDisplayProperties) {
|
||||
properties.SetArtist(data.Media.Info.Artist)
|
||||
properties.SetTitle(data.Media.Info.Title)
|
||||
properties.SetAlbumTitle(data.Media.Info.Album)
|
||||
if data.Media.Info.Cover.Url != "" {
|
||||
imgUri, _ := foundation.UriCreateUri(data.Media.Info.Cover.Url)
|
||||
defer imgUri.Release()
|
||||
stream, _ := streams.RandomAccessStreamReferenceCreateFromUri(imgUri)
|
||||
defer stream.Release()
|
||||
_ = updater.SetThumbnail(stream)
|
||||
} else {
|
||||
// todo: using cover data
|
||||
}
|
||||
_ = updater.Update()
|
||||
})
|
||||
if data.Removed {
|
||||
smtc.SetPlaybackStatus(media.MediaPlaybackStatusChanging)
|
||||
}
|
||||
})
|
||||
|
||||
global.EventManager.RegisterA(events.PlayerPropertyPauseUpdate, "sysmediacontrol.update_paused", func(event *event.Event) {
|
||||
if event.Data.(events.PlayerPropertyPauseUpdateEvent).Paused {
|
||||
smtc.SetPlaybackStatus(media.MediaPlaybackStatusPaused)
|
||||
} else {
|
||||
smtc.SetPlaybackStatus(media.MediaPlaybackStatusPlaying)
|
||||
}
|
||||
})
|
||||
|
||||
pressedHandler := foundation.NewTypedEventHandler(
|
||||
ole.NewGUID(buttonPressedEventGUID),
|
||||
func(_ *foundation.TypedEventHandler, _ unsafe.Pointer, args unsafe.Pointer) {
|
||||
eventArgs := (*media.SystemMediaTransportControlsButtonPressedEventArgs)(args)
|
||||
defer eventArgs.Release()
|
||||
switch val, _ := eventArgs.GetButton(); val {
|
||||
case media.SystemMediaTransportControlsButtonPlay:
|
||||
global.EventManager.CallA(
|
||||
events.PlayerSetPauseCmd, events.PlayerSetPauseCmdEvent{Pause: false})
|
||||
case media.SystemMediaTransportControlsButtonPause:
|
||||
global.EventManager.CallA(
|
||||
events.PlayerSetPauseCmd, events.PlayerSetPauseCmdEvent{Pause: true})
|
||||
case media.SystemMediaTransportControlsButtonNext:
|
||||
global.EventManager.CallA(
|
||||
events.PlayerPlayNextCmd, events.PlayerPlayNextCmdEvent{})
|
||||
case media.SystemMediaTransportControlsButtonPrevious:
|
||||
global.EventManager.CallA(events.PlayerSeekCmd, events.PlayerSeekCmdEvent{
|
||||
Position: 0,
|
||||
Absolute: true,
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
_, _ = smtc.AddButtonPressed(pressedHandler)
|
||||
pressedHandler.Release()
|
||||
|
||||
// todo: finish timeline properties
|
||||
// cuz win 11 are not display timeline properties now
|
||||
// i just ignore it
|
||||
lastDuration := int64(0)
|
||||
lastTimePos := int64(0)
|
||||
timelineProps, _ = media.NewSystemMediaTransportControlsTimelineProperties()
|
||||
global.EventManager.RegisterA(events.PlayerPropertyDurationUpdate, "sysmediacontrol.properties.duration", func(event *event.Event) {
|
||||
data := event.Data.(events.PlayerPropertyDurationUpdateEvent)
|
||||
lastDuration = int64(data.Duration * 1000)
|
||||
_ = timelineProps.SetStartTime(foundation.TimeSpan{Duration: 0})
|
||||
_ = timelineProps.SetMinSeekTime(foundation.TimeSpan{Duration: 0})
|
||||
_ = timelineProps.SetEndTime(foundation.TimeSpan{Duration: lastDuration * TicksPerMillisecond})
|
||||
_ = timelineProps.SetMaxSeekTime(foundation.TimeSpan{Duration: lastDuration * TicksPerMillisecond})
|
||||
_ = timelineProps.SetPosition(foundation.TimeSpan{Duration: lastTimePos * TicksPerMillisecond})
|
||||
_ = smtc.UpdateTimelineProperties(timelineProps)
|
||||
})
|
||||
global.EventManager.RegisterA(events.PlayerPropertyTimePosUpdate, "sysmediacontrol.properties.time_pos", func(event *event.Event) {
|
||||
data := event.Data.(events.PlayerPropertyTimePosUpdateEvent)
|
||||
lastTimePos = int64(data.TimePos * 1000)
|
||||
_ = timelineProps.SetStartTime(foundation.TimeSpan{Duration: 0})
|
||||
_ = timelineProps.SetMinSeekTime(foundation.TimeSpan{Duration: 0})
|
||||
_ = timelineProps.SetEndTime(foundation.TimeSpan{Duration: lastDuration * TicksPerMillisecond})
|
||||
_ = timelineProps.SetMaxSeekTime(foundation.TimeSpan{Duration: lastDuration * TicksPerMillisecond})
|
||||
_ = timelineProps.SetPosition(foundation.TimeSpan{Duration: lastTimePos * TicksPerMillisecond})
|
||||
_ = smtc.UpdateTimelineProperties(timelineProps)
|
||||
})
|
||||
}
|
||||
|
||||
func Destroy() {
|
||||
timelineProps.Release()
|
||||
smtc.Release()
|
||||
_player.Release()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
const (
|
||||
ProgramName = "卡西米尔唱片机"
|
||||
Version uint32 = 0x010009
|
||||
Version uint32 = 0x010100
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -11,6 +11,7 @@ type _GeneralConfig struct {
|
||||
PlayNextOnFail bool
|
||||
UseSystemPlaylist bool
|
||||
FixedSize bool
|
||||
EnableSMC bool // enable system media control
|
||||
}
|
||||
|
||||
func (c *_GeneralConfig) Name() string {
|
||||
@@ -27,4 +28,5 @@ var General = &_GeneralConfig{
|
||||
PlayNextOnFail: false,
|
||||
UseSystemPlaylist: true,
|
||||
FixedSize: true,
|
||||
EnableSMC: true,
|
||||
}
|
||||
|
||||
Submodule pkg/liveroom-sdk updated: 457e63879a...5a2c1d569d
Submodule pkg/miaosic updated: 6ee4bed043...2521f55b66
@@ -3,5 +3,5 @@ Artist: {{ .Current.Artist }}
|
||||
Album: {{ .Current.Album}}
|
||||
Username: {{ .Current.Username }}
|
||||
Progress(in seconds): {{.CurrentTime.TotalSeconds}} / {{.TotalTime.TotalSeconds}}
|
||||
Progress(in minutes:seconds): {{ .CurrentTime.Minutes}}:{{ .CurrentTime.Seconds}} / {{ .TotalTime.Minutes}}:{{ .TotalTime.Seconds}}
|
||||
Progress(in minutes:seconds): {{printf "%02d" .CurrentTime.Minutes}}:{{printf "%02d" .CurrentTime.Seconds}} / {{printf "%02d" .TotalTime.Minutes}}:{{printf "%02d" .TotalTime.Seconds}}
|
||||
Lyric: {{ .Lyric}}
|
||||
@@ -1,5 +1,5 @@
|
||||
{{range .Playlist}}
|
||||
Index: # {{ .Index}}
|
||||
Index: #{{ .Index}}
|
||||
Title: {{ .Title }}
|
||||
Artist: {{ .Artist }}
|
||||
Album: {{ .Album}}
|
||||
|
||||
8
todo.txt
8
todo.txt
@@ -8,16 +8,18 @@
|
||||
- 适配歌词服务器
|
||||
- 媒体源 - 歌单信息获取
|
||||
- mpris, SMTC
|
||||
- web弹幕协议的断线handler (web 重连)
|
||||
- 歌词event发送全部歌词,前端处理不同版本
|
||||
- 网页输出重写,使用网页版本,不绑定在点歌机内(点歌机不需要启动网页服务)
|
||||
- optimize local music
|
||||
- 从搜索里添加的歌不能被切
|
||||
- 随机歌单
|
||||
|
||||
----
|
||||
|
||||
Finished
|
||||
- 2024.08.25 : 添加是否播放闲置歌单选项,修复退出时panic的导致配置无法正确保存的问题
|
||||
- 2024.10.24 : 修复随机播放是真随机的问题,现在每首歌在都会被播放到,添加windows系统级控制
|
||||
- 2024.10.05 : 添加windows system media transport control
|
||||
- 2024.09.25 : 修复web弹幕粉丝牌子等级获取不正确的问题
|
||||
- 2024.08.25@1.0.9 : 添加是否播放闲置歌单选项,修复退出时panic的导致配置无法正确保存的问题
|
||||
- 2024.08.14 : 网页输出模版beta上线
|
||||
- 2024.08.06 : 修复使用身份码连接的时候房管无法切歌的问题
|
||||
- 2024.07.25 : 或许修复配置无法正确保存的问题
|
||||
|
||||
Reference in New Issue
Block a user