M CHANGELOG.md => CHANGELOG.md +3 -3
@@ 6,9 6,9 @@
deleting the database and starting anew
- Multiple performance fixes for update
- Fix navigation keys to use native cview navigation
- - Add Subscription Page
- - Add Tree config theme for subscription page
- - Add Unread key command to config
+ - Add subscription Page
+ - Add tree config theme for subscription page
+ - Add unread key command to config
- Add tree to config
- Add favorite to item model
M db/db.go => db/db.go +57 -6
@@ 397,14 397,27 @@ func (s *Storage) MarkRead(key string) error {
return fmt.Errorf("key was empty, unable to mark read")
}
+ item := s.Items[key]
+ if item.Read {
+ return nil
+ }
+
db, err := openDB(s.Path)
if err != nil {
return fmt.Errorf("unable to open db: %s", err.Error())
}
- item := s.Items[key]
item.Read = true
+ feedKey := item.FeedURL
+ feed, ok := s.Feeds[feedKey]
+ if !ok {
+ return fmt.Errorf("unable to find feed, unable to mark read")
+ }
+ if feed.Unread > 0 {
+ feed.Unread--
+ }
+
itemJSON, err := json.Marshal(item)
if err != nil {
if err := db.Close(); err != nil {
@@ 413,6 426,14 @@ func (s *Storage) MarkRead(key string) error {
return fmt.Errorf("unable to marshal item: %s", err.Error())
}
+ feedJSON, err := json.Marshal(feed)
+ if err != nil {
+ if err := db.Close(); err != nil {
+ return err
+ }
+ return fmt.Errorf("unable to marshal feed item: %s", err.Error())
+ }
+
if err := db.Update(func(tx *bolt.Tx) error {
// Remove from Queue Database
if err := tx.Bucket([]byte(queueTbl)).Delete([]byte(key)); err != nil {
@@ 424,13 445,18 @@ func (s *Storage) MarkRead(key string) error {
return fmt.Errorf("error putting into item bucket: %s", err.Error())
}
+ // increment unread in Feed Database
+ if err := tx.Bucket([]byte(feedTbl)).Put([]byte(feedKey), feedJSON); err != nil {
+ return fmt.Errorf("error putting into feed bucket: %s", err.Error())
+ }
+
return nil
}); err != nil {
if err := db.Close(); err != nil {
return err
}
- return fmt.Errorf("item, and queue: %s", err.Error())
+ return fmt.Errorf("feed, item, and queue: %s", err.Error())
}
if err := db.Close(); err != nil {
@@ 446,7 472,12 @@ func (s *Storage) MarkRead(key string) error {
// add the item from the list.
func (s *Storage) MarkUnread(key string) error {
if key == "" {
- return fmt.Errorf("item key was empty, unable to mark unread")
+ return fmt.Errorf("key was empty, unable to mark unread")
+ }
+
+ item := s.Items[key]
+ if !item.Read {
+ return nil
}
db, err := openDB(s.Path)
@@ 454,9 485,16 @@ func (s *Storage) MarkUnread(key string) error {
return fmt.Errorf("unable to open db: %s", err.Error())
}
- item := s.Items[key]
item.Read = false
+ feedKey := item.FeedURL
+ feed, ok := s.Feeds[feedKey]
+ if !ok {
+ return fmt.Errorf("unable to find feed, unable to mark unread")
+ }
+
+ feed.Unread++
+
queue := &model.QueueItem{
Item: *item,
PlaybackPOS: 0,
@@ 478,8 516,16 @@ func (s *Storage) MarkUnread(key string) error {
return fmt.Errorf("unable to marshal queue item: %s", err.Error())
}
+ feedJSON, err := json.Marshal(feed)
+ if err != nil {
+ if err := db.Close(); err != nil {
+ return err
+ }
+ return fmt.Errorf("unable to marshal feed item: %s", err.Error())
+ }
+
if err := db.Update(func(tx *bolt.Tx) error {
- // Remove from Queue Database
+ // Add to Queue Database
if err := tx.Bucket([]byte(queueTbl)).Put([]byte(key), queueJSON); err != nil {
return fmt.Errorf("error putting into queue bucket: %s", err.Error())
}
@@ 489,13 535,18 @@ func (s *Storage) MarkUnread(key string) error {
return fmt.Errorf("error putting into item bucket: %s", err.Error())
}
+ // increment unread in Feed Database
+ if err := tx.Bucket([]byte(feedTbl)).Put([]byte(feedKey), feedJSON); err != nil {
+ return fmt.Errorf("error putting into feed bucket: %s", err.Error())
+ }
+
return nil
}); err != nil {
if err := db.Close(); err != nil {
return err
}
- return fmt.Errorf("item, and queue: %s", err.Error())
+ return fmt.Errorf("feed, item, and queue: %s", err.Error())
}
if err := db.Close(); err != nil {
M model/feed.go => model/feed.go +3 -0
@@ 35,6 35,7 @@ type Feed struct {
UpdateURL string `json:"updateurl"`
Link string `json:"link"`
Items map[string]bool `json:"items"`
+ Unread int `json:"unread"`
}
// CreateFeed will process the RSS/ATOM Feed into our Feed structure
@@ 49,6 50,7 @@ func CreateFeed(feed *gofeed.Feed, url string) *Feed {
UpdateURL: url,
Link: feed.FeedLink,
Items: make(map[string]bool),
+ Unread: len(feed.Items),
}
if f.Link == "" {
@@ 76,6 78,7 @@ func (f *Feed) FindNewItems() (map[string]*Item, error) {
}
i := CreateItem(item)
+ i.FeedURL = f.UpdateURL
items[i.Link] = i
}
M ui/tree.go => ui/tree.go +37 -6
@@ 72,13 72,17 @@ func newTree(config *config.Config) *tree {
}
}
-func (w *tree) add(item *model.Feed, itemMap model.Items) {
+func (w *tree) add(f *model.Feed, itemMap model.Items) {
i := 0
- items := make([]*tui.TreeNode, len(item.Items))
- for k := range item.Items {
+ items := make([]*tui.TreeNode, len(f.Items))
+ for k := range f.Items {
it := itemMap[k]
- n := tui.NewTreeNode(it.Title)
+ name := it.Title
+ if strings.Contains(it.Type, "audio") {
+ name = fmt.Sprintf("🎧 %s", name)
+ }
+ n := tui.NewTreeNode(name)
n.SetReference(it.Link)
n.SetColor(tcell.GetColor(w.TextColor))
@@ 96,9 100,13 @@ func (w *tree) add(item *model.Feed, itemMap model.Items) {
return w.Dates[a].Sub(w.Dates[b]) < 0
})
- node := tui.NewTreeNode(item.Title)
+ title := f.Title
+ if f.Unread != 0 {
+ title = fmt.Sprintf("%s (*%d)", title, f.Unread)
+ }
+ node := tui.NewTreeNode(title)
node.SetColor(tcell.GetColor(w.TextColor))
- node.SetReference(item.UpdateURL)
+ node.SetReference(f.UpdateURL)
node.SetChildren(items)
node.Collapse()
@@ 133,6 141,29 @@ func (w *tree) markUnread() {
n.SetColor(tcell.GetColor(w.TextColor))
}
+func (w *tree) updateReadCount(feeds model.Feeds, itemMap model.Items) {
+ item, ok := itemMap[w.getKey()]
+ if !ok {
+ return
+ }
+
+ f, ok := feeds[item.FeedURL]
+ if !ok {
+ return
+ }
+
+ for _, c := range w.ChildNodes {
+ if f.UpdateURL == fmt.Sprintf("%v", c.GetReference()) {
+ title := f.Title
+ if f.Unread != 0 {
+ title = fmt.Sprintf("%s (*%d)", title, f.Unread)
+ }
+ c.SetText(title)
+ break
+ }
+ }
+}
+
func (w *tree) refresh(feeds model.Feeds, itemMap model.Items) {
w.Node.ClearChildren()
M ui/ui.go => ui/ui.go +3 -0
@@ 280,6 280,7 @@ func (i *UI) markUnread(event *tcell.EventKey) *tcell.EventKey {
}
i.list.refresh(i.DB.Queue)
i.subTree.markUnread()
+ i.subTree.updateReadCount(i.DB.Feeds, i.DB.Items)
})
}
@@ 333,6 334,8 @@ func (i *UI) markRead(event *tcell.EventKey) *tcell.EventKey {
i.list.removeByKey(key)
i.list.refresh(i.DB.Queue)
i.subTree.markRead()
+ i.subTree.updateReadCount(i.DB.Feeds, i.DB.Items)
+
}
})
return nil