Skip to content

Commit

Permalink
Fixes #18, Fixes #11, Fixes #10
Browse files Browse the repository at this point in the history
- Background fetch
- parallell feed update
- search functionality
- ask to quit
  • Loading branch information
Lallassu committed Oct 28, 2020
1 parent 00bfc5c commit 6e47358
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 43 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ run: build
release:
@mkdir release
@mkdir dist
@CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ GOARCH=amd64 GOOS=linux CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static -s -w -X $(shell go list)/internal.Version=${VERSION}" -o ./release/gorss_linux ./cmd/gorss/...
@go build -ldflags "-s -w -X $(shell go list)/internal.Version=${VERSION}" -o ./release/gorss_osx ./cmd/gorss/...
@GOARCH=amd64 GOOS=linux go build -ldflags "-s -w -X $(shell go list)/internal.Version=${VERSION}" -o ./release/gorss_linux ./cmd/gorss/...
@GOARCH=amd64 GOOS=darwin go build -ldflags "-s -w -X $(shell go list)/internal.Version=${VERSION}" -o ./release/gorss_osx ./cmd/gorss/...
@cp gorss.conf dist/
@cp themes/default.theme dist/
@cp -r themes dist/
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ to use with the argument `-db` to the binary.
- Mark articles as read
- Mark all as read/unread
- Undo last read (mark it as unread)
- Search titles

