minifluxmpv/cmd/mpv.go
2025-02-08 21:13:52 +01:00

171 lines
2.7 KiB
Go

package cmd
import (
"fmt"
"os"
"os/exec"
"sync"
"time"
"github.com/dexterlb/mpvipc"
)
type VideoID string
type MPVPLayer struct {
c *mpvipc.Connection
f *os.File
videoID VideoID
videoPosition time.Duration
videoDuration time.Duration
isPlaying bool
finishedVideo string
sync.RWMutex
}
func NewMPVPlayer() *MPVPLayer {
return &MPVPLayer{}
}
func (mpv *MPVPLayer) Exit() error {
return nil
}
func (mpv *MPVPLayer) Play(id VideoID, url string) error {
if err := mpv.ensurePlayer(); err != nil {
return err
}
mpv.Lock()
defer mpv.Unlock()
_, err := mpv.c.Call("loadfile", url)
if err != nil {
return err
}
mpv.videoID = id
mpv.isPlaying = true
if err := mpv.c.Set("pause", false); err != nil {
return err
}
return nil
}
func (mpv *MPVPLayer) Stop() error {
mpv.Lock()
defer mpv.Unlock()
if mpv.c == nil {
return nil
}
err := mpv.c.Set("pause", true)
return err
}
func (mpv *MPVPLayer) VideoDuration() time.Duration {
mpv.Lock()
defer mpv.Unlock()
if mpv.c != nil {
data, _ := mpv.c.Get("duration")
if data != nil {
data_s := data.(float64)
if data_s != 0 {
mpv.videoDuration = time.Duration(data_s) * time.Second
}
}
}
return mpv.videoDuration
}
func (mpv *MPVPLayer) VideoPosition() time.Duration {
mpv.Lock()
defer mpv.Unlock()
if mpv.c != nil {
data, _ := mpv.c.Get("time-pos")
if data != nil {
data_s := data.(float64)
if data_s != 0 {
mpv.videoPosition = time.Duration(data_s) * time.Second
}
}
}
return mpv.videoPosition
}
func (mpv *MPVPLayer) IsPlaying() bool {
mpv.Lock()
defer mpv.Unlock()
if mpv.c == nil {
return false
}
// closed
if mpv.c.IsClosed() {
return false
}
// eof
data, _ := mpv.c.Get("eof-reached")
if data != nil && data.(bool) == true {
return false
}
return mpv.isPlaying
}
// TODO: this fucking sucks, a lot, what the fuck
func (mpv *MPVPLayer) ensurePlayer() error {
mpv.Lock()
defer mpv.Unlock()
if mpv.c != nil && !mpv.c.IsClosed() {
return nil
}
// TODO: cleanup this file
var err error
// mpv.f, err = os.Create(fmt.Sprintf("%s/%s", os.TempDir(), "mpvminiflux")) # no such device or address, etc. errors
mpv.f, err = os.CreateTemp("", "mpvminiflux")
if err != nil {
return err
}
cmd := exec.Command(
"mpv",
"--keep-open=yes",
"--idle",
fmt.Sprintf("--input-ipc-server=%s", mpv.f.Name()),
)
// start
err = cmd.Start()
if err != nil {
return err
}
// try 10 times to open connection
// return error otherwise
for i := 0; i < 10; i++ {
time.Sleep(10 * time.Millisecond)
mpv.c = mpvipc.NewConnection(mpv.f.Name())
err = mpv.c.Open()
if err == nil {
break
}
}
if err != nil {
return err
}
return nil
}