diff --git a/API.py b/API.py index a8b19ee..6e75481 100644 --- a/API.py +++ b/API.py @@ -33,3 +33,18 @@ class Fetcher: response = httpx.get(self.URL+"/reader/api/0/stream/contents?ot="+timestamp+"&s=" + category, headers=self.headers) return response.json()["items"] + + def toggleArticleStatus(self, articleId, is_read): + if is_read == 0: + tag_op = 'r' + else: + tag_op = 'a' + try: + response = httpx.post(self.URL+"/reader/api/0/edit-tag", data={"i": articleId, tag_op: "user/-/state/com.google/read"}, + headers=self.headers) + if response.status_code == 200: + return True + else: + return False + except BaseException: + return False diff --git a/App.py b/App.py index 6e3ec3f..b916406 100644 --- a/App.py +++ b/App.py @@ -1,6 +1,5 @@ import urwid import yaml -import asyncio import warnings import subprocess import os @@ -42,27 +41,26 @@ class LeftPane(urwid.ListBox): walker = urwid.SimpleListWalker(items) self.body = walker + def findById(self, id): + idx = 0 + for idx, item in zip(range(len(self.body)), self.body): + if item.attr_map[None][0] == id: + break + return idx + def setArticlesPaneTitle(self, text): tui.rightBox.set_title(text) - def getArticlesFromCategory(self, category, number=0): - tui.fetcher.articlesFromCategory(category, str(number)) - articles = tui.fetcher.articles[category] - return articles - - def getArticlesFromFeed(self, feed): - return tui.fetcher.articlesFromFeed(feed, self.currentCategory) - - async def setCategoryArticles(self, attrMap): + def setCategoryArticles(self, attrMap): itemId = attrMap[0] name = attrMap[1] - tui.articles = tui.cache.getArticlesFromCategory(itemId) + tui.articles = tui.cache.getArticlesFromCategory(itemId, tui.show_read) tui.articleView.fill(tui.articles) self.setArticlesPaneTitle(name) def setFeedArticles(self, attrMap): itemId = attrMap[0] - tui.articles = tui.cache.getArticlesFromFeed(itemId) + tui.articles = tui.cache.getArticlesFromFeed(itemId, tui.show_read) if tui.articles is not None: tui.articleView.fill(tui.articles) self.setArticlesPaneTitle(attrMap[1]) @@ -77,7 +75,7 @@ class LeftPane(urwid.ListBox): focus_widget, idx = self.get_focus() if self.isCategoryView: self.currentCategory = focus_widget.attr_map[None][0] - asyncio.create_task(self.setCategoryArticles(focus_widget.attr_map[None])) + self.setCategoryArticles(focus_widget.attr_map[None]) else: self.setFeedArticles(focus_widget.attr_map[None]) return @@ -89,7 +87,7 @@ class LeftPane(urwid.ListBox): focus_widget, idx = self.get_focus() if self.isCategoryView: self.currentCategory = focus_widget.attr_map[None][0] - asyncio.create_task(self.setCategoryArticles(focus_widget.attr_map[None])) + self.setCategoryArticles(focus_widget.attr_map[None]) else: self.setFeedArticles(focus_widget.attr_map[None]) return @@ -100,7 +98,7 @@ class LeftPane(urwid.ListBox): self.categoryPosition = idx categoryId = focus_widget.attr_map[None][0] categoryName = focus_widget.attr_map[None][1] - feeds = tui.cache.getFeeds(categoryId) + feeds = tui.cache.getFeeds(categoryId, tui.show_read) self.fill(feeds, False) focus_widget, idx = self.get_focus() self.setFeedArticles(focus_widget.attr_map[None]) @@ -113,7 +111,7 @@ class LeftPane(urwid.ListBox): tui.leftBox.set_title("Categories") self.set_focus(self.categoryPosition) focus_widget, idx = self.get_focus() - asyncio.create_task(self.setCategoryArticles(focus_widget.attr_map[None])) + self.setCategoryArticles(focus_widget.attr_map[None]) return return super().keypress(size, key) @@ -130,10 +128,13 @@ class RightPane(urwid.ListBox): self.chunkNumber = 0 def fill(self, articles): + status = "" + if tui.show_read: + status = "R" items = [ urwid.AttrMap( urwid.Columns( - [(2, urwid.Text("")), + [(2, urwid.Text(status)), (16, urwid.Text(article[3])), urwid.Text(article[1])]), article[0], @@ -171,6 +172,33 @@ class RightPane(urwid.ListBox): idx = idx - 1 self.set_focus(idx) return + elif key in ("r"): + if self.isList is True: + feeds = [] + article_widget, article_idx = self.get_focus() + articleId = article_widget.attr_map[None] + tui.cache.toggleArticleStatus(articleId) + item_widget, item_idx = tui.feedView.get_focus() + itemAttrMap = item_widget.attr_map[None] + if tui.feedView.isCategoryView: + tui.feedView.setCategoryArticles(itemAttrMap) + else: + tui.feedView.setFeedArticles(itemAttrMap) + if article_idx > 0: + article_idx -= 1 + try: + self.set_focus(article_idx) + except BaseException: + pass + if tui.feedView.isCategoryView: + feeds = tui.cache.getCategories(tui.show_read) + tui.categories = feeds + else: + feeds = tui.cache.getFeeds(tui.feedView.currentCategory, tui.show_read) + tui.feedView.fill(feeds, tui.feedView.isCategoryView) + new_idx = tui.feedView.findById(itemAttrMap[0]) + tui.feedView.set_focus(new_idx) + return elif key in ("l", "right"): if self.isList is True: self.isList = False @@ -278,10 +306,11 @@ class TUI(urwid.Frame): URL = config["server"]["URL"] token = config["server"]["token"] + self.show_read = 0 self.overlay = None self.fetcher = Fetcher(URL, token) self.cache = Cache(self.fetcher) - self.categories = self.cache.getCategories() + self.categories = self.cache.getCategories(self.show_read) self.leftPaneItems = {} self.activePane = False @@ -301,11 +330,11 @@ class TUI(urwid.Frame): def initialize_panes(self): try: - self.feedView.fill(self.cache.getCategories(), True) + self.feedView.fill(self.cache.getCategories(self.show_read), True) focus_widget, idx = self.feedView.get_focus() item = focus_widget.attr_map[None][0] name = focus_widget.attr_map[None][1] - self.articles = self.cache.getArticlesFromCategory(item) + self.articles = self.cache.getArticlesFromCategory(item, self.show_read) self.articleView.fill(self.articles) self.feedView.setArticlesPaneTitle(name) except BaseException: @@ -334,7 +363,7 @@ class TUI(urwid.Frame): tui.articleView.isList = True elif key == "q": raise urwid.ExitMainLoop() - elif key == "r": + elif key == "f": olb = urwid.ListBox(urwid.SimpleListWalker([urwid.Text("")])) overlay = urwid.Overlay( urwid.LineBox(olb), @@ -346,6 +375,16 @@ class TUI(urwid.Frame): tui.loop.entering_idle() self.body = overlay.bottom_w self.initialize_panes() + elif key == "R": + self.show_read = int(not self.show_read) + focus_widget, idx = self.feedView.get_focus() + if self.feedView.isCategoryView: + self.feedView.setCategoryArticles(focus_widget.attr_map[None]) + else: + self.feedView.setFeedArticles(focus_widget.attr_map[None]) + self.categories = tui.cache.getCategories(self.show_read) + self.feedView.fill(self.categories, True) + return tui = TUI.create() diff --git a/Cache.py b/Cache.py index ddf711b..0d7de56 100644 --- a/Cache.py +++ b/Cache.py @@ -64,30 +64,53 @@ class Cache: cur.execute("""select title,content,url from articles where id = ?""", (id,)) return cur.fetchone() + def toggleArticleStatus(self, id): + inc = 0 + cur = self.conn.cursor() + cur.execute("""update articles set is_read = not is_read where id = ?""", (id,)) + cur.execute("""select origin, category_id, is_read from articles where id = ?""", (id,)) + feed_id, category_id, is_read = cur.fetchone() + if is_read == 0: + inc = 1 + else: + inc = -1 + cur.execute("""update categories set unread_count = unread_count + ? where id = ?""", (inc, category_id,)) + cur.execute("""update feeds set unread_count = unread_count + ? where id = ?""", (inc, feed_id,)) + if self.api.toggleArticleStatus(id, is_read): + self.conn.commit() + else: + self.conn.rollback() + def getArticleLinks(self, id): cur = self.conn.cursor() cur.execute("""select url from links where id = ?""", (id,)) links = functools.reduce(operator.iconcat, cur.fetchall(), []) return links - def getArticlesFromFeed(self, feed_id): + def getArticlesFromFeed(self, feed_id, is_read): cur = self.conn.cursor() - cur.execute("""select * from articles where origin = ? order by timestamp desc""", (feed_id,)) + cur.execute("""select * from articles where origin = ? and is_read = ? order by timestamp desc""", (feed_id, is_read,)) return cur.fetchall() - def getArticlesFromCategory(self, category_id): + def getArticlesFromCategory(self, category_id, is_read): cur = self.conn.cursor() - cur.execute("""select * from articles where category_id = ? order by timestamp desc""", (category_id,)) + cur.execute("""select * from articles where category_id = ? and is_read = ? order by timestamp desc""", (category_id, is_read,)) return cur.fetchall() - def getCategories(self): + def getCategories(self, show_read): + statement = """select * from categories where unread_count != 0 order by timestamp desc""" + if show_read == 1: + statement = """select * from categories order by timestamp desc""" cur = self.conn.cursor() - cur.execute("""select * from categories where unread_count != 0 order by timestamp desc""") + cur.execute(statement) return cur.fetchall() - def getFeeds(self, category_id): + def getFeeds(self, category_id, show_read): + statement = """select * from feeds where category_id = ? and unread_count != 0 order by timestamp desc""" + if show_read == 1: + statement = """select * from feeds where category_id = ? order by timestamp desc""" cur = self.conn.cursor() - cur.execute("""select * from feeds where category_id = ? and unread_count != 0 order by timestamp desc""", (category_id,)) + cur.execute(statement, (category_id,)) return cur.fetchall() def refresh(self): diff --git a/Utils.py b/Utils.py index 5745dc8..0ebc9a2 100644 --- a/Utils.py +++ b/Utils.py @@ -36,4 +36,4 @@ def checkRedditComments(links): def writeLog(text): with open("debug.log", "a") as f: - f.write(str(text)) + f.write(str(text)+"\n")