From 0d873460894376a7493f59784573c66a34a08059 Mon Sep 17 00:00:00 2001 From: eyjhb Date: Sun, 26 Jan 2025 12:56:18 +0100 Subject: [PATCH] something works --- cmd/cmd.go | 146 ++++++++++++++++++++++++++++++++++++++++++++ cmd/feed_entries.go | 8 +++ go.mod | 29 +++++++++ go.sum | 51 ++++++++++++++++ main.go | 49 +++++++++++++++ 5 files changed, 283 insertions(+) create mode 100644 cmd/cmd.go create mode 100644 cmd/feed_entries.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/cmd/cmd.go b/cmd/cmd.go new file mode 100644 index 0000000..fb1e9b3 --- /dev/null +++ b/cmd/cmd.go @@ -0,0 +1,146 @@ +package cmd + +import ( + "context" + "fmt" + "slices" + "time" + + "github.com/blang/mpv" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/simonhege/timeago" + miniflux "miniflux.app/client" +) + +var ( + titleStyle = lipgloss.NewStyle().MarginLeft(2) + itemStyle = lipgloss.NewStyle().PaddingLeft(4) + selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) + paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) + helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) + quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4) +) + +type Test uint + +const ( + ViewListCategories = 10 +) + +type feedEntry struct { + Name string + Feed string + Link string + 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 { + MinifluxClient *miniflux.Client + DefaultCategory string + MpvPath string + + // feedEntriesList []feedEntry + feedEntriesList list.Model + selectedEntry *feedEntry +} + +func (mp *MinifluxPlayer) fetchEntries() tea.Msg { + entriesResult, err := mp.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 (mp *MinifluxPlayer) Init() tea.Cmd { + mp.feedEntriesList = list.New([]list.Item{feedEntry{}}, list.NewDefaultDelegate(), 100, 50) + mp.feedEntriesList.Title = "Feed" + return mp.fetchEntries +} + +func (mp *MinifluxPlayer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + mp.feedEntriesList.SetSize(msg.Width, msg.Height) + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q": + return mp, tea.Quit + case "enter": + i, ok := mp.feedEntriesList.SelectedItem().(feedEntry) + if ok { + mp.selectedEntry = &i + } + return mp, tea.Quit + } + break + + case MsgFetchedEntries: + var items []list.Item + for _, e := range msg { + items = append(items, e) + } + mp.feedEntriesList.SetItems(items) + case MsgFetchedEntriesError: + break + } + + var cmd tea.Cmd + mp.feedEntriesList, cmd = mp.feedEntriesList.Update(msg) + return mp, cmd +} + +func (mp *MinifluxPlayer) View() string { + if mp.selectedEntry != nil { + ipcc := mpv.NewIPCClient("/tmp/mpvsocket") // Lowlevel client + 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() +} + +func (mp *MinifluxPlayer) FetchCategories(ctx context.Context) ([]*miniflux.Category, error) { + return mp.MinifluxClient.Categories() +} diff --git a/cmd/feed_entries.go b/cmd/feed_entries.go new file mode 100644 index 0000000..c4623d0 --- /dev/null +++ b/cmd/feed_entries.go @@ -0,0 +1,8 @@ +// package cmd + +// import "github.com/charmbracelet/bubbles/list" + +// type feedEntriesModel struct { +// entries list.Model +// selectedEntry +// } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..67f0ec8 --- /dev/null +++ b/go.mod @@ -0,0 +1,29 @@ +module git.fricloud.dk/eyjhb/minifluxmpv + +go 1.23.4 + +require ( + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/blang/mpv v0.0.0-20160810175505-d56d7352e068 // indirect + github.com/charmbracelet/bubbles v0.20.0 // indirect + github.com/charmbracelet/bubbletea v1.2.4 // indirect + github.com/charmbracelet/lipgloss v1.0.0 // indirect + github.com/charmbracelet/x/ansi v0.4.5 // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sahilm/fuzzy v0.1.1 // indirect + github.com/simonhege/timeago v1.0.0-rc5 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/text v0.11.0 // indirect + miniflux.app v1.0.46 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4056c75 --- /dev/null +++ b/go.sum @@ -0,0 +1,51 @@ +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/blang/mpv v0.0.0-20160810175505-d56d7352e068 h1:P3ukpA1t7dgNIfe21LpB+zIBDQ1Dik9K1DMPdO/TcUA= +github.com/blang/mpv v0.0.0-20160810175505-d56d7352e068/go.mod h1:E3TTEJpVApQMkhVk3Lr0sAmcbcclY3pGgPbRsy+rdlk= +github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= +github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= +github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE= +github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM= +github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= +github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= +github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= +github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= +github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/simonhege/timeago v1.0.0-rc5 h1:Fx6M3eLoSdZDRX1fYf0ZKEHK6dlmvfLY+zHRwsnOGNU= +github.com/simonhege/timeago v1.0.0-rc5/go.mod h1:PfcxupQPucgCUBC1uH6OI1vHaKuhDvXN9eo54vseEVc= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +miniflux.app v1.0.46 h1:2/xrbXiEoQlj/bAZ8MT+fPN1+gmYDYuXVCOhvSskns4= +miniflux.app v1.0.46/go.mod h1:YtEJIO1vMCvZgyzDbds7II0W/H7sGpo3auFCQscuMrE= diff --git a/main.go b/main.go new file mode 100644 index 0000000..882f51b --- /dev/null +++ b/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + + "git.fricloud.dk/eyjhb/minifluxmpv/cmd" + tea "github.com/charmbracelet/bubbletea" + miniflux "miniflux.app/client" +) + +func main() { + + // ipcc := mpv.NewIPCClient("/tmp/mpvsocket") // Lowlevel client + // c := mpv.NewClient(ipcc) // Highlevel client, can also use RPCClient + + // c.Loadfile("https://www.youtube.com/watch?v=9dncyekT9d4", mpv.LoadFileModeReplace) + // // c.SetPause(true) + // // c.Seek(600, mpv.SeekModeAbsolute) + // // c.SetFullscreen(true) + // c.SetPause(false) + // // fmt.Println(c.Idle()) + // // time.Sleep(10 * time.Second) + // // fmt.Println(c.Idle()) + // for { + // pos, _ := c.Position() + // dur, _ := c.Duration() + // fmt.Printf("%f/%f\n", pos, dur) + + // time.Sleep(1 * time.Second) + + // } + // return + + // init miniflux + client := miniflux.New("https://miniflux.fricloud.dk/v1/", "tFkVpjmSvePfGX6SBtcE61HSziALNAIeZ0eq5mkQOso=") + + // init miniflux player + m := cmd.MinifluxPlayer{ + MinifluxClient: client, + DefaultCategory: "", + MpvPath: "mpv", + } + + // run tea program + if _, err := tea.NewProgram(&m, tea.WithAltScreen()).Run(); err != nil { + fmt.Println(err) + + } +}