Refactored page initialization, content initialization, and loading.
This commit is contained in:
@@ -135,7 +135,7 @@ class SubmissionContent(BaseContent):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
submission,
|
submission,
|
||||||
loader=default_loader(),
|
loader=default_loader,
|
||||||
indent_size=2,
|
indent_size=2,
|
||||||
max_indent_level=4):
|
max_indent_level=4):
|
||||||
|
|
||||||
@@ -143,26 +143,35 @@ class SubmissionContent(BaseContent):
|
|||||||
self.max_indent_level = max_indent_level
|
self.max_indent_level = max_indent_level
|
||||||
self._loader = loader
|
self._loader = loader
|
||||||
|
|
||||||
|
self._submissin = submission
|
||||||
self._submission_data = self.strip_praw_submission(submission)
|
self._submission_data = self.strip_praw_submission(submission)
|
||||||
self.name = self._submission_data['permalink']
|
self.name = self._submission_data['permalink']
|
||||||
with loader:
|
with self._loader():
|
||||||
comments = self.flatten_comments(submission.comments)
|
comments = self.flatten_comments(submission.comments)
|
||||||
self._comment_data = [self.strip_praw_comment(c) for c in comments]
|
self._comment_data = [self.strip_praw_comment(c) for c in comments]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_url(
|
def from_url(
|
||||||
cls,
|
cls,
|
||||||
r,
|
reddit,
|
||||||
url,
|
url,
|
||||||
loader=default_loader(),
|
loader=default_loader,
|
||||||
indent_size=2,
|
indent_size=2,
|
||||||
max_indent_level=4):
|
max_indent_level=4):
|
||||||
|
|
||||||
with loader:
|
with loader():
|
||||||
submission = r.get_submission(url)
|
submission = reddit.get_submission(url)
|
||||||
|
|
||||||
return cls(submission, loader, indent_size, max_indent_level)
|
return cls(submission, loader, indent_size, max_indent_level)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
|
||||||
|
self._submissin.refresh()
|
||||||
|
self._submission_data = self.strip_praw_submission(submission)
|
||||||
|
self.name = self._submission_data['permalink']
|
||||||
|
comments = self.flatten_comments(submission.comments)
|
||||||
|
self._comment_data = [self.strip_praw_comment(c) for c in comments]
|
||||||
|
|
||||||
def get(self, index, n_cols=70):
|
def get(self, index, n_cols=70):
|
||||||
"""
|
"""
|
||||||
Grab the `i`th submission, with the title field formatted to fit inside
|
Grab the `i`th submission, with the title field formatted to fit inside
|
||||||
@@ -227,7 +236,7 @@ class SubmissionContent(BaseContent):
|
|||||||
|
|
||||||
elif data['type'] == 'MoreComments':
|
elif data['type'] == 'MoreComments':
|
||||||
|
|
||||||
with self._loader:
|
with self._loader():
|
||||||
comments = data['object'].comments()
|
comments = data['object'].comments()
|
||||||
comments = self.flatten_comments(comments, root_level=data['level'])
|
comments = self.flatten_comments(comments, root_level=data['level'])
|
||||||
comment_data = [self.strip_praw_comment(c) for c in comments]
|
comment_data = [self.strip_praw_comment(c) for c in comments]
|
||||||
@@ -249,23 +258,24 @@ class SubredditContent(BaseContent):
|
|||||||
list for repeat access.
|
list for repeat access.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, submission_generator, loader=default_loader()):
|
def __init__(self, name, submissions, loader=default_loader):
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self._loader = loader
|
self._loader = loader
|
||||||
self._submissions = submission_generator
|
self._submissions = submissions
|
||||||
self._submission_data = []
|
self._submission_data = []
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_name(cls, r, name, loader=default_loader()):
|
def from_name(cls, reddit, name, loader=default_loader):
|
||||||
|
|
||||||
if name == 'front':
|
if name == 'front':
|
||||||
return cls('Front Page', r.get_front_page(limit=None), loader)
|
return cls('Front Page', reddit.get_front_page(limit=None), loader)
|
||||||
|
|
||||||
if name == 'all':
|
if name == 'all':
|
||||||
sub = r.get_subreddit(name)
|
sub = reddit.get_subreddit(name)
|
||||||
else:
|
else:
|
||||||
sub = r.get_subreddit(name, fetch=True)
|
with loader():
|
||||||
|
sub = reddit.get_subreddit(name, fetch=True)
|
||||||
|
|
||||||
return cls('/r/'+sub.display_name, sub.get_hot(limit=None), loader)
|
return cls('/r/'+sub.display_name, sub.get_hot(limit=None), loader)
|
||||||
|
|
||||||
@@ -281,7 +291,7 @@ class SubredditContent(BaseContent):
|
|||||||
while index >= len(self._submission_data):
|
while index >= len(self._submission_data):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self._loader:
|
with self._loader():
|
||||||
submission = self._submissions.next()
|
submission = self._submissions.next()
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise IndexError
|
raise IndexError
|
||||||
|
|||||||
14
rtv/main.py
14
rtv/main.py
@@ -1,7 +1,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import praw
|
import praw
|
||||||
from utils import curses_session, LoadScreen
|
|
||||||
from content import SubredditContent
|
from utils import curses_session
|
||||||
from subreddit import SubredditPage
|
from subreddit import SubredditPage
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Reddit Terminal Viewer')
|
parser = argparse.ArgumentParser(description='Reddit Terminal Viewer')
|
||||||
@@ -13,17 +13,15 @@ group.add_argument('-p', dest='password', help='reddit password')
|
|||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
|
|
||||||
r = praw.Reddit(user_agent='reddit terminal viewer v0.0')
|
reddit = praw.Reddit(user_agent='reddit terminal viewer v0.0')
|
||||||
r.config.decode_html_entities = True
|
reddit.config.decode_html_entities = True
|
||||||
|
|
||||||
if args.username and args.password:
|
if args.username and args.password:
|
||||||
r.login(args.username, args.password)
|
reddit.login(args.username, args.password)
|
||||||
|
|
||||||
with curses_session() as stdscr:
|
with curses_session() as stdscr:
|
||||||
|
|
||||||
loader = LoadScreen(stdscr)
|
page = SubredditPage(stdscr, reddit, args.subreddit)
|
||||||
content = SubredditContent(r, subreddit=args.subreddit, loader=loader)
|
|
||||||
page = SubredditPage(stdscr, content)
|
|
||||||
page.loop()
|
page.loop()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
18
rtv/page.py
18
rtv/page.py
@@ -79,14 +79,12 @@ class BasePage(object):
|
|||||||
|
|
||||||
self.stdscr = stdscr
|
self.stdscr = stdscr
|
||||||
self.content = content
|
self.content = content
|
||||||
|
|
||||||
self.nav = Navigator(self.content.get, **kwargs)
|
self.nav = Navigator(self.content.get, **kwargs)
|
||||||
|
|
||||||
|
self._header_window = None
|
||||||
|
self._content_window = None
|
||||||
self._subwindows = None
|
self._subwindows = None
|
||||||
|
|
||||||
def draw(self):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def move_cursor_up(self):
|
def move_cursor_up(self):
|
||||||
self._move_cursor(-1)
|
self._move_cursor(-1)
|
||||||
|
|
||||||
@@ -106,12 +104,22 @@ class BasePage(object):
|
|||||||
continue
|
continue
|
||||||
self.stdscr.nodelay(0)
|
self.stdscr.nodelay(0)
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
|
||||||
|
n_rows, n_cols = self.stdscr.getmaxyx()
|
||||||
|
self._header_window = self.stdscr.derwin(1, n_cols, 0, 0)
|
||||||
|
self._content_window = self.stdscr.derwin(1, 0)
|
||||||
|
|
||||||
|
self.draw_header()
|
||||||
|
self.draw_content()
|
||||||
|
self.add_cursor()
|
||||||
|
|
||||||
def draw_header(self):
|
def draw_header(self):
|
||||||
|
|
||||||
n_rows, n_cols = self._header_window.getmaxyx()
|
n_rows, n_cols = self._header_window.getmaxyx()
|
||||||
|
|
||||||
self._header_window.erase()
|
self._header_window.erase()
|
||||||
self._header_window.addnstr(0, 0, self.content.display_name, n_cols-1)
|
self._header_window.addnstr(0, 0, self.content.name, n_cols-1)
|
||||||
|
|
||||||
def draw_content(self):
|
def draw_content(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
import praw
|
|
||||||
import curses
|
import curses
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from content import SubmissionContent
|
||||||
from page import BasePage
|
from page import BasePage
|
||||||
from utils import curses_session
|
from utils import LoadScreen
|
||||||
|
|
||||||
class SubmissionPage(BasePage):
|
class SubmissionPage(BasePage):
|
||||||
|
|
||||||
def __init__(self, stdscr, content):
|
def __init__(self, stdscr, reddit, url=None, submission=None):
|
||||||
|
|
||||||
|
self.loader = LoadScreen(stdscr)
|
||||||
|
|
||||||
|
if url is not None:
|
||||||
|
content = SubmissionContent.from_url(reddit, url, self.loader)
|
||||||
|
elif submission is not None:
|
||||||
|
content = SubmissionContent(submission, self.loader)
|
||||||
|
else:
|
||||||
|
raise ValueError('Must specify url or submission')
|
||||||
|
|
||||||
page_index, cursor_index = -1, 1
|
|
||||||
super(SubmissionPage, self).__init__(
|
super(SubmissionPage, self).__init__(
|
||||||
stdscr, content,
|
stdscr, content, page_index=-1, cursor_index=1)
|
||||||
page_index=page_index, cursor_index=cursor_index)
|
|
||||||
|
|
||||||
def loop(self):
|
def loop(self):
|
||||||
|
|
||||||
@@ -61,16 +68,6 @@ class SubmissionPage(BasePage):
|
|||||||
self.stdscr.clear()
|
self.stdscr.clear()
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def draw(self):
|
|
||||||
|
|
||||||
n_rows, n_cols = self.stdscr.getmaxyx()
|
|
||||||
self._header_window = self.stdscr.derwin(1, n_cols, 0, 0)
|
|
||||||
self._content_window = self.stdscr.derwin(1, 0)
|
|
||||||
|
|
||||||
self.draw_header()
|
|
||||||
self.draw_content()
|
|
||||||
self.add_cursor()
|
|
||||||
|
|
||||||
def draw_item(self, win, data, inverted=False):
|
def draw_item(self, win, data, inverted=False):
|
||||||
|
|
||||||
if data['type'] == 'MoreComments':
|
if data['type'] == 'MoreComments':
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
import praw
|
|
||||||
import textwrap
|
|
||||||
import curses
|
import curses
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from page import BasePage
|
from page import BasePage
|
||||||
from submission import SubmissionPage
|
from submission import SubmissionPage
|
||||||
from content import SubmissionContent
|
from content import SubredditContent
|
||||||
from utils import curses_session, text_input
|
from utils import LoadScreen, text_input
|
||||||
|
|
||||||
class SubredditPage(BasePage):
|
class SubredditPage(BasePage):
|
||||||
|
|
||||||
|
def __init__(self, stdscr, reddit, name):
|
||||||
|
|
||||||
|
self.reddit = reddit
|
||||||
|
self.name = name
|
||||||
|
self.loader = LoadScreen(stdscr)
|
||||||
|
|
||||||
|
content = SubredditContent.from_name(reddit, name, self.loader)
|
||||||
|
super(SubredditPage, self).__init__(stdscr, content)
|
||||||
|
|
||||||
def loop(self):
|
def loop(self):
|
||||||
|
|
||||||
self.draw()
|
self.draw()
|
||||||
@@ -47,11 +54,12 @@ class SubredditPage(BasePage):
|
|||||||
else:
|
else:
|
||||||
curses.beep()
|
curses.beep()
|
||||||
|
|
||||||
def refresh_content(self, subreddit=None):
|
def refresh_content(self, name=None):
|
||||||
|
|
||||||
self.nav.page_index, self.nav.cursor_index = 0, 0
|
self.nav.page_index, self.nav.cursor_index = 0, 0
|
||||||
self.nav.inverted = False
|
self.nav.inverted = False
|
||||||
self.content.reset(subreddit=subreddit)
|
self.name = name if name else self.name
|
||||||
|
self.content = SubredditContent.from_name(self.reddit, self.name, self.loader)
|
||||||
self.stdscr.clear()
|
self.stdscr.clear()
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
@@ -67,26 +75,15 @@ class SubredditPage(BasePage):
|
|||||||
if out is None:
|
if out is None:
|
||||||
self.draw()
|
self.draw()
|
||||||
else:
|
else:
|
||||||
self.refresh_content(subreddit=out)
|
self.refresh_content(name=out)
|
||||||
|
|
||||||
def open_submission(self):
|
def open_submission(self):
|
||||||
"Select the current submission to view posts"
|
"Select the current submission to view posts"
|
||||||
|
|
||||||
submission = self.content.get(self.nav.absolute_index)['object']
|
submission = self.content.get(self.nav.absolute_index)['object']
|
||||||
content = SubmissionContent(submission, loader=self.content.loader)
|
page = SubmissionPage(self.stdscr, self.reddit, submission=submission)
|
||||||
page = SubmissionPage(self.stdscr, content)
|
|
||||||
page.loop()
|
page.loop()
|
||||||
|
|
||||||
def draw(self):
|
|
||||||
|
|
||||||
n_rows, n_cols = self.stdscr.getmaxyx()
|
|
||||||
self._header_window = self.stdscr.derwin(1, n_cols, 0, 0)
|
|
||||||
self._content_window = self.stdscr.derwin(1, 0)
|
|
||||||
|
|
||||||
self.draw_header()
|
|
||||||
self.draw_content()
|
|
||||||
self.add_cursor()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def draw_item(win, data, inverted=False):
|
def draw_item(win, data, inverted=False):
|
||||||
|
|
||||||
|
|||||||
37
rtv/utils.py
37
rtv/utils.py
@@ -42,26 +42,27 @@ def text_input(window):
|
|||||||
|
|
||||||
class LoadScreen(object):
|
class LoadScreen(object):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, stdscr):
|
||||||
self,
|
|
||||||
stdscr,
|
|
||||||
message='Downloading',
|
|
||||||
trail='...',
|
|
||||||
delay=0.5,
|
|
||||||
interval=0.4):
|
|
||||||
|
|
||||||
self._stdscr = stdscr
|
self._stdscr = stdscr
|
||||||
self.message = message
|
|
||||||
self.delay = delay
|
|
||||||
self.interval=interval
|
|
||||||
self.trail = trail
|
|
||||||
|
|
||||||
|
self._args = None
|
||||||
self._animator = None
|
self._animator = None
|
||||||
self._is_running = None
|
self._is_running = None
|
||||||
|
|
||||||
|
def __call__(
|
||||||
|
self,
|
||||||
|
delay=0.5,
|
||||||
|
interval=0.4,
|
||||||
|
message='Downloading',
|
||||||
|
trail='...'):
|
||||||
|
|
||||||
|
self._args = (delay, interval, message, trail)
|
||||||
|
return self
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
|
|
||||||
self._animator = threading.Thread(target=self.animate)
|
self._animator = threading.Thread(target=self.animate, args=self._args)
|
||||||
self._animator.daemon = True
|
self._animator.daemon = True
|
||||||
|
|
||||||
self._is_running = True
|
self._is_running = True
|
||||||
@@ -72,23 +73,23 @@ class LoadScreen(object):
|
|||||||
self._is_running = False
|
self._is_running = False
|
||||||
self._animator.join()
|
self._animator.join()
|
||||||
|
|
||||||
def animate(self):
|
def animate(self, delay, interval, message, trail):
|
||||||
|
|
||||||
# Delay before starting animation to avoid wasting resources if the
|
# Delay before starting animation to avoid wasting resources if the
|
||||||
# wait time is very short
|
# wait time is very short
|
||||||
start = time.time()
|
start = time.time()
|
||||||
while (time.time() - start) < self.delay:
|
while (time.time() - start) < delay:
|
||||||
if not self._is_running:
|
if not self._is_running:
|
||||||
return
|
return
|
||||||
|
|
||||||
message_len = len(self.message) + len(self.trail)
|
message_len = len(message) + len(trail)
|
||||||
n_rows, n_cols = self._stdscr.getmaxyx()
|
n_rows, n_cols = self._stdscr.getmaxyx()
|
||||||
s_row = (n_rows - 2) / 2
|
s_row = (n_rows - 2) / 2
|
||||||
s_col = (n_cols - message_len - 1) / 2
|
s_col = (n_cols - message_len - 1) / 2
|
||||||
window = self._stdscr.derwin(3, message_len+2, s_row, s_col)
|
window = self._stdscr.derwin(3, message_len+2, s_row, s_col)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
for i in xrange(len(self.trail)+1):
|
for i in xrange(len(trail)+1):
|
||||||
|
|
||||||
if not self._is_running:
|
if not self._is_running:
|
||||||
# TODO: figure out why this isn't removing the screen
|
# TODO: figure out why this isn't removing the screen
|
||||||
@@ -98,9 +99,9 @@ class LoadScreen(object):
|
|||||||
|
|
||||||
window.erase()
|
window.erase()
|
||||||
window.border()
|
window.border()
|
||||||
window.addstr(1, 1, self.message + self.trail[:i])
|
window.addstr(1, 1, message + trail[:i])
|
||||||
window.refresh()
|
window.refresh()
|
||||||
time.sleep(self.interval)
|
time.sleep(interval)
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
|
|||||||
Reference in New Issue
Block a user