rss2mpv/rss2mpv.go

152 lines
3.2 KiB
Go
Raw Permalink Normal View History

2022-09-05 15:46:20 -04:00
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/mmcdole/gofeed"
)
type rss_info struct {
title string
description string
link string
}
func (i rss_info) Title() string { return i.title }
func (i rss_info) Description() string { return i.description }
func (i rss_info) Link() string { return i.link }
func (i rss_info) FilterValue() string { return i.title }
type model struct {
list list.Model
delegateKeys *delegateKeyMap
}
var (
appStyle = lipgloss.NewStyle().Padding(1, 2)
titleStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#FFFDF5")).
Background(lipgloss.Color("#CC11FF")).
Padding(0, 1)
statusMessageStyle = lipgloss.NewStyle().
Foreground(lipgloss.AdaptiveColor{Light: "#FF44FF", Dark: "#CC11FF"}).
Render
enterKeyBinding = key.NewBinding(
key.WithKeys("enter"),
key.WithHelp("enter", "write playlist"),
)
)
func newModel() model {
var (
delegateKeys = newDelegateKeyMap()
)
// Make initial list of items
items := make([]list.Item, 0)
argsCount := len(os.Args[1:])
if argsCount >= 2 {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
for _, rss := range os.Args[2:] {
fp := gofeed.NewParser()
feed, err := fp.ParseURLWithContext(rss, ctx)
if err != nil {
log.Fatal(err)
os.Exit(1)
}
for _, item := range feed.Items {
items = append(items, rss_info{
title: item.Title,
description: item.Description,
link: item.Link,
})
}
}
} else {
log.Fatal(fmt.Errorf("%v", "usage: rss2mpv playlist-file rss-url..."))
os.Exit(1)
}
// Setup list
delegate := newItemDelegate(delegateKeys)
rssList := list.New(items, delegate, 0, 0)
rssList.Title = "RSS Feed Links"
rssList.Styles.Title = titleStyle
return model{
list: rssList,
delegateKeys: delegateKeys,
}
}
func (m model) Init() tea.Cmd {
return tea.EnterAltScreen
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
switch msg := msg.(type) {
case tea.WindowSizeMsg:
h, v := appStyle.GetFrameSize()
m.list.SetSize(msg.Width-h, msg.Height-v)
case tea.KeyMsg:
// Don't match any of the keys below if we're actively filtering.
if m.list.FilterState() == list.Filtering {
break
}
switch {
case key.Matches(msg, enterKeyBinding):
playlist, err := os.OpenFile(os.Args[1], os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
os.Exit(1)
}
defer playlist.Close()
for _, item := range m.list.Items() {
playlist.WriteString(item.(rss_info).link + "\n")
}
m.list.NewStatusMessage(statusMessageStyle("Wrote to " + os.Args[1] + "!"))
return m, nil
}
}
// This will also call our delegate's update function.
newListModel, cmd := m.list.Update(msg)
m.list = newListModel
cmds = append(cmds, cmd)
return m, tea.Batch(cmds...)
}
func (m model) View() string {
return appStyle.Render(m.list.View())
}
func main() {
if err := tea.NewProgram(newModel()).Start(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
os.Exit(0)
}