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.

480 lines
18 KiB

import urwid
import yaml
import warnings
import subprocess
import os
from concurrent.futures import ThreadPoolExecutor
from API import Fetcher
from Cache import Cache
from Render import Render
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[4])), urwid.Text(category[1]), (5, urwid.Text(str(category[2])))]),
(category[0], category[1], category[2]), "reveal focus") for category in categories]
walker = urwid.SimpleListWalker(items)
self.body = walker
self.categoryPosition = 0
self.isCategoryView = True
self.currentCategory = ""
def processAttrMap(self, attrMap):
res = attrMap[None]
if res == "favorite":
return attrMap["attrs"]
else:
return res
def fill(self, items, is_category_view):
def getAttrs(item):
if is_category_view is True:
return (item[0], item[1], item[2])
else:
return (item[0], item[1])
if is_category_view is True:
items = [
urwid.AttrMap(
urwid.Columns(
[(16, urwid.Text(items[0][4])),
urwid.Text(items[0][1]),
(5, urwid.Text(str(items[0][2])))]),
{None: "favorite", "attrs": getAttrs(items[0])},
"reveal focus"),
*
[urwid.AttrMap(
urwid.Columns([(16, urwid.Text(item[4])),
urwid.Text(item[1]),
(5, urwid.Text(str(item[2])))]),
getAttrs(item),
"reveal focus") for item in items[1:]]]
else:
items = [urwid.AttrMap(urwid.Columns([
(16, urwid.Text(item[4])), urwid.Text(item[1]), (5, urwid.Text(str(item[2])))]),
getAttrs(item), "reveal focus") for item in items]
walker = urwid.SimpleListWalker(items)
self.body = walker
focus_widget, idx = self.get_focus()
if self.isCategoryView:
try:
self.currentCategory = focus_widget.attr_map[None][0]
except BaseException:
self.currentCategory = None
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 setCategoryArticles(self, attrMap):
itemId = attrMap[0]
name = attrMap[1]
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.show_read)
if tui.articles is not None:
tui.articleView.fill(tui.articles)
self.setArticlesPaneTitle(attrMap[1])
def keypress(self, size, key): # noqa
if key in ("j", "down"):
item_size = len(self.body)
try:
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 = self.processAttrMap(focus_widget.attr_map)[0]
self.setCategoryArticles(self.processAttrMap(focus_widget.attr_map))
else:
self.setFeedArticles(focus_widget.attr_map[None])
except BaseException:
pass
return
elif key in ("k", "up"):
try:
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 = self.processAttrMap(focus_widget.attr_map)[0]
self.setCategoryArticles(self.processAttrMap(focus_widget.attr_map))
else:
self.setFeedArticles(focus_widget.attr_map[None])
except BaseException:
pass
return
elif key in ("l", "right"):
try:
if self.isCategoryView:
self.isCategoryView = False
focus_widget, idx = self.get_focus()
self.categoryPosition = idx
categoryId = self.processAttrMap(focus_widget.attr_map)[0]
categoryName = self.processAttrMap(focus_widget.attr_map)[1]
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])
tui.leftBox.set_title(categoryName)
except BaseException:
pass
return
elif key in ("h", "left"):
if not self.isCategoryView:
self.isCategoryView = True
self.fill(tui.categories, True)
tui.leftBox.set_title("Categories")
self.set_focus(self.categoryPosition)
focus_widget, idx = self.get_focus()
self.setCategoryArticles(self.processAttrMap(focus_widget.attr_map))
return
elif key in ("r"):
try:
focus_widget, idx = self.get_focus()
del self.body[idx]
if idx > 0:
idx -= 1
self.set_focus(idx)
tui.cache.markStreamAsRead(self.processAttrMap(focus_widget.attr_map)[0])
tui.categories = tui.cache.getCategories(tui.show_read)
focus_widget, idx = self.get_focus()
if self.isCategoryView:
self.currentCategory = self.processAttrMap(focus_widget.attr_map)[0]
self.setCategoryArticles(self.processAttrMap(focus_widget.attr_map))
else:
self.setFeedArticles(focus_widget.attr_map[None])
except BaseException as e:
Utils.writeLog(e)
pass
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):
status = ""
if tui.show_read:
status = "R"
items = [
urwid.AttrMap(
urwid.Columns(
[(2, urwid.Text(status)),
(16, urwid.Text(article[3])),
urwid.Text(article[1])]),
article[0],
"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)
try:
focus_widget, idx = self.get_focus()
if idx < item_size - 1:
idx = idx + 1
self.set_focus(idx)
except BaseException:
pass
return
elif key in ("k", "up"):
if not self.isList:
walker = urwid.SimpleListWalker([urwid.Text(self.article.scrollUp())])
self.body = walker
self.setArticleTitle()
try:
focus_widget, idx = self.get_focus()
if idx > 0:
idx = idx - 1
self.set_focus(idx)
except BaseException:
pass
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
tui.categories = tui.cache.getCategories(tui.show_read)
if tui.feedView.isCategoryView:
feeds = tui.categories
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])
try:
tui.feedView.set_focus(new_idx)
focus_widget, idx = tui.feedView.get_focus()
if tui.feedView.isCategoryView:
tui.feedView.currentCategory = tui.feedView.processAttrMap(focus_widget.attr_map)[0]
tui.feedView.setCategoryArticles(tui.feedView.processAttrMap(focus_widget.attr_map))
else:
tui.feedView.setFeedArticles(focus_widget.attr_map[None])
try:
self.set_focus(article_idx)
except BaseException:
pass
except BaseException:
pass
return
elif key in ("l", "right"):
if self.isList is True:
self.isList = False
self.chunkNumber = 0
try:
focus_widget, idx = self.get_focus()
self.articlePosition = idx
articleId = focus_widget.attr_map[None]
Utils.writeLog(tui.feedView.currentCategory)
self.article = Render(*tui.cache.getArticle(articleId, tui.feedView.currentCategory == "Favorites"),
tui.cache.getArticleLinks(articleId))
walker = urwid.SimpleListWalker([urwid.Text(self.article.firstPage)])
self.body = walker
self.setArticleTitle()
except BaseException:
pass
return
elif key in ("c"):
if self.isList is False:
self.article.loadComments()
walker = urwid.SimpleListWalker([urwid.Text(self.article.firstPage)])
self.body = walker
return
elif key in ("h", "left"):
try:
if self.isList is False:
self.isList = True
self.fill(tui.articles)
focusFeed, idx = tui.feedView.get_focus()
tui.rightBox.set_title(tui.feedView.processAttrMap(focusFeed.attr_map)[1])
self.set_focus(self.articlePosition)
except BaseException:
pass
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 in ("q", "esc"):
tui.destroyOverlay()
return
class TUI(urwid.Frame):
@classmethod
def create(cls):
tui = cls()
palette = [("linebox", "bold", "dark cyan", "standout"), ("text", "dark cyan", "dark cyan"),
("favorite", "dark green", "black"),
('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.show_read = 0
self.overlay = None
self.fetcher = Fetcher(URL, token)
self.cache = Cache(self.fetcher)
self.categories = self.cache.getCategories(self.show_read)
self.leftPaneItems = {}
self.activePane = False
self.executor = ThreadPoolExecutor(max_workers=1)
self.loop = None
self.feedView = LeftPane([])
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 initialize_panes(self):
try:
self.feedView.fill(self.cache.getCategories(self.show_read), True)
try:
self.feedView.set_focus(1)
except BaseException:
pass
focus_widget, idx = self.feedView.get_focus()
item = self.feedView.processAttrMap(focus_widget.attr_map)[0]
name = self.feedView.processAttrMap(focus_widget.attr_map)[1]
self.articles = self.cache.getArticlesFromCategory(item, self.show_read)
self.articleView.fill(self.articles)
self.feedView.setArticlesPaneTitle(name)
except BaseException:
pass
def run(self):
self.initialize_panes()
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 == "S":
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.cache.refresh()
for text in articles:
olb.body = urwid.SimpleListWalker([urwid.Text(text)])
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)
feeds = tui.cache.getFeeds(self.feedView.currentCategory, self.show_read)
if self.feedView.isCategoryView:
self.feedView.fill(self.categories, self.show_read)
else:
self.feedView.fill(feeds, self.show_read)
try:
self.feedView.set_focus(idx)
except BaseException:
pass
return
tui = TUI.create()
tui.run()