Merge branch 'master' of https://github.com/michael-lazar/rtv
This commit is contained in:
@@ -70,6 +70,7 @@ In subreddit mode you can browse through the top submissions on either the front
|
||||
|
||||
:``►`` or ``l``: View comments for the selected submission
|
||||
:``/``: Open a prompt to switch subreddits
|
||||
:``f``: Open a prompt to search the current subreddit
|
||||
|
||||
The ``/`` prompt accepts subreddits in the following formats
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ class SubredditContent(BaseContent):
|
||||
self._submission_data = []
|
||||
|
||||
@classmethod
|
||||
def from_name(cls, reddit, name, loader, order='hot'):
|
||||
def from_name(cls, reddit, name, loader, order='hot', search=None):
|
||||
|
||||
if name is None:
|
||||
name = 'front'
|
||||
@@ -266,9 +266,11 @@ class SubredditContent(BaseContent):
|
||||
display_name = '/r/{}'.format(name)
|
||||
else:
|
||||
display_name = '/r/{}/{}'.format(name, order)
|
||||
|
||||
|
||||
if name == 'front':
|
||||
if order == 'hot':
|
||||
if search:
|
||||
submissions = reddit.search(search, None, order)
|
||||
elif order == 'hot':
|
||||
submissions = reddit.get_front_page(limit=None)
|
||||
elif order == 'top':
|
||||
submissions = reddit.get_top(limit=None)
|
||||
@@ -280,10 +282,11 @@ class SubredditContent(BaseContent):
|
||||
submissions = reddit.get_controversial(limit=None)
|
||||
else:
|
||||
raise SubredditError(display_name)
|
||||
|
||||
else:
|
||||
subreddit = reddit.get_subreddit(name)
|
||||
if order == 'hot':
|
||||
if search:
|
||||
submissions = reddit.search(search, name, order)
|
||||
elif order == 'hot':
|
||||
submissions = subreddit.get_hot(limit=None)
|
||||
elif order == 'top':
|
||||
submissions = subreddit.get_top(limit=None)
|
||||
|
||||
@@ -52,12 +52,14 @@ def show_notification(stdscr, message):
|
||||
for index, line in enumerate(message, start=1):
|
||||
window.addstr(index, 1, line)
|
||||
window.refresh()
|
||||
stdscr.getch()
|
||||
ch = stdscr.getch()
|
||||
|
||||
window.clear()
|
||||
window = None
|
||||
stdscr.refresh()
|
||||
|
||||
return ch
|
||||
|
||||
|
||||
def show_help(stdscr):
|
||||
"""
|
||||
|
||||
@@ -2,9 +2,7 @@ from .__version__ import __version__
|
||||
|
||||
__all__ = ['AGENT', 'SUMMARY', 'AUTH', 'CONTROLS', 'HELP']
|
||||
|
||||
AGENT = """
|
||||
desktop:https://github.com/michael-lazar/rtv:{} (by /u/civilization_phaze_3)
|
||||
""".format(__version__)
|
||||
AGENT = "desktop:https://github.com/michael-lazar/rtv:{} (by /u/civilization_phaze_3)".format(__version__)
|
||||
|
||||
SUMMARY = """
|
||||
Reddit Terminal Viewer is a lightweight browser for www.reddit.com built into a
|
||||
@@ -33,11 +31,13 @@ Global Commands
|
||||
`r` : Refresh the current page
|
||||
`q` : Quit the program
|
||||
`ENTER` or `o` : Open the selected item in the default web browser
|
||||
`u` : Log in
|
||||
`?` : Show this help message
|
||||
|
||||
Subreddit Mode
|
||||
`RIGHT` or `l` : View comments for the selected submission
|
||||
`/` : Open a prompt to switch subreddits
|
||||
`f` : Open a prompt to search the current subreddit
|
||||
|
||||
Submission Mode
|
||||
`LEFT` or `h` : Return to subreddit mode
|
||||
|
||||
58
rtv/page.py
58
rtv/page.py
@@ -5,7 +5,8 @@ import sys
|
||||
import praw.errors
|
||||
|
||||
from .helpers import clean
|
||||
from .curses_helpers import Color, show_notification, show_help
|
||||
from .curses_helpers import Color, show_notification, show_help, text_input
|
||||
from .docs import AGENT
|
||||
|
||||
__all__ = ['Navigator']
|
||||
|
||||
@@ -226,6 +227,61 @@ class BasePage(object):
|
||||
except praw.errors.LoginOrScopeRequired:
|
||||
show_notification(self.stdscr, ['Login to vote'])
|
||||
|
||||
@BaseController.register('u')
|
||||
def login(self):
|
||||
"""
|
||||
Prompt to log into the user's account. Log out if the user is already
|
||||
logged in.
|
||||
"""
|
||||
|
||||
if self.reddit.is_logged_in():
|
||||
self.logout()
|
||||
return
|
||||
|
||||
username = self.prompt_input('Enter username:')
|
||||
password = self.prompt_input('Enter password:', hide=True)
|
||||
if not username or not password:
|
||||
curses.flash()
|
||||
return
|
||||
|
||||
try:
|
||||
self.reddit.login(username, password)
|
||||
except praw.errors.InvalidUserPass:
|
||||
show_notification(self.stdscr, ['Invalid user/pass'])
|
||||
else:
|
||||
show_notification(self.stdscr, ['Logged in'])
|
||||
|
||||
def logout(self):
|
||||
"""
|
||||
Prompt to log out of the user's account.
|
||||
"""
|
||||
|
||||
ch = self.prompt_input("Log out? (y/n):")
|
||||
if ch == 'y':
|
||||
self.reddit.clear_authentication()
|
||||
show_notification(self.stdscr, ['Logged out'])
|
||||
elif ch != 'n':
|
||||
curses.flash()
|
||||
|
||||
def prompt_input(self, prompt, hide=False):
|
||||
"""Prompt the user for input"""
|
||||
attr = curses.A_BOLD | Color.CYAN
|
||||
n_rows, n_cols = self.stdscr.getmaxyx()
|
||||
|
||||
if hide:
|
||||
prompt += ' ' * (n_cols - len(prompt) - 1)
|
||||
self.stdscr.addstr(n_rows-1, 0, prompt, attr)
|
||||
out = self.stdscr.getstr(n_rows-1, 1)
|
||||
else:
|
||||
self.stdscr.addstr(n_rows - 1, 0, prompt, attr)
|
||||
self.stdscr.refresh()
|
||||
window = self.stdscr.derwin(1, n_cols - len(prompt),
|
||||
n_rows - 1, len(prompt))
|
||||
window.attrset(attr)
|
||||
out = text_input(window)
|
||||
|
||||
return out
|
||||
|
||||
def draw(self):
|
||||
|
||||
n_rows, n_cols = self.stdscr.getmaxyx()
|
||||
|
||||
@@ -143,13 +143,13 @@ class SubmissionPage(BasePage):
|
||||
row = offset
|
||||
if row in valid_rows:
|
||||
|
||||
text = clean('{author} '.format(**data))
|
||||
text = clean(u'{author} '.format(**data))
|
||||
attr = curses.A_BOLD
|
||||
attr |= (Color.BLUE if not data['is_author'] else Color.GREEN)
|
||||
win.addnstr(row, 1, text, n_cols - 1, attr)
|
||||
|
||||
if data['flair']:
|
||||
text = clean('{flair} '.format(**data))
|
||||
text = clean(u'{flair} '.format(**data))
|
||||
attr = curses.A_BOLD | Color.YELLOW
|
||||
win.addnstr(text, n_cols - win.getyx()[1], attr)
|
||||
|
||||
@@ -161,7 +161,7 @@ class SubmissionPage(BasePage):
|
||||
text, attr = DARROW, (curses.A_BOLD | Color.RED)
|
||||
win.addnstr(text, n_cols - win.getyx()[1], attr)
|
||||
|
||||
text = clean(' {score} {created}'.format(**data))
|
||||
text = clean(u' {score} {created}'.format(**data))
|
||||
win.addnstr(text, n_cols - win.getyx()[1])
|
||||
|
||||
n_body = len(data['split_body'])
|
||||
@@ -191,9 +191,9 @@ class SubmissionPage(BasePage):
|
||||
n_rows, n_cols = win.getmaxyx()
|
||||
n_cols -= 1
|
||||
|
||||
text = clean('{body}'.format(**data))
|
||||
text = clean(u'{body}'.format(**data))
|
||||
win.addnstr(0, 1, text, n_cols - 1)
|
||||
text = clean(' [{count}]'.format(**data))
|
||||
text = clean(u' [{count}]'.format(**data))
|
||||
win.addnstr(text, n_cols - win.getyx()[1], curses.A_BOLD)
|
||||
|
||||
# Unfortunately vline() doesn't support custom color so we have to
|
||||
@@ -209,37 +209,39 @@ class SubmissionPage(BasePage):
|
||||
n_rows, n_cols = win.getmaxyx()
|
||||
n_cols -= 3 # one for each side of the border + one for offset
|
||||
|
||||
# Don't print at all if there is not enough room to fit the whole sub
|
||||
if data['n_rows'] > n_rows:
|
||||
win.addnstr(0, 0, '(Not enough space to display)', n_cols)
|
||||
return
|
||||
|
||||
for row, text in enumerate(data['split_title'], start=1):
|
||||
text = clean(text)
|
||||
win.addnstr(row, 1, text, n_cols, curses.A_BOLD)
|
||||
|
||||
row = len(data['split_title']) + 1
|
||||
attr = curses.A_BOLD | Color.GREEN
|
||||
text = clean('{author}'.format(**data))
|
||||
text = clean(u'{author}'.format(**data))
|
||||
win.addnstr(row, 1, text, n_cols, attr)
|
||||
attr = curses.A_BOLD | Color.YELLOW
|
||||
text = clean(' {flair}'.format(**data))
|
||||
text = clean(u' {flair}'.format(**data))
|
||||
win.addnstr(text, n_cols - win.getyx()[1], attr)
|
||||
text = clean(' {created} {subreddit}'.format(**data))
|
||||
text = clean(u' {created} {subreddit}'.format(**data))
|
||||
win.addnstr(text, n_cols - win.getyx()[1])
|
||||
|
||||
row = len(data['split_title']) + 2
|
||||
attr = curses.A_UNDERLINE | Color.BLUE
|
||||
text = clean('{url}'.format(**data))
|
||||
text = clean(u'{url}'.format(**data))
|
||||
win.addnstr(row, 1, text, n_cols, attr)
|
||||
|
||||
offset = len(data['split_title']) + 3
|
||||
for row, text in enumerate(data['split_text'], start=offset):
|
||||
|
||||
# Cut off text if there is not enough room to display the whole post
|
||||
split_text = data['split_text']
|
||||
if data['n_rows'] > n_rows:
|
||||
cutoff = data['n_rows'] - n_rows + 1
|
||||
split_text = split_text[:-cutoff]
|
||||
split_text.append('(Not enough space to display)')
|
||||
|
||||
for row, text in enumerate(split_text, start=offset):
|
||||
text = clean(text)
|
||||
win.addnstr(row, 1, text, n_cols)
|
||||
|
||||
row = len(data['split_title']) + len(data['split_text']) + 3
|
||||
text = clean('{score} {comments}'.format(**data))
|
||||
row = len(data['split_title']) + len(split_text) + 3
|
||||
text = clean(u'{score} {comments}'.format(**data))
|
||||
win.addnstr(row, 1, text, n_cols, curses.A_BOLD)
|
||||
|
||||
win.border()
|
||||
|
||||
@@ -8,7 +8,7 @@ from .submission import SubmissionPage
|
||||
from .content import SubredditContent
|
||||
from .helpers import clean, open_browser
|
||||
from .curses_helpers import (BULLET, UARROW, DARROW, Color, LoadScreen,
|
||||
text_input, show_notification)
|
||||
show_notification)
|
||||
|
||||
__all__ = ['opened_links', 'SubredditController', 'SubredditPage']
|
||||
|
||||
@@ -50,22 +50,27 @@ class SubredditPage(BasePage):
|
||||
else:
|
||||
self.nav = Navigator(self.content.get)
|
||||
|
||||
@SubredditController.register('f')
|
||||
def search_subreddit(self, name=None):
|
||||
"""Open a prompt to search the subreddit"""
|
||||
name = name or self.content.name
|
||||
prompt = 'Search this Subreddit: '
|
||||
search = self.prompt_input(prompt)
|
||||
if search is not None:
|
||||
try:
|
||||
self.nav.cursor_index = 0
|
||||
self.content = SubredditContent.from_name(self.reddit, name,
|
||||
self.loader, search=search)
|
||||
except IndexError: # if there are no submissions
|
||||
show_notification(self.stdscr, ['No results found'])
|
||||
|
||||
@SubredditController.register('/')
|
||||
def prompt_subreddit(self):
|
||||
"Open a prompt to type in a new subreddit"
|
||||
|
||||
attr = curses.A_BOLD | Color.CYAN
|
||||
"""Open a prompt to type in a new subreddit"""
|
||||
prompt = 'Enter Subreddit: /r/'
|
||||
n_rows, n_cols = self.stdscr.getmaxyx()
|
||||
self.stdscr.addstr(n_rows - 1, 0, prompt, attr)
|
||||
self.stdscr.refresh()
|
||||
window = self.stdscr.derwin(1, n_cols - len(prompt),
|
||||
n_rows - 1, len(prompt))
|
||||
window.attrset(attr)
|
||||
|
||||
out = text_input(window)
|
||||
if out is not None:
|
||||
self.refresh_content(name=out)
|
||||
name = self.prompt_input(prompt)
|
||||
if name is not None:
|
||||
self.refresh_content(name=name)
|
||||
|
||||
@SubredditController.register(curses.KEY_RIGHT, 'l')
|
||||
def open_submission(self):
|
||||
@@ -110,12 +115,12 @@ class SubredditPage(BasePage):
|
||||
seen = (data['url_full'] in opened_links)
|
||||
link_color = Color.MAGENTA if seen else Color.BLUE
|
||||
attr = curses.A_UNDERLINE | link_color
|
||||
text = clean('{url}'.format(**data))
|
||||
text = clean(u'{url}'.format(**data))
|
||||
win.addnstr(row, 1, text, n_cols - 1, attr)
|
||||
|
||||
row = n_title + offset + 1
|
||||
if row in valid_rows:
|
||||
text = clean('{score} '.format(**data))
|
||||
text = clean(u'{score} '.format(**data))
|
||||
win.addnstr(row, 1, text, n_cols - 1)
|
||||
|
||||
if data['likes'] is None:
|
||||
@@ -126,14 +131,14 @@ class SubredditPage(BasePage):
|
||||
text, attr = DARROW, curses.A_BOLD | Color.RED
|
||||
win.addnstr(text, n_cols - win.getyx()[1], attr)
|
||||
|
||||
text = clean(' {created} {comments}'.format(**data))
|
||||
text = clean(u' {created} {comments}'.format(**data))
|
||||
win.addnstr(text, n_cols - win.getyx()[1])
|
||||
|
||||
row = n_title + offset + 2
|
||||
if row in valid_rows:
|
||||
text = clean('{author}'.format(**data))
|
||||
text = clean(u'{author}'.format(**data))
|
||||
win.addnstr(row, 1, text, n_cols - 1, curses.A_BOLD)
|
||||
text = clean(' {subreddit}'.format(**data))
|
||||
text = clean(u' {subreddit}'.format(**data))
|
||||
win.addnstr(text, n_cols - win.getyx()[1], Color.YELLOW)
|
||||
text = clean(' {flair}'.format(**data))
|
||||
text = clean(u' {flair}'.format(**data))
|
||||
win.addnstr(text, n_cols - win.getyx()[1], Color.RED)
|
||||
|
||||
Reference in New Issue
Block a user