1package main23import (4 "github.com/nmeum/mpvfs/fileserver"5 "github.com/nmeum/mpvfs/mpv"6 "github.com/nmeum/mpvfs/playlistfs"78 "errors"9 "strings"10 "sync/atomic"11)1213var ErrEmptyPlaylist = errors.New("playlist is empty")1415type playctl struct {16 *playlistfs.BlockRecv1718 pos chan int19 play chan bool20 stopRead int322122 state *playerState23 mpv *mpv.Client24}2526func newCtl() (fileserver.File, error) {27 c := &playctl{28 state: state,29 mpv: mpvClient,30 pos: make(chan int, 1),31 play: make(chan bool, 1),32 }3334 c.BlockRecv = playlistfs.NewBlockRecv(c)35 return c, nil36}3738func (c *playctl) StateReader(pos int, playing bool) *strings.Reader {39 var str string40 if pos == -1 {41 str = "stop"42 } else if playing {43 str = "play"44 } else {45 str = "pause"46 }4748 // XXX: This will set position to -1 on stop49 cmd := playlistfs.Control{Name: str, Arg: &pos}50 return strings.NewReader(cmd.String() + "\n")51}5253func (c *playctl) CurrentReader() *strings.Reader {54 reader := c.StateReader(c.state.Index(), c.state.Playing())5556 go func(ch chan<- int) {57 for atomic.LoadInt32(&c.stopRead) == 0 {58 ch <- c.state.WaitIndex()59 }60 }(c.pos)61 go func(ch chan<- bool) {62 for atomic.LoadInt32(&c.stopRead) == 0 {63 ch <- c.state.WaitPlaying()64 }65 }(c.play)6667 return reader68}6970func (c *playctl) NextReader() *strings.Reader {71 var pos int72 var playing bool7374 select {75 case i := <-c.pos:76 pos = i77 playing = c.state.Playing()78 case p := <-c.play:79 playing = p80 pos = c.state.Index()81 }8283 return c.StateReader(pos, playing)84}8586func (c *playctl) Write(off int64, p []byte) (int, error) {87 cmd, err := playlistfs.CtlCmd(p)88 if err != nil {89 return 0, err90 }9192 if cmd.Arg != nil {93 err := c.mpv.SetProperty("playlist-pos", *cmd.Arg)94 if err != nil {95 return 0, err96 }97 }9899 switch cmd.Name {100 case "stop":101 err := c.mpv.SetProperty("playlist-pos", -1)102 if err != nil {103 return 0, err104 }105106 fallthrough107 case "pause":108 err := c.mpv.SetProperty("pause", true)109 if err != nil {110 return 0, err111 }112 case "skip":113 var inc int114 if cmd.Arg != nil {115 inc = *cmd.Arg116 } else {117 inc = 1118 }119120 idx := c.state.Index()121 if idx == -1 {122 inc = 1 // Start from beginning123 }124125 newArg := idx + inc126 cmd.Arg = &newArg127128 fallthrough129 case "play":130 fallthrough131 case "resume":132 err := c.mpv.SetProperty("pause", false)133 if err != nil {134 return 0, err135 }136 }137138 return len(p), nil139}140141func (c *playctl) Close() error {142 atomic.StoreInt32(&c.stopRead, 1)143 return nil144}