From dae22a9716be58a5c268893bf701946a0e12e663 Mon Sep 17 00:00:00 2001 From: eyjhb Date: Tue, 4 Feb 2025 20:20:55 +0100 Subject: [PATCH] more shit --- cmd/mpv.go | 111 ++++++++++++++++++++++++++++++++++------------ cmd/player.go | 119 +++++++++++--------------------------------------- main.go | 14 ++++-- 3 files changed, 120 insertions(+), 124 deletions(-) diff --git a/cmd/mpv.go b/cmd/mpv.go index ce57993..fd4b0b3 100644 --- a/cmd/mpv.go +++ b/cmd/mpv.go @@ -12,13 +12,15 @@ import ( ) type MPVPLayer struct { - entries []*feedEntry + entries []*feedEntry + finishedEntries []*feedEntry c *mpvipc.Connection f *os.File - VideoPosition time.Duration - VideoDuration time.Duration + videoPosition time.Duration + videoDuration time.Duration + isPlaying bool sync.RWMutex } @@ -32,52 +34,103 @@ func (mpv *MPVPLayer) Exit() error { } func (mpv *MPVPLayer) Queue(e feedEntry) error { + mpv.Lock() + defer mpv.Unlock() + // TODO(eyJhb): implement checking mpv.entries = append(mpv.entries, &e) if len(mpv.entries) == 1 { - return mpv.Play(e.Link) + return mpv.play(e.Link) } return nil } -func (mpv *MPVPLayer) Play(url string) error { +func (mpv *MPVPLayer) FinishedPlaying() []*feedEntry { + mpv.Lock() + defer mpv.Unlock() + + f := mpv.finishedEntries + mpv.finishedEntries = nil + + return f +} + +func (mpv *MPVPLayer) CurrentlyPlaying() *feedEntry { + mpv.Lock() + defer mpv.Unlock() + + if !mpv.isPlaying { + return nil + } + + return mpv.entries[0] +} + +func (mpv *MPVPLayer) play(url string) error { if err := mpv.ensurePlayer(); err != nil { return err } - t, err := mpv.c.Call("loadfile", url) - fmt.Println(t) + _, err := mpv.c.Call("loadfile", url) + if err != nil { + return err + } + + mpv.isPlaying = true + return err } 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) IsPlaying() (bool, error) { - if mpv.c == nil || mpv.c.IsClosed() { - return false, nil - } +func (mpv *MPVPLayer) VideoDuration() time.Duration { + mpv.RLock() + defer mpv.RUnlock() - path, err := mpv.c.Get("path") - if err != nil { - return false, err - } - - return path != "", nil + return mpv.videoDuration } -func (mpv *MPVPLayer) finishedVideo() (bool, error) { +func (mpv *MPVPLayer) VideoPosition() time.Duration { + mpv.RLock() + defer mpv.RUnlock() + + return mpv.videoPosition +} + +func (mpv *MPVPLayer) IsPlaying() bool { mpv.Lock() defer mpv.Unlock() - mpv.entries = mpv.entries[1:] + if mpv.c == nil || mpv.c.IsClosed() { + if mpv.isPlaying == true { + mpv.finishedVideo() + } + return false + } + + return mpv.isPlaying +} + +func (mpv *MPVPLayer) finishedVideo() (bool, error) { + if len(mpv.entries) > 0 { + mpv.finishedEntries = append(mpv.finishedEntries, mpv.entries[0]) + mpv.entries = mpv.entries[1:] + } + mpv.isPlaying = false if len(mpv.entries) == 1 { - if err := mpv.Play(mpv.entries[0].Link); err != nil { + if err := mpv.play(mpv.entries[0].Link); err != nil { return false, err } } @@ -114,7 +167,6 @@ func (mpv *MPVPLayer) ensurePlayer() error { "mpv", "--keep-open=yes", "--idle", - // fmt.Sprintf("--input-ipc-server=%d", mpv.f.Fd()), fmt.Sprintf("--input-ipc-server=%s", mpv.f.Name()), ) @@ -144,22 +196,27 @@ func (mpv *MPVPLayer) ensurePlayer() error { go func() { for event := range events { - fmt.Println("event", event) - mpv.Lock() if event.ID == 1 { if event.Data != nil { - mpv.VideoDuration = time.Duration(event.Data.(float64)) * time.Second + mpv.Lock() + mpv.videoDuration = time.Duration(event.Data.(float64)) * time.Second + mpv.Unlock() } } else if event.ID == 2 { if event.Data != nil { - mpv.VideoPosition = time.Duration(event.Data.(float64)) * time.Second + mpv.Lock() + mpv.videoPosition = time.Duration(event.Data.(float64)) * time.Second + mpv.Unlock() } } else if event.ID == 3 { if event.Data != nil { - mpv.finishedVideo() + if event.Data.(bool) == true { + mpv.Lock() + mpv.finishedVideo() + mpv.Unlock() + } } } - mpv.Unlock() } }() diff --git a/cmd/player.go b/cmd/player.go index 0b41fe6..03033f1 100644 --- a/cmd/player.go +++ b/cmd/player.go @@ -1,13 +1,8 @@ package cmd import ( - "bufio" - "context" "fmt" - "os/exec" "regexp" - "strconv" - "strings" "sync" "time" @@ -23,38 +18,24 @@ var ( ) type playerModel struct { - entry *feedEntry - isPlayingVideo bool + // entry *feedEntry + // isPlayingVideo bool - // video information - videoDuration time.Duration - videoPosition time.Duration + // // video information + // videoDuration time.Duration + // videoPosition time.Duration // TODO: make this smarter // finished entries to send messages about finishedEntries []int64 + mpv *MPVPLayer + sync.RWMutex } func (m *playerModel) Init() tea.Cmd { - return nil -} - -func (m *playerModel) playEntry(f feedEntry) tea.Cmd { - if m.isPlayingVideo == true { - return nil - } - - m.entry = &f - - if m.entry != nil && m.isPlayingVideo == false { - go m.playVideo(context.Background(), m.entry.Link) - } else { - // TODO: we are already playing something, we should not allow this - // return MsgTick(time.Now()) - - } + m.mpv = NewMPVPlayer() return nil } @@ -63,28 +44,33 @@ func (m *playerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case MsgPlayEntry: f := feedEntry(msg) - return m, m.playEntry(f) + go m.mpv.Queue(f) } // send message because it is finished - m.Lock() - defer m.Unlock() - if len(m.finishedEntries) > 0 { - watchedEntryID := m.finishedEntries[0] - m.finishedEntries = m.finishedEntries[1:] - return m, func() tea.Msg { return MsgWatchedEntry(watchedEntryID) } + fe := m.mpv.FinishedPlaying() + if len(fe) > 0 { + var cmds []tea.Cmd + for _, e := range fe { + cmds = append(cmds, func() tea.Msg { return MsgWatchedEntry(e.ID) }) + } + return m, tea.Batch(cmds...) } return m, nil } func (m *playerModel) View() string { - if m.isPlayingVideo && m.entry != nil { - timePos := time.Time{}.Add(m.videoPosition) - timeDur := time.Time{}.Add(m.videoDuration) + // return "NO DONT ASK" + // return fmt.Sprintf("IsPlaying: %v", m.mpv.IsPlaying()) + + if m.mpv.IsPlaying() { + timePos := time.Time{}.Add(m.mpv.VideoPosition()) + timeDur := time.Time{}.Add(m.mpv.VideoDuration()) // truncate name if needed - name := m.entry.Name + // name := m.entry.Name + name := m.mpv.CurrentlyPlaying().Name if len(name) > playerMaxTitleLength { name = name[0:playerMaxTitleLength] + "..." } @@ -93,65 +79,10 @@ func (m *playerModel) View() string { name, timePos.Format(time.TimeOnly), timeDur.Format(time.TimeOnly), - videoPercentageWatched(m.videoPosition, m.videoDuration), + videoPercentageWatched(m.mpv.VideoPosition(), m.mpv.VideoDuration()), ) } return "" } - -func (m *playerModel) finishedVideo() { - m.Lock() - defer m.Unlock() - - m.isPlayingVideo = false - - if videoPercentageWatched(m.videoPosition, m.videoDuration) > 90.0 { - m.finishedEntries = append(m.finishedEntries, m.entry.ID) - } -} - -func (m *playerModel) playVideo(ctx context.Context, url string) (bool, error) { - m.Lock() - m.isPlayingVideo = true - m.Unlock() - - defer m.finishedVideo() - - cmd := exec.CommandContext(ctx, "mpv", url) - output, err := cmd.StdoutPipe() - if err != nil { - return false, err - } - - err = cmd.Start() - if err != nil { - return false, err - } - - s := bufio.NewScanner(output) - go func(s *bufio.Scanner) { - var finishedVideo bool - for s.Scan() { - t := s.Text() - if strings.Contains(t, "End of file") { - finishedVideo = true - } else if strings.HasPrefix(t, "AV: ") { - matches := regexpPosDur.FindStringSubmatch(t) - posh, _ := strconv.Atoi(matches[1]) - posm, _ := strconv.Atoi(matches[2]) - poss, _ := strconv.Atoi(matches[3]) - durh, _ := strconv.Atoi(matches[4]) - durm, _ := strconv.Atoi(matches[5]) - durs, _ := strconv.Atoi(matches[6]) - - m.videoPosition = time.Duration((posh*60*60 + posm*60 + poss) * int(time.Second)) - m.videoDuration = time.Duration((durh*60*60 + durm*60 + durs) * int(time.Second)) - } - } - _ = finishedVideo - }(s) - - return false, cmd.Wait() -} diff --git a/main.go b/main.go index d94ef82..6200e53 100644 --- a/main.go +++ b/main.go @@ -10,8 +10,8 @@ import ( ) func main() { - fmt.Println(test()) - return + // fmt.Println(test()) + // return // init miniflux client := miniflux.New("https://miniflux.fricloud.dk/v1/", "F_61V4HkhhJjCF_hI12oDAYhgMY2769KAvOkqPsubqc=") @@ -35,14 +35,22 @@ func main() { func test() error { p := cmd.NewMPVPlayer() fmt.Println(p.IsPlaying()) - err := p.Play("https://www.youtube.com/watch?v=gCYcHz2k5x0") + + // err := p.Play("https://www.youtube.com/watch?v=gCYcHz2k5x0") + var err error if err != nil { return err } time.Sleep(10 * time.Second) + fmt.Println("First is playing") fmt.Println(p.IsPlaying()) + for { + fmt.Println("2nd is playing") + fmt.Println(p.IsPlaying()) + } + // err = p.Play("https://www.youtube.com/watch?v=3d3ceC_EuC0") // if err != nil { // return err