|
@@ -0,0 +1,113 @@
|
|
|
+package player
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "errors"
|
|
|
+ "io"
|
|
|
+ "os"
|
|
|
+ "os/exec"
|
|
|
+ "path/filepath"
|
|
|
+)
|
|
|
+
|
|
|
+type VLC struct {
|
|
|
+ session *exec.Cmd
|
|
|
+ ctx context.Context
|
|
|
+ cancelFunc context.CancelFunc
|
|
|
+ wr *writer
|
|
|
+}
|
|
|
+
|
|
|
+func NewVLC(ctx context.Context) (Player, error) {
|
|
|
+ r := new(VLC)
|
|
|
+
|
|
|
+ if err := r.Available(ctx); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ return r, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *VLC) Available(ctx context.Context) error {
|
|
|
+ p.ctx, p.cancelFunc = context.WithCancel(ctx)
|
|
|
+
|
|
|
+ home, err := os.UserHomeDir()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ var (
|
|
|
+ paths = []string{
|
|
|
+ filepath.Join("/", "Applications", "VLC.app", "Contents", "MacOS", "VLC"),
|
|
|
+ filepath.Join("/", "Applications", "VLC.app", "Contents", "MacOS", "vlc"),
|
|
|
+ filepath.Join("/", "Applications", "MacPorts", "VLC.app", "Contents", "MacOS", "VLC"),
|
|
|
+ filepath.Join("/", "Applications", "MacPorts", "VLC.app", "Contents", "MacOS", "vlc"),
|
|
|
+ filepath.Join(home, "Applications", "VLC.app", "Contents", "MacOS", "vlc"),
|
|
|
+ filepath.Join(home, "Applications", "VLC.app", "Contents", "MacOS", "vlc"),
|
|
|
+ }
|
|
|
+ f *os.File
|
|
|
+ s os.FileInfo
|
|
|
+ )
|
|
|
+
|
|
|
+ for _, path := range paths {
|
|
|
+ if f, err = os.Open(path); err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if s, err = f.Stat(); err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if s.IsDir() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ p.session = exec.CommandContext(p.ctx, path, "-")
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ return errors.New("could not find installed VLC player")
|
|
|
+}
|
|
|
+
|
|
|
+func (p *VLC) Start(stop chan error) error {
|
|
|
+ if p.session == nil {
|
|
|
+ return errors.New("illegal state: player session was not established")
|
|
|
+ }
|
|
|
+
|
|
|
+ var (
|
|
|
+ pipe io.WriteCloser
|
|
|
+ err error
|
|
|
+ )
|
|
|
+
|
|
|
+ if pipe, err = p.session.StdinPipe(); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if err = p.session.Start(); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ p.wr = Writer(pipe)
|
|
|
+ go p.wr.Run(stop)
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *VLC) Write(d []byte) error {
|
|
|
+ if p.wr == nil {
|
|
|
+ return io.ErrClosedPipe
|
|
|
+ }
|
|
|
+
|
|
|
+ return p.wr.Write(d)
|
|
|
+}
|
|
|
+
|
|
|
+func (p *VLC) Close() error {
|
|
|
+ if p.cancelFunc != nil {
|
|
|
+ p.cancelFunc()
|
|
|
+ }
|
|
|
+
|
|
|
+ if p.wr != nil {
|
|
|
+ _ = p.wr.Close()
|
|
|
+ }
|
|
|
+
|
|
|
+ p.session = nil
|
|
|
+ return nil
|
|
|
+}
|