You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

348 lines
13 KiB

import urwid
import yaml
import asyncio
import warnings
import subprocess
import os
from concurrent.futures import ThreadPoolExecutor
from API import Fetcher
from DB import DB
from Render import Article
import Utils
warnings.filterwarnings("ignore")
class LeftPane(urwid.ListBox):
def __init__(self, categories):
super().__init__(self)
items = [urwid.AttrMap(urwid.Columns([
(16, urwid.Text(category["date"])), urwid.Text(category["name"]), (5, urwid.Text(str(category["count"])))]),
(category["id"], category["name"], category["count"]), "reveal focus") for category in categories]
walker = urwid.SimpleListWalker(items)
self.body = walker
self.categoryPosition = 0
self.isCategoryView = True
self.currentCategory = ""
focus_widget, idx = self.get_focus()
if self.isCategoryView:
self.currentCategory = focus_widget.attr_map[None][0]
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):
itemId = attrMap[0]
number = attrMap[2]
name = attrMap[1]
await tui.fetcher.articlesFromCategoryAsync(itemId, str(number))
focus_widget, idx = self.get_focus()
currentCategory = focus_widget.attr_map[None][0]
if itemId == currentCategory:
tui.articles = tui.fetcher.articles[currentCategory]
tui.articleView.fill(tui.articles)
self.setArticlesPaneTitle(name)
def setFeedArticles(self, attrMap):
itemId = attrMap[0]
tui.articles = tui.fetcher.articlesFromFeed(itemId, self.currentCategory)
if tui.articles is not None:
tui.articleView.fill(tui.articles)
self.setArticlesPaneTitle(attrMap[1])
def keypress(self, size, key):
if key in ("j", "down"):
item_size = len(self.body)
focus_widget, idx = self.get_focus()
if idx < item_size - 1:
idx = idx + 1
self.set_focus(idx)
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]))
else:
self.setFeedArticles(focus_widget.attr_map[None])
return
elif key in ("k", "up"):
focus_widget, idx = self.get_focus()
if idx > 0:
idx = idx - 1
self.set_focus(idx)
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]))
else:
self.setFeedArticles(focus_widget.attr_map[None])
return
elif key in ("l", "right"):
if self.isCategoryView and tui.fetcher.checkCategory(self.currentCategory):
self.isCategoryView = False
focus_widget, idx = self.get_focus()
self.categoryPosition = idx
categoryId = focus_widget.attr_map[None][0]
categoryName = focus_widget.attr_map[None][1]
feeds = tui.fetcher.feedsFromCategory(categoryId)
feedItems = [urwid.AttrMap(urwid.Columns([(16, urwid.Text(tui.fetcher.unreadCounts[feed["id"]][2])),
urwid.Text(feed["title"]),
(5, urwid.Text(str(tui.fetcher.unreadCounts[feed["id"]][0])))]),
(feed["id"], feed["title"]), "reveal focus") for feed in feeds]
walker = urwid.SimpleListWalker(feedItems)
self.body = walker
focus_widget, idx = self.get_focus()
self.setFeedArticles(focus_widget.attr_map[None])
tui.leftBox.set_title(categoryName)
return
elif key in ("h", "left"):
if not self.isCategoryView:
self.isCategoryView = True
items = [
urwid.AttrMap(
urwid.Columns(
[(16, urwid.Text(category["date"])),
urwid.Text(category["name"]),
(5, urwid.Text(str(category["count"])))]),
(category["id"],
category["name"],
category["count"]),
"reveal focus") for category in tui.fetcher.categories]
walker = urwid.SimpleFocusListWalker(items)
self.body = walker
tui.leftBox.set_title("Categories")
self.set_focus(self.categoryPosition)
focus_widget, idx = self.get_focus()
tui.articles = self.getArticlesFromCategory(focus_widget.attr_map[None][0])
tui.articleView.fill(tui.articles)
self.setArticlesPaneTitle(self.currentCategory[13:])
return
return super().keypress(size, key)
class RightPane(urwid.ListBox):
def __init__(self, items):
super().__init__(self)
walker = urwid.SimpleListWalker([])
self.body = walker
self.isList = True
self.articlePosition = 0
self.article = None
self.chunkNumber = 0
def fill(self, articles):
items = [
urwid.AttrMap(
urwid.Columns(
[(2, urwid.Text("")),
(16, urwid.Text(Utils.timestampToDate(article["timestampUsec"]))),
urwid.Text(article["title"])]),
article["id"],
"reveal focus") for article in articles]
walker = urwid.SimpleListWalker(items)
self.body = walker
def getArticle(self, articleId):
article = [item for item in tui.fetcher.articles[tui.feedView.currentCategory] if item["id"] == articleId][0]
return article
def setArticleTitle(self):
tui.rightBox.set_title(self.article.title + " (" + str(self.article.currentPageNumber) + "/" +
str(self.article.numberOfPages) + ")")
def keypress(self, size, key): # noqa
if key in ("j", "down"):
if not self.isList:
walker = urwid.SimpleListWalker([urwid.Text(self.article.scrollDown())])
self.body = walker
self.setArticleTitle()
item_size = len(self.body)
focus_widget, idx = self.get_focus()
if idx < item_size - 1:
idx = idx + 1
self.set_focus(idx)
return
elif key in ("k", "up"):
if not self.isList:
walker = urwid.SimpleListWalker([urwid.Text(self.article.scrollUp())])
self.body = walker
self.setArticleTitle()
focus_widget, idx = self.get_focus()
if idx > 0:
idx = idx - 1
self.set_focus(idx)
return
elif key in ("l", "right"):
if self.isList is True:
self.isList = False
self.chunkNumber = 0
focus_widget, idx = self.get_focus()
self.articlePosition = idx
articleId = focus_widget.attr_map[None]
self.article = Article(self.getArticle(articleId))
walker = urwid.SimpleListWalker([urwid.Text(self.article.firstPage)])
self.body = walker
self.setArticleTitle()
return
elif key in ("h", "left"):
if self.isList is False:
self.isList = True
self.fill(tui.articles)
focusFeed, idx = tui.feedView.get_focus()
tui.rightBox.set_title(focusFeed.attr_map[None][1])
self.set_focus(self.articlePosition)
return
elif key == "m":
if self.isList is False and len(self.article.links) > 0:
top = Links(self.article.links)
tui.createOverlay(urwid.LineBox(top), len(self.article.links)+2)
return
elif key == "v":
if self.isList is False:
subprocess.Popen(['firefox', '-new-tab', self.article.url])
return
return super().keypress(size, key)
class Links(urwid.ListBox):
def __init__(self, links):
super().__init__(self)
items = [urwid.AttrMap(urwid.Columns([urwid.Text(link)]), (link), "reveal focus") for link in links]
walker = urwid.SimpleFocusListWalker(items)
self.body = walker
def parseLink(self, link):
ext = link.split(".")[-1]
if Utils.checkPic(ext.lower()):
os.system('nohup feh ' + link + ' </dev/null >/dev/null 2>&1 &')
elif Utils.checkStreamingVideo(link):
tui.destroyOverlay()
os.system(
'nohup mpv --ytdl-format="bestvideo[height<=720]+bestaudio/best[height<=720]" "' +
link +
'" </dev/null >/dev/null 2>&1 &')
else:
subprocess.Popen(['firefox', '-new-tab', link])
def keypress(self, size, key):
if key in ("j", "down"):
focus_widget, idx = self.get_focus()
item_size = len(self.body)
if idx < item_size - 1:
idx = idx + 1
self.set_focus(idx)
return
elif key in ("k", "up"):
focus_widget, idx = self.get_focus()
if idx > 0:
idx = idx - 1
self.set_focus(idx)
return
elif key in ("l", "right"):
focus_widget, idx = self.get_focus()
link = focus_widget.attr_map[None]
self.parseLink(link)
elif key == "q":
tui.destroyOverlay()
return
class TUI(urwid.Frame):
@classmethod
def create(cls):
tui = cls()
palette = [("linebox", "dark blue", "black"), ("text", "dark cyan", "dark cyan"),
('header', 'white', 'black'), ('reveal focus', 'black', 'dark cyan', 'standout')]
loop = urwid.MainLoop(
tui,
palette,
event_loop=urwid.AsyncioEventLoop(),
unhandled_input=tui.unhandled_input,
)
tui.loop = loop
return tui
def __init__(self):
with open(os.path.expanduser('~') + '/.config/inomnibus/config.yml', 'r') as file:
config = yaml.safe_load(file)
URL = config["server"]["URL"]
token = config["server"]["token"]
self.overlay = None
self.fetcher = Fetcher(URL, token)
self.DB = DB(self.fetcher)
self.DB.refresh()
self.leftPaneItems = {}
self.activePane = False
self.executor = ThreadPoolExecutor(max_workers=1)
self.loop = None
self.feedView = LeftPane(self.fetcher.categories)
self.articleView = RightPane([])
self.leftBox = urwid.LineBox(self.feedView, title="Categories")
self.rightBox = urwid.LineBox(self.articleView, title="Articles")
self.views = urwid.Columns(
[(56, self.leftBox), self.rightBox])
self.container = urwid.Pile([self.views])
self.body = self.container
self.articles = []
super().__init__(self.body)
def run(self):
focus_widget, idx = self.feedView.get_focus()
item = focus_widget.attr_map[None][0]
name = focus_widget.attr_map[None][1]
self.fetcher.articlesFromCategory(item, str(focus_widget.attr_map[None][2]))
self.articles = tui.fetcher.articles[item]
self.articleView.fill(self.articles)
self.feedView.setArticlesPaneTitle(name)
self.loop.run()
self.executor.shutdown(wait=False)
def createOverlay(self, element, h):
self.overlay = urwid.Overlay(
element,
self.body, align="center", width=("relative", 50), valign="middle", height=h)
self.body = self.overlay
def destroyOverlay(self):
self.body = self.overlay.bottom_w
del(self.overlay)
def unhandled_input(self, key):
if key == "tab":
self.activePane = not self.activePane
self.views.set_focus(int(self.activePane))
if self.activePane:
tui.articleView.isList = True
elif key == "q":
raise urwid.ExitMainLoop()
elif key == "r":
olb = urwid.ListBox(urwid.SimpleListWalker([urwid.Text("")]))
overlay = urwid.Overlay(
urwid.LineBox(olb),
self.body, align="center", width=("relative", 50), valign="middle", height=3)
self.body = overlay
articles = tui.fetcher.fetch()
for text in articles:
olb.body = urwid.SimpleListWalker([urwid.Text(text)])
tui.loop.entering_idle()
self.body = overlay.bottom_w
tui = TUI.create()
tui.run()