Comments are now forced to sort by "hot" in all cases.
This commit is contained in:
@@ -50,7 +50,7 @@ def humanize_timestamp(utc_timestamp, verbose=False):
|
|||||||
return ('%d years ago' % years) if verbose else ('%dyr' % years)
|
return ('%d years ago' % years) if verbose else ('%dyr' % years)
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def default_loader(self):
|
def default_loader():
|
||||||
yield
|
yield
|
||||||
|
|
||||||
class BaseContent(object):
|
class BaseContent(object):
|
||||||
@@ -85,6 +85,8 @@ class BaseContent(object):
|
|||||||
retval = []
|
retval = []
|
||||||
while stack:
|
while stack:
|
||||||
item = stack.pop(0)
|
item = stack.pop(0)
|
||||||
|
if isinstance(item, praw.objects.MoreComments) and (item.count==0):
|
||||||
|
continue
|
||||||
nested = getattr(item, 'replies', None)
|
nested = getattr(item, 'replies', None)
|
||||||
if nested:
|
if nested:
|
||||||
for n in nested:
|
for n in nested:
|
||||||
@@ -104,11 +106,6 @@ class BaseContent(object):
|
|||||||
data['object'] = comment
|
data['object'] = comment
|
||||||
data['level'] = comment.nested_level
|
data['level'] = comment.nested_level
|
||||||
|
|
||||||
if getattr(comment.submission, 'author'):
|
|
||||||
sub_author = comment.submission.author.name
|
|
||||||
else:
|
|
||||||
sub_author = '[deleted]'
|
|
||||||
|
|
||||||
if isinstance(comment, praw.objects.MoreComments):
|
if isinstance(comment, praw.objects.MoreComments):
|
||||||
data['type'] = 'MoreComments'
|
data['type'] = 'MoreComments'
|
||||||
data['count'] = comment.count
|
data['count'] = comment.count
|
||||||
@@ -119,7 +116,7 @@ class BaseContent(object):
|
|||||||
data['created'] = humanize_timestamp(comment.created_utc)
|
data['created'] = humanize_timestamp(comment.created_utc)
|
||||||
data['score'] = '{} pts'.format(comment.score)
|
data['score'] = '{} pts'.format(comment.score)
|
||||||
data['author'] = (comment.author.name if getattr(comment, 'author') else '[deleted]')
|
data['author'] = (comment.author.name if getattr(comment, 'author') else '[deleted]')
|
||||||
data['is_author'] = (data['author'] == sub_author)
|
data['is_author'] = (data['author'] == getattr(comment.submission, 'author'))
|
||||||
data['flair'] = (comment.author_flair_text if comment.author_flair_text else '')
|
data['flair'] = (comment.author_flair_text if comment.author_flair_text else '')
|
||||||
data['likes'] = comment.likes
|
data['likes'] = comment.likes
|
||||||
|
|
||||||
@@ -170,11 +167,11 @@ class SubmissionContent(BaseContent):
|
|||||||
self.max_indent_level = max_indent_level
|
self.max_indent_level = max_indent_level
|
||||||
self._loader = loader
|
self._loader = loader
|
||||||
self._submission = submission
|
self._submission = submission
|
||||||
self._submission_data = None
|
|
||||||
self._comment_data = None
|
|
||||||
self.name = None
|
|
||||||
|
|
||||||
self.reset()
|
self._submission_data = self.strip_praw_submission(self._submission)
|
||||||
|
self.name = self._submission_data['permalink']
|
||||||
|
comments = self.flatten_comments(self._submission.comments)
|
||||||
|
self._comment_data = [self.strip_praw_comment(c) for c in comments]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_url(
|
def from_url(
|
||||||
@@ -187,22 +184,12 @@ class SubmissionContent(BaseContent):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
with loader():
|
with loader():
|
||||||
submission = reddit.get_submission(url)
|
submission = reddit.get_submission(url, comment_sort='hot')
|
||||||
|
|
||||||
except praw.errors.APIException:
|
except praw.errors.APIException:
|
||||||
raise SubmissionURLError(url)
|
raise SubmissionURLError(url)
|
||||||
|
|
||||||
return cls(submission, loader, indent_size, max_indent_level)
|
return cls(submission, loader, indent_size, max_indent_level)
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
|
|
||||||
with self._loader():
|
|
||||||
self._submission.refresh()
|
|
||||||
self._submission_data = self.strip_praw_submission(self._submission)
|
|
||||||
self.name = self._submission_data['permalink']
|
|
||||||
comments = self.flatten_comments(self._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
|
||||||
@@ -269,7 +256,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(update=False)
|
||||||
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]
|
||||||
self._comment_data[index:index+1] = comment_data
|
self._comment_data[index:index+1] = comment_data
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import sys
|
|||||||
|
|
||||||
from .content import SubmissionContent
|
from .content import SubmissionContent
|
||||||
from .page import BasePage
|
from .page import BasePage
|
||||||
from .utils import LoadScreen, Color, Symbol, display_help, open_browser
|
from .utils import Color, Symbol, display_help
|
||||||
|
from .workers import LoadScreen, open_browser
|
||||||
|
|
||||||
class SubmissionPage(BasePage):
|
class SubmissionPage(BasePage):
|
||||||
|
|
||||||
@@ -80,7 +81,8 @@ class SubmissionPage(BasePage):
|
|||||||
|
|
||||||
def refresh_content(self):
|
def refresh_content(self):
|
||||||
|
|
||||||
self.content.reset()
|
url = self.content.name
|
||||||
|
self.content = SubmissionContent.from_url(self.reddit, url, self.loader)
|
||||||
self.nav.page_index, self.nav.cursor_index = -1, 0
|
self.nav.page_index, self.nav.cursor_index = -1, 0
|
||||||
self.nav.inverted = False
|
self.nav.inverted = False
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from .errors import SubredditNameError
|
|||||||
from .page import BasePage
|
from .page import BasePage
|
||||||
from .submission import SubmissionPage
|
from .submission import SubmissionPage
|
||||||
from .content import SubredditContent
|
from .content import SubredditContent
|
||||||
from .utils import (LoadScreen, Symbol, Color, text_input, display_message,
|
from .utils import Symbol, Color, text_input, display_message, display_help
|
||||||
display_help, open_browser)
|
from .workers import LoadScreen, open_browser
|
||||||
|
|
||||||
# Used to keep track of browsing history across the current session
|
# Used to keep track of browsing history across the current session
|
||||||
_opened_links = set()
|
_opened_links = set()
|
||||||
@@ -108,7 +108,7 @@ class SubredditPage(BasePage):
|
|||||||
"Select the current submission to view posts"
|
"Select the current submission to view posts"
|
||||||
|
|
||||||
data = self.content.get(self.nav.absolute_index)
|
data = self.content.get(self.nav.absolute_index)
|
||||||
page = SubmissionPage(self.stdscr, self.reddit, submission=data['object'])
|
page = SubmissionPage(self.stdscr, self.reddit, url=data['permalink'])
|
||||||
page.loop()
|
page.loop()
|
||||||
|
|
||||||
if data['url'] == 'selfpost':
|
if data['url'] == 'selfpost':
|
||||||
|
|||||||
82
rtv/utils.py
82
rtv/utils.py
@@ -1,9 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
import curses
|
import curses
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
from curses import textpad, ascii
|
from curses import textpad, ascii
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
@@ -193,82 +189,6 @@ def display_help(stdscr):
|
|||||||
help_msgs = HELP.split("\n")
|
help_msgs = HELP.split("\n")
|
||||||
display_message(stdscr, help_msgs)
|
display_message(stdscr, help_msgs)
|
||||||
|
|
||||||
class LoadScreen(object):
|
|
||||||
|
|
||||||
def __init__(self, stdscr):
|
|
||||||
|
|
||||||
self._stdscr = stdscr
|
|
||||||
|
|
||||||
self._args = None
|
|
||||||
self._animator = 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):
|
|
||||||
|
|
||||||
self._animator = threading.Thread(target=self.animate, args=self._args)
|
|
||||||
self._animator.daemon = True
|
|
||||||
|
|
||||||
self._is_running = True
|
|
||||||
self._animator.start()
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
||||||
|
|
||||||
self._is_running = False
|
|
||||||
self._animator.join()
|
|
||||||
|
|
||||||
def animate(self, delay, interval, message, trail):
|
|
||||||
|
|
||||||
# Delay before starting animation to avoid wasting resources if the
|
|
||||||
# wait time is very short
|
|
||||||
start = time.time()
|
|
||||||
while (time.time() - start) < delay:
|
|
||||||
if not self._is_running:
|
|
||||||
return
|
|
||||||
|
|
||||||
message_len = len(message) + len(trail)
|
|
||||||
n_rows, n_cols = self._stdscr.getmaxyx()
|
|
||||||
s_row = (n_rows - 3) // 2
|
|
||||||
s_col = (n_cols - message_len - 1) // 2
|
|
||||||
window = self._stdscr.derwin(3, message_len+2, s_row, s_col)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
for i in range(len(trail)+1):
|
|
||||||
|
|
||||||
if not self._is_running:
|
|
||||||
window.clear()
|
|
||||||
window = None
|
|
||||||
self._stdscr.refresh()
|
|
||||||
return
|
|
||||||
|
|
||||||
window.erase()
|
|
||||||
window.border()
|
|
||||||
window.addstr(1, 1, message + trail[:i])
|
|
||||||
window.refresh()
|
|
||||||
time.sleep(interval)
|
|
||||||
|
|
||||||
def open_browser(url):
|
|
||||||
"""
|
|
||||||
Call webbrowser.open_new_tab(url) and redirect stdout/stderr to devnull.
|
|
||||||
|
|
||||||
This is a workaround to stop firefox from spewing warning messages to the
|
|
||||||
console. See http://bugs.python.org/issue22277 for a better description
|
|
||||||
of the problem.
|
|
||||||
"""
|
|
||||||
command = "import webbrowser; webbrowser.open_new_tab('%s')" % url
|
|
||||||
args = [sys.executable, '-c', command]
|
|
||||||
with open(os.devnull, 'ab+', 0) as null:
|
|
||||||
subprocess.check_call(args, stdout=null, stderr=null)
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def curses_session():
|
def curses_session():
|
||||||
|
|
||||||
@@ -316,4 +236,4 @@ def curses_session():
|
|||||||
stdscr.keypad(0)
|
stdscr.keypad(0)
|
||||||
curses.echo()
|
curses.echo()
|
||||||
curses.nocbreak()
|
curses.nocbreak()
|
||||||
curses.endwin()
|
curses.endwin()
|
||||||
95
rtv/workers.py
Normal file
95
rtv/workers.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import time
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def open_browser(url):
|
||||||
|
"""
|
||||||
|
Call webbrowser.open_new_tab(url) and redirect stdout/stderr to devnull.
|
||||||
|
|
||||||
|
This is a workaround to stop firefox from spewing warning messages to the
|
||||||
|
console. See http://bugs.python.org/issue22277 for a better description
|
||||||
|
of the problem.
|
||||||
|
"""
|
||||||
|
command = "import webbrowser; webbrowser.open_new_tab('%s')" % url
|
||||||
|
args = [sys.executable, '-c', command]
|
||||||
|
with open(os.devnull, 'ab+', 0) as null:
|
||||||
|
subprocess.check_call(args, stdout=null, stderr=null)
|
||||||
|
|
||||||
|
|
||||||
|
class LoadScreen(object):
|
||||||
|
"""
|
||||||
|
Display a loading dialog while waiting for a blocking action to complete.
|
||||||
|
|
||||||
|
This class spins off a seperate thread to animate the loading screen in the
|
||||||
|
background.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
#>>> loader = LoadScreen(stdscr)
|
||||||
|
#>>> with loader(...):
|
||||||
|
#>>> blocking_request(...)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, stdscr):
|
||||||
|
|
||||||
|
self._stdscr = stdscr
|
||||||
|
|
||||||
|
self._args = None
|
||||||
|
self._animator = 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):
|
||||||
|
|
||||||
|
self._animator = threading.Thread(target=self.animate, args=self._args)
|
||||||
|
self._animator.daemon = True
|
||||||
|
|
||||||
|
self._is_running = True
|
||||||
|
self._animator.start()
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
|
||||||
|
self._is_running = False
|
||||||
|
self._animator.join()
|
||||||
|
|
||||||
|
# Check for timeout error
|
||||||
|
|
||||||
|
def animate(self, delay, interval, message, trail):
|
||||||
|
|
||||||
|
# Delay before starting animation to avoid wasting resources if the
|
||||||
|
# wait time is very short
|
||||||
|
start = time.time()
|
||||||
|
while (time.time() - start) < delay:
|
||||||
|
if not self._is_running:
|
||||||
|
return
|
||||||
|
|
||||||
|
message_len = len(message) + len(trail)
|
||||||
|
n_rows, n_cols = self._stdscr.getmaxyx()
|
||||||
|
s_row = (n_rows - 3) // 2
|
||||||
|
s_col = (n_cols - message_len - 1) // 2
|
||||||
|
window = self._stdscr.derwin(3, message_len+2, s_row, s_col)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for i in range(len(trail)+1):
|
||||||
|
|
||||||
|
if not self._is_running:
|
||||||
|
window.clear()
|
||||||
|
window = None
|
||||||
|
self._stdscr.refresh()
|
||||||
|
return
|
||||||
|
|
||||||
|
window.erase()
|
||||||
|
window.border()
|
||||||
|
window.addstr(1, 1, message + trail[:i])
|
||||||
|
window.refresh()
|
||||||
|
time.sleep(interval)
|
||||||
Reference in New Issue
Block a user