## Configuration Example (Default config)
It's possible to specify configuration file as a flag, default is `gorss.conf`.
Expand Down Expand Up @@ -110,6 +111,7 @@ and name fields. (See the example below for supported options).
"keySwitchWindows": "Tab",
"keyQuit": "Esc",
"keyUndoLastRead": "u",
"keySearchPromt": "/",
"customCommands": [
{
"key": "j",
Expand Down
2 changes: 2 additions & 0 deletions gorss.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"voxel",
"gorss",
"doit",
"devel",
"lallassu"
],
"OPMLFile": "../example_ompl.xml",
Expand Down Expand Up @@ -43,6 +44,7 @@
"keySwitchWindows": "Tab",
"keyQuit": "Esc",
"keyUndoLastRead": "u",
"keySearchPromt": "/",
"customCommands": [
{
"key": "j",
Expand Down
1 change: 1 addition & 0 deletions internal/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Config struct {
KeySwitchWindows string `json:"keySwitchWindows"`
KeyQuit string `json:"keyQuit"`
KeyUndoLastRead string `json:"keyUndoLastRead"`
KeySearchPromt string `json:"keySearchPromt"`
CustomCommands []Command `json:"customCommands"`
}

Expand Down
64 changes: 43 additions & 21 deletions internal/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@ import (

// Controller handles the logic and keep everything together
type Controller struct {
rss *RSS
db *DB
win *Window
activeFeed string
linksToOpen []string
quit chan int
articles []Article
aLock sync.Mutex
conf Config
theme Theme
isUpdated bool
prevArticle *Article
undoArticle *Article
lastUpdate time.Time
rss *RSS
db *DB
win *Window
activeFeed string
linksToOpen []string
quit chan int
articles []Article
aLock sync.Mutex
conf Config
theme Theme
isUpdated bool
prevArticle *Article
undoArticle *Article
lastUpdate time.Time
searchResults int
}

// Init initiates the controller with database handles etc.
Expand Down Expand Up @@ -102,7 +103,7 @@ func (c *Controller) GetConfigKeys() map[string]string {
// UpdateLoop updates the feeds and windows
func (c *Controller) UpdateLoop() {
c.GetArticlesFromDB()
c.UpdateFeeds() // Start by updating feeds.
go c.UpdateFeeds() // Start by updating feeds.
c.ShowFeeds()
go func() {
updateWin := time.NewTicker(time.Duration(30) * time.Second)
Expand All @@ -116,9 +117,11 @@ func (c *Controller) UpdateLoop() {
}
c.ShowFeeds()
case <-updateFeeds.C:
c.UpdateFeeds()
c.db.CleanupDB()
c.win.StatusUpdate()
go func() {
c.UpdateFeeds()
c.db.CleanupDB()
c.win.StatusUpdate()
}()
case <-c.quit:
c.Quit()
return
Expand Down Expand Up @@ -242,6 +245,7 @@ func (c *Controller) ShowFeeds() {
}
}
c.win.AddToFeeds(fmt.Sprintf("[%s]Highlight", c.theme.Highlights), "", hc, total, &Article{feed: "highlight"})
c.win.AddToFeeds(fmt.Sprintf("[%s]Search Results", c.theme.Highlights), "", c.searchResults, c.searchResults, &Article{feed: "result"})

type feed struct {
count int
Expand Down Expand Up @@ -295,6 +299,8 @@ func (c *Controller) ShowArticles(feed string) {

if feed == "" {
feed = "highlight"
} else if feed == "result" {
c.searchResults = 0
}

c.activeFeed = feed
Expand All @@ -304,6 +310,19 @@ func (c *Controller) ShowArticles(feed string) {
if !a.highlight {
continue
}
} else if feed == "result" {
match := false
for _, f := range strings.Fields(c.win.currSearch) {
// Insensitive search
if strings.Contains(strings.ToLower(a.title), strings.ToLower(f)) {
match = true
c.searchResults++
break
}
}
if !match {
continue
}
} else if feed == "allarticles" {
// pass - take all articles
} else if feed == "unread" {
Expand Down Expand Up @@ -334,6 +353,7 @@ func (c *Controller) ShowArticles(feed string) {
c.isUpdated = false

c.win.articles.ScrollToBeginning()
c.ShowFeeds()
}

// GetArticleForSelection returns the article instance for the selected article
Expand Down Expand Up @@ -409,7 +429,6 @@ func (c *Controller) SelectArticle(row, col int) {
c.db.MarkRead(c.prevArticle)
c.prevArticle.read = true
}

}

// Input handles keystrokes
Expand All @@ -420,8 +439,11 @@ func (c *Controller) Input(e *tcell.EventKey) *tcell.EventKey {
}

switch keyName {
case c.conf.KeySearchPromt:
c.win.Search()

case c.conf.KeyQuit:
c.quit <- 1
c.win.AskQuit()

case c.conf.KeySwitchWindows:
c.win.SwitchFocus()
Expand Down Expand Up @@ -452,7 +474,7 @@ func (c *Controller) Input(e *tcell.EventKey) *tcell.EventKey {
// Remove the linkmarker icon
r, _ := c.win.articles.GetSelection()
cell := c.win.articles.GetCell(r, 1)
cell.SetText(fmt.Sprintf("%s", c.theme.UnreadMarker))
cell.SetText(c.theme.UnreadMarker)
}
if c.activeFeed != "unread" {
c.ShowArticles(c.activeFeed)
Expand Down
37 changes: 25 additions & 12 deletions internal/rss.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"log"
"net/http"
"sync"

"github.com/gilliek/go-opml/opml"
"github.com/mmcdole/gofeed"
Expand Down Expand Up @@ -69,20 +70,32 @@ func (r *RSS) Update() {
displayName string
feed *gofeed.Feed
}{}

var mu sync.Mutex

var wg sync.WaitGroup

for _, f := range r.c.conf.Feeds {
feed, err := r.FetchURL(fp, f.URL)
if err != nil {
log.Printf("error fetching url: %s, err: %v", f.URL, err)
continue
}
r.feeds = append(r.feeds, struct {
displayName string
feed *gofeed.Feed
}{
f.Name,
feed,
})
wg.Add(1)
go func(f Feed) {
feed, err := r.FetchURL(fp, f.URL)
if err != nil {
log.Printf("error fetching url: %s, err: %v", f.URL, err)
} else {
mu.Lock()
r.feeds = append(r.feeds, struct {
displayName string
feed *gofeed.Feed
}{
f.Name,
feed,
})
mu.Unlock()
}
wg.Done()
}(f)
}
wg.Wait()
}

// FetchURL fetches the feed URL and also fakes the user-agent to be able
Expand Down
1 change: 1 addition & 0 deletions internal/version.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
package internal

// Version is version of the application
var Version string
115 changes: 107 additions & 8 deletions internal/window.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type Window struct {
showHelp bool
nArticles int
nFeeds int
askQuit bool
currSearch string
}

const (
Expand Down Expand Up @@ -223,8 +225,87 @@ func (w *Window) UpdateStatusTicker() {
}()
}

// Search asks the user to input search query
func (w *Window) Search() {
w.askQuit = true
w.flexStatus.RemoveItem(w.status)
w.currSearch = ""

inputField := tview.NewInputField().
SetLabel("find: ").
SetFieldWidth(20).
SetFieldBackgroundColor(tcell.ColorBlack)

capt := func(e *tcell.EventKey) *tcell.EventKey {
keyName := string(e.Name())
if strings.Contains(keyName, "Rune") {
keyName = string(e.Rune())
}

if strings.EqualFold(keyName, "esc") {
w.flexStatus.RemoveItem(inputField)
w.flexStatus.AddItem(w.status, 1, 1, false)
w.app.SetInputCapture(w.c.Input)
w.app.SetFocus(w.articles)
}

if strings.EqualFold(keyName, "enter") {
w.flexStatus.RemoveItem(inputField)
w.flexStatus.AddItem(w.status, 1, 1, false)
w.app.SetInputCapture(w.c.Input)
w.app.SetFocus(w.articles)

w.feeds.Select(2, 0)
w.articles.Select(0, 3)

} else {
w.currSearch += keyName
}

return e
}
w.flexStatus.AddItem(inputField, 1, 0, false)
w.app.SetFocus(inputField)
w.app.SetInputCapture(capt)
}

// AskQuit asks the user to quit or not.
func (w *Window) AskQuit() {
w.askQuit = true
w.flexStatus.RemoveItem(w.status)

inputField := tview.NewInputField().
SetLabel("Quit [Y/n]? ").
SetFieldWidth(5).
SetFieldBackgroundColor(tcell.ColorBlack)

x := func(e *tcell.EventKey) *tcell.EventKey {
keyName := string(e.Name())
if strings.Contains(keyName, "Rune") {
keyName = string(e.Rune())
}

if strings.EqualFold(keyName, "y") || strings.EqualFold(keyName, "enter") {
w.c.quit <- 1
}

w.flexStatus.RemoveItem(inputField)
w.flexStatus.AddItem(w.status, 1, 1, false)
w.app.SetInputCapture(w.c.Input)
w.app.SetFocus(w.articles)

return e
}
w.flexStatus.AddItem(inputField, 1, 0, false)
w.app.SetFocus(inputField)
w.app.SetInputCapture(x)
}

// StatusUpdate updates the status window with updated information
func (w *Window) StatusUpdate() {
if w.askQuit {
return
}
// Update time
c := w.status.GetCell(0, 0)
c.SetText(
Expand Down Expand Up @@ -557,12 +638,12 @@ func (w *Window) AddToArticles(a *Article, markedWeb bool) {
tc.SetReference(a)
w.articles.SetCell(w.nArticles, 3, tc)

if a.highlight {
if w.c.activeFeed == "result" {
hTitle := ""
fields := strings.Fields(a.title)
for _, f := range fields {
found := false
for _, h := range w.c.conf.Highlights {
for _, h := range strings.Fields(w.currSearch) {
if strings.Contains(strings.ToLower(f), strings.ToLower(h)) {
found = true
}
Expand All @@ -575,8 +656,26 @@ func (w *Window) AddToArticles(a *Article, markedWeb bool) {
}
tc.SetText(hTitle)
} else {
tc.SetText(a.title)

if a.highlight {
hTitle := ""
fields := strings.Fields(a.title)
for _, f := range fields {
found := false
for _, h := range w.c.conf.Highlights {
if strings.Contains(strings.ToLower(f), strings.ToLower(h)) {
found = true
}
}
if found {
hTitle += fmt.Sprintf("[%s]"+f+" [%s]", w.c.theme.Highlights, w.c.theme.Title)
} else {
hTitle += f + " "
}
}
tc.SetText(hTitle)
} else {
tc.SetText(a.title)
}
}

str := time.Since(a.published).Round(time.Minute).String()
Expand Down Expand Up @@ -637,10 +736,10 @@ func (w *Window) AddPreview(a *Article) {

// GetTime returns the timestring formatted as (%h%m < 24 hours < %d)
func GetTime(ts string) string {
d_rex := regexp.MustCompile(`(\d+)h`)
d_res := d_rex.FindStringSubmatch(ts)
if len(d_res) > 0 {
if i, err := strconv.Atoi(d_res[1]); err == nil {
dDrex := regexp.MustCompile(`(\d+)h`)
dRes := dDrex.FindStringSubmatch(ts)
if len(dRes) > 0 {
if i, err := strconv.Atoi(dRes[1]); err == nil {
if i > 23 {
days := i / 24
return strconv.Itoa(days) + "d"
Expand Down

0 comments on commit 6e47358

Please sign in to comment.