update
This commit is contained in:
parent
0d87346089
commit
32c5cae17a
2 changed files with 151 additions and 95 deletions
142
cmd/cmd.go
142
cmd/cmd.go
|
@ -3,14 +3,11 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/blang/mpv"
|
|
||||||
"github.com/charmbracelet/bubbles/list"
|
"github.com/charmbracelet/bubbles/list"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/simonhege/timeago"
|
|
||||||
miniflux "miniflux.app/client"
|
miniflux "miniflux.app/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,124 +20,91 @@ var (
|
||||||
quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
|
quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Test uint
|
type ViewType uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ViewListCategories = 10
|
ViewListFeedEntries ViewType = iota
|
||||||
|
ViewPlayer
|
||||||
|
ViewFeeds
|
||||||
)
|
)
|
||||||
|
|
||||||
type feedEntry struct {
|
type MsgChangeView ViewType
|
||||||
Name string
|
type MsgSelectedItem feedEntry
|
||||||
Feed string
|
type MsgTickInternal time.Time
|
||||||
Link string
|
type MsgTick uint8
|
||||||
PublishedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type MsgFetchedEntries []feedEntry
|
|
||||||
type MsgFetchedEntriesError error
|
|
||||||
|
|
||||||
func (fe feedEntry) Title() string { return fe.Name }
|
|
||||||
func (fe feedEntry) Description() string {
|
|
||||||
formattedTimeAgo := timeago.WithMax(timeago.English, time.Hour*7*24, timeago.English.DefaultLayout).Format(fe.PublishedAt)
|
|
||||||
return fmt.Sprintf("%s - Published %s", fe.Feed, formattedTimeAgo)
|
|
||||||
}
|
|
||||||
func (fe feedEntry) FilterValue() string { return fmt.Sprintf("%s - %s", fe.Name, fe.Feed) }
|
|
||||||
|
|
||||||
type MinifluxPlayer struct {
|
type MinifluxPlayer struct {
|
||||||
MinifluxClient *miniflux.Client
|
MinifluxClient *miniflux.Client
|
||||||
DefaultCategory string
|
DefaultCategory string
|
||||||
MpvPath string
|
MpvPath string
|
||||||
|
|
||||||
// feedEntriesList []feedEntry
|
CurrentView ViewType
|
||||||
feedEntriesList list.Model
|
|
||||||
selectedEntry *feedEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *MinifluxPlayer) fetchEntries() tea.Msg {
|
feedEntries feedEntriesModel
|
||||||
entriesResult, err := mp.MinifluxClient.CategoryEntries(4, nil)
|
player playerModel
|
||||||
if err != nil {
|
|
||||||
return MsgFetchedEntriesError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var feedEntries []feedEntry
|
|
||||||
for _, e := range entriesResult.Entries {
|
|
||||||
feedEntries = append(feedEntries, feedEntry{
|
|
||||||
Name: e.Title,
|
|
||||||
Feed: e.Feed.Title,
|
|
||||||
Link: e.URL,
|
|
||||||
PublishedAt: e.Date,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
slices.Reverse(feedEntries)
|
|
||||||
|
|
||||||
return MsgFetchedEntries(feedEntries)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MinifluxPlayer) Init() tea.Cmd {
|
func (mp *MinifluxPlayer) Init() tea.Cmd {
|
||||||
mp.feedEntriesList = list.New([]list.Item{feedEntry{}}, list.NewDefaultDelegate(), 100, 50)
|
mp.feedEntries = feedEntriesModel{
|
||||||
mp.feedEntriesList.Title = "Feed"
|
minifluxClient: mp.MinifluxClient,
|
||||||
return mp.fetchEntries
|
}
|
||||||
|
|
||||||
|
mp.player = playerModel{}
|
||||||
|
|
||||||
|
return tea.Sequence(
|
||||||
|
tickEvery(),
|
||||||
|
mp.feedEntries.Init(),
|
||||||
|
mp.player.Init(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MinifluxPlayer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (mp *MinifluxPlayer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case tea.WindowSizeMsg:
|
|
||||||
mp.feedEntriesList.SetSize(msg.Width, msg.Height)
|
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
case "ctrl+c", "q":
|
||||||
return mp, tea.Quit
|
return mp, tea.Quit
|
||||||
case "enter":
|
|
||||||
i, ok := mp.feedEntriesList.SelectedItem().(feedEntry)
|
|
||||||
if ok {
|
|
||||||
mp.selectedEntry = &i
|
|
||||||
}
|
|
||||||
return mp, tea.Quit
|
|
||||||
}
|
}
|
||||||
break
|
case MsgTickInternal:
|
||||||
|
fnSendTick := func() tea.Msg { return MsgTick(0) }
|
||||||
case MsgFetchedEntries:
|
return mp, tea.Batch(tickEvery(), fnSendTick)
|
||||||
var items []list.Item
|
case MsgChangeView:
|
||||||
for _, e := range msg {
|
mp.CurrentView = ViewType(msg)
|
||||||
items = append(items, e)
|
|
||||||
}
|
|
||||||
mp.feedEntriesList.SetItems(items)
|
|
||||||
case MsgFetchedEntriesError:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmd tea.Cmd
|
if mp.CurrentView == ViewListFeedEntries {
|
||||||
mp.feedEntriesList, cmd = mp.feedEntriesList.Update(msg)
|
_, c := mp.feedEntries.Update(msg)
|
||||||
return mp, cmd
|
return mp, c
|
||||||
|
} else if mp.CurrentView == ViewPlayer {
|
||||||
|
_, c := mp.player.Update(msg)
|
||||||
|
return mp, c
|
||||||
|
}
|
||||||
|
|
||||||
|
return mp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MinifluxPlayer) View() string {
|
func (mp *MinifluxPlayer) View() string {
|
||||||
if mp.selectedEntry != nil {
|
if mp.CurrentView == ViewPlayer {
|
||||||
ipcc := mpv.NewIPCClient("/tmp/mpvsocket") // Lowlevel client
|
return mp.player.View()
|
||||||
c := mpv.NewClient(ipcc) // Highlevel client, can also use RPCClient
|
|
||||||
|
|
||||||
c.Loadfile(mp.selectedEntry.Link, mpv.LoadFileModeReplace)
|
|
||||||
// c.SetPause(true)
|
|
||||||
// c.Seek(600, mpv.SeekModeAbsolute)
|
|
||||||
// c.SetFullscreen(true)
|
|
||||||
c.SetPause(false)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
for {
|
|
||||||
pos, _ := c.Position()
|
|
||||||
dur, _ := c.Duration()
|
|
||||||
fmt.Printf("%f/%f\n", pos, dur)
|
|
||||||
|
|
||||||
if pos >= dur {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return quitTextStyle.Render(fmt.Sprintf("Selected entry %s", mp.selectedEntry.Link))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mp.feedEntriesList.View()
|
if mp.player.currentlyPlaying == true {
|
||||||
|
return lipgloss.JoinVertical(0.2, mp.feedEntries.View(), "", fmt.Sprintf("Currently Playing: %s (%v/%v)",
|
||||||
|
mp.player.selectedEntry.Name,
|
||||||
|
mp.player.videoPosition,
|
||||||
|
mp.player.videoDuration,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return mp.feedEntries.View()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MinifluxPlayer) FetchCategories(ctx context.Context) ([]*miniflux.Category, error) {
|
func (mp *MinifluxPlayer) FetchCategories(ctx context.Context) ([]*miniflux.Category, error) {
|
||||||
return mp.MinifluxClient.Categories()
|
return mp.MinifluxClient.Categories()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tickEvery() tea.Cmd {
|
||||||
|
return tea.Every(time.Second, func(t time.Time) tea.Msg {
|
||||||
|
return MsgTickInternal(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,100 @@
|
||||||
// package cmd
|
package cmd
|
||||||
|
|
||||||
// import "github.com/charmbracelet/bubbles/list"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
|
||||||
// type feedEntriesModel struct {
|
"github.com/charmbracelet/bubbles/list"
|
||||||
// entries list.Model
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
// selectedEntry
|
"github.com/simonhege/timeago"
|
||||||
// }
|
miniflux "miniflux.app/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type feedEntry struct {
|
||||||
|
Name string
|
||||||
|
Feed string
|
||||||
|
Link string
|
||||||
|
PublishedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fe feedEntry) Title() string { return fe.Name }
|
||||||
|
func (fe feedEntry) Description() string {
|
||||||
|
formattedTimeAgo := timeago.WithMax(timeago.English, time.Hour*7*24, timeago.English.DefaultLayout).Format(fe.PublishedAt)
|
||||||
|
return fmt.Sprintf("%s - Published %s", fe.Feed, formattedTimeAgo)
|
||||||
|
}
|
||||||
|
func (fe feedEntry) FilterValue() string { return fmt.Sprintf("%s - %s", fe.Name, fe.Feed) }
|
||||||
|
|
||||||
|
type feedEntriesModel struct {
|
||||||
|
minifluxClient *miniflux.Client
|
||||||
|
entries list.Model
|
||||||
|
selectedEntry *feedEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
type MsgFetchedEntries []feedEntry
|
||||||
|
type MsgFetchedEntriesError error
|
||||||
|
|
||||||
|
func (m *feedEntriesModel) fetchEntries() tea.Msg {
|
||||||
|
entriesResult, err := m.minifluxClient.CategoryEntries(4, nil)
|
||||||
|
if err != nil {
|
||||||
|
return MsgFetchedEntriesError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var feedEntries []feedEntry
|
||||||
|
for _, e := range entriesResult.Entries {
|
||||||
|
feedEntries = append(feedEntries, feedEntry{
|
||||||
|
Name: e.Title,
|
||||||
|
Feed: e.Feed.Title,
|
||||||
|
Link: e.URL,
|
||||||
|
PublishedAt: e.Date,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
slices.Reverse(feedEntries)
|
||||||
|
|
||||||
|
return MsgFetchedEntries(feedEntries)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *feedEntriesModel) Init() tea.Cmd {
|
||||||
|
m.entries = list.New([]list.Item{feedEntry{}}, list.NewDefaultDelegate(), 100, 50)
|
||||||
|
m.entries.Title = "Feed"
|
||||||
|
return m.fetchEntries
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *feedEntriesModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.KeyMsg:
|
||||||
|
switch msg.String() {
|
||||||
|
case "enter":
|
||||||
|
fnChangeView := func() tea.Msg { return MsgChangeView(ViewPlayer) }
|
||||||
|
|
||||||
|
fnGetSelected := func() tea.Msg {
|
||||||
|
i, ok := m.entries.SelectedItem().(feedEntry)
|
||||||
|
if ok {
|
||||||
|
m.selectedEntry = &i
|
||||||
|
}
|
||||||
|
|
||||||
|
return MsgSelectedItem(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, tea.Sequence(fnChangeView, fnGetSelected)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case MsgFetchedEntries:
|
||||||
|
var items []list.Item
|
||||||
|
for _, e := range msg {
|
||||||
|
items = append(items, e)
|
||||||
|
}
|
||||||
|
m.entries.SetItems(items)
|
||||||
|
case MsgFetchedEntriesError:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmd tea.Cmd
|
||||||
|
m.entries, cmd = m.entries.Update(msg)
|
||||||
|
return m, cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *feedEntriesModel) View() string {
|
||||||
|
return m.entries.View()
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue