<s> from __future__ import print_function <EOL> from __future__ import division <EOL> import platform <EOL> import re <EOL> import sys <EOL> import webbrowser <EOL> import click <EOL> from . compat import HTMLParser <EOL> from . compat import urlparse <EOL> from . config import Config <EOL> from . lib . haxor . haxor import HackerNewsApi , HTTPError , InvalidItemID , InvalidUserID <EOL> from . lib . pretty_date_time import pretty_date_time <EOL> from . onions import onions <EOL> from . web_viewer import WebViewer <EOL> class HackerNews ( object ) : <EOL> """<STR_LIT>""" <EOL> COMMENT_INDENT = '<STR_LIT:U+0020>' <EOL> COMMENT_UNSEEN = '<STR_LIT>' <EOL> MAX_LIST_INDEX = <NUM_LIT:1000> <EOL> MAX_SNIPPET_LENGTH = <NUM_LIT> <EOL> QUERY_UNSEEN = '<STR_LIT>' <EOL> def __init__ ( self ) : <EOL> self . hacker_news_api = HackerNewsApi ( ) <EOL> try : <EOL> self . html = HTMLParser . HTMLParser ( ) <EOL> except : <EOL> self . html = HTMLParser <EOL> self . config = Config ( ) <EOL> self . web_viewer = WebViewer ( ) <EOL> def ask ( self , limit ) : <EOL> """<STR_LIT>""" <EOL> self . print_items ( <EOL> message = self . headlines_message ( '<STR_LIT>' ) , <EOL> item_ids = self . hacker_news_api . ask_stories ( limit ) ) <EOL> def best ( self , limit ) : <EOL> """<STR_LIT>""" <EOL> self . print_items ( <EOL> message = self . headlines_message ( '<STR_LIT>' ) , <EOL> item_ids = self . hacker_news_api . best_stories ( limit ) ) <EOL> def headlines_message ( self , message ) : <EOL> """<STR_LIT>""" <EOL> return '<STR_LIT>' . format ( message ) <EOL> def hiring_and_freelance ( self , regex_query , post_id ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> item = self . hacker_news_api . get_item ( post_id ) <EOL> self . print_comments ( item , <EOL> regex_query , <EOL> comments_hide_non_matching = True ) <EOL> self . config . save_cache ( ) <EOL> except InvalidItemID : <EOL> self . print_item_not_found ( post_id ) <EOL> except IOError : <EOL> sys . stderr . close ( ) <EOL> def jobs ( self , limit ) : <EOL> """<STR_LIT>""" <EOL> self . print_items ( <EOL> message = self . headlines_message ( '<STR_LIT>' ) , <EOL> item_ids = self . hacker_news_api . job_stories ( limit ) ) <EOL> def new ( self , limit ) : <EOL> """<STR_LIT>""" <EOL> self . print_items ( <EOL> message = self . headlines_message ( '<STR_LIT>' ) , <EOL> item_ids = self . hacker_news_api . new_stories ( limit ) ) <EOL> def onion ( self , limit ) : <EOL> """<STR_LIT>""" <EOL> click . secho ( '<STR_LIT>' . format ( h = self . headlines_message ( '<STR_LIT>' ) ) , <EOL> fg = self . config . clr_title ) <EOL> index = <NUM_LIT:1> <EOL> for onion in onions [ <NUM_LIT:0> : limit ] : <EOL> formatted_index_title = self . format_index_title ( index , onion ) <EOL> click . echo ( formatted_index_title ) <EOL> index += <NUM_LIT:1> <EOL> click . echo ( '<STR_LIT>' ) <EOL> def print_comment ( self , item , regex_query = '<STR_LIT>' , <EOL> comments_hide_non_matching = False , depth = <NUM_LIT:0> ) : <EOL> """<STR_LIT>""" <EOL> if item . text is None : <EOL> return <EOL> header_color = '<STR_LIT>' <EOL> header_color_highlight = '<STR_LIT>' <EOL> header_adornment = '<STR_LIT>' <EOL> if self . config . item_cache is not None and str ( item . item_id ) not in self . config . item_cache : <EOL> header_adornment = self . COMMENT_UNSEEN <EOL> self . config . item_cache . append ( item . item_id ) <EOL> show_comment = True <EOL> if regex_query is not None : <EOL> if self . match_comment_unseen ( regex_query , header_adornment ) or self . match_regex ( item , regex_query ) : <EOL> header_color = header_color_highlight <EOL> else : <EOL> show_comment = False <EOL> formatted_heading , formatted_comment = self . format_comment ( <EOL> item , depth , header_color , header_adornment ) <EOL> if show_comment : <EOL> click . echo ( formatted_heading , color = True ) <EOL> click . echo ( formatted_comment , color = True ) <EOL> elif comments_hide_non_matching : <EOL> click . secho ( '<STR_LIT:.>' , nl = False ) <EOL> else : <EOL> click . echo ( formatted_heading , color = True ) <EOL> num_chars = len ( formatted_comment ) <EOL> if num_chars > self . MAX_SNIPPET_LENGTH : <EOL> num_chars = self . MAX_SNIPPET_LENGTH <EOL> click . echo ( formatted_comment [ <NUM_LIT:0> : num_chars ] + '<STR_LIT>' , color = True ) <EOL> def print_comments ( self , item , regex_query = '<STR_LIT>' , <EOL> comments_hide_non_matching = False , depth = <NUM_LIT:0> ) : <EOL> """<STR_LIT>""" <EOL> self . print_comment ( item , regex_query , comments_hide_non_matching , depth ) <EOL> comment_ids = item . kids <EOL> if not comment_ids : <EOL> return <EOL> for comment_id in comment_ids : <EOL> try : <EOL> comment = self . hacker_news_api . get_item ( comment_id ) <EOL> depth += <NUM_LIT:1> <EOL> self . print_comments ( <EOL> comment , <EOL> regex_query = regex_query , <EOL> comments_hide_non_matching = comments_hide_non_matching , <EOL> depth = depth ) <EOL> depth -= <NUM_LIT:1> <EOL> except ( InvalidItemID , HTTPError ) : <EOL> click . echo ( '<STR_LIT>' ) <EOL> self . print_item_not_found ( comment_id ) <EOL> def format_comment ( self , item , depth , header_color , header_adornment ) : <EOL> """<STR_LIT>""" <EOL> indent = self . COMMENT_INDENT * depth <EOL> formatted_heading = click . style ( <EOL> '<STR_LIT>' . format ( <EOL> i = indent , <EOL> b = item . by , <EOL> d = str ( pretty_date_time ( item . submission_time ) ) , <EOL> h = header_adornment ) , <EOL> fg = header_color ) <EOL> unescaped_text = self . html . unescape ( item . text ) <EOL> regex_paragraph = re . compile ( r'<STR_LIT>' ) <EOL> unescaped_text = regex_paragraph . sub ( click . style ( <EOL> '<STR_LIT>' + indent ) , unescaped_text ) <EOL> regex_url = re . compile ( r'<STR_LIT>' ) <EOL> unescaped_text = regex_url . sub ( click . style ( <EOL> r'<STR_LIT>' , fg = self . config . clr_link ) , unescaped_text ) <EOL> regex_tag = re . compile ( r'<STR_LIT>' ) <EOL> unescaped_text = regex_tag . sub ( click . style ( <EOL> r'<STR_LIT>' , fg = self . config . clr_tag ) , unescaped_text ) <EOL> formatted_comment = click . wrap_text ( text = unescaped_text , <EOL> initial_indent = indent , <EOL> subsequent_indent = indent ) <EOL> return formatted_heading , formatted_comment <EOL> def format_index_title ( self , index , title ) : <EOL> """<STR_LIT>""" <EOL> INDEX_PAD = <NUM_LIT:5> <EOL> formatted_index = '<STR_LIT:U+0020>' + ( str ( index ) + '<STR_LIT:.>' ) . ljust ( INDEX_PAD ) <EOL> formatted_index_title = click . style ( formatted_index , <EOL> fg = self . config . clr_view_index ) <EOL> formatted_index_title += click . style ( title + '<STR_LIT:U+0020>' , <EOL> fg = self . config . clr_title ) <EOL> return formatted_index_title <EOL> def format_item ( self , item , index ) : <EOL> """<STR_LIT>""" <EOL> formatted_item = self . format_index_title ( index , item . title ) <EOL> if item . url is not None : <EOL> netloc = urlparse ( item . url ) . netloc <EOL> netloc = re . sub ( '<STR_LIT>' , '<STR_LIT>' , netloc ) <EOL> formatted_item += click . style ( '<STR_LIT:(>' + netloc + '<STR_LIT:)>' , <EOL> fg = self . config . clr_view_link ) <EOL> formatted_item += '<STR_LIT>' <EOL> formatted_item += click . style ( str ( item . score ) + '<STR_LIT>' , <EOL> fg = self . config . clr_num_points ) <EOL> formatted_item += click . style ( '<STR_LIT>' + item . by + '<STR_LIT:U+0020>' , <EOL> fg = self . config . clr_user ) <EOL> submission_time = str ( pretty_date_time ( item . submission_time ) ) <EOL> formatted_item += click . style ( submission_time + '<STR_LIT:U+0020>' , <EOL> fg = self . config . clr_time ) <EOL> num_comments = str ( item . descendants ) if item . descendants else '<STR_LIT:0>' <EOL> formatted_item += click . style ( '<STR_LIT>' + num_comments + '<STR_LIT>' , <EOL> fg = self . config . clr_num_comments ) <EOL> return formatted_item <EOL> def print_item_not_found ( self , item_id ) : <EOL> """<STR_LIT>""" <EOL> click . secho ( '<STR_LIT>' . format ( item_id ) , fg = '<STR_LIT>' ) <EOL> def print_items ( self , message , item_ids ) : <EOL> """<STR_LIT>""" <EOL> self . config . item_ids = [ ] <EOL> index = <NUM_LIT:1> <EOL> for item_id in item_ids : <EOL> try : <EOL> item = self . hacker_news_api . get_item ( item_id ) <EOL> if item . title : <EOL> formatted_item = self . format_item ( item , index ) <EOL> self . config . item_ids . append ( item . item_id ) <EOL> click . echo ( formatted_item ) <EOL> index += <NUM_LIT:1> <EOL> except InvalidItemID : <EOL> self . print_item_not_found ( item_id ) <EOL> self . config . save_cache ( ) <EOL> if self . config . show_tip : <EOL> click . secho ( self . tip_view ( str ( index - <NUM_LIT:1> ) ) ) <EOL> def tip_view ( self , max_index ) : <EOL> """<STR_LIT>""" <EOL> tip = click . style ( '<STR_LIT>' , <EOL> fg = self . config . clr_tooltip ) <EOL> tip += click . style ( '<STR_LIT>' , fg = self . config . clr_view_index ) <EOL> tip += click . style ( str ( max_index ) , fg = self . config . clr_view_index ) <EOL> tip += click . style ( '<STR_LIT>' , <EOL> fg = self . config . clr_tooltip ) <EOL> tip += click . style ( '<STR_LIT>' , fg = self . config . clr_view_index ) <EOL> tip += click . style ( ( '<STR_LIT>' <EOL> '<STR_LIT>' + '<STR_LIT:\n>' ) , <EOL> fg = self . config . clr_tooltip ) <EOL> return tip <EOL> def match_comment_unseen ( self , regex_query , header_adornment ) : <EOL> """<STR_LIT>""" <EOL> if regex_query == self . QUERY_UNSEEN and header_adornment == self . COMMENT_UNSEEN : <EOL> return True <EOL> else : <EOL> return False <EOL> def match_regex ( self , item , regex_query ) : <EOL> """<STR_LIT>""" <EOL> match_time = re . search ( <EOL> regex_query , <EOL> str ( pretty_date_time ( item . submission_time ) ) ) <EOL> match_user = re . search ( regex_query , item . by ) <EOL> match_text = re . search ( regex_query , item . text ) <EOL> if not match_text and not match_user and not match_time : <EOL> return False <EOL> else : <EOL> return True <EOL> def show ( self , limit ) : <EOL> """<STR_LIT>""" <EOL> self . print_items ( <EOL> message = self . headlines_message ( '<STR_LIT>' ) , <EOL> item_ids = self . hacker_news_api . show_stories ( limit ) ) <EOL> def top ( self , limit ) : <EOL> """<STR_LIT>""" <EOL> self . print_items ( <EOL> message = self . headlines_message ( '<STR_LIT>' ) , <EOL> item_ids = self . hacker_news_api . top_stories ( limit ) ) <EOL> def user ( self , user_id , submission_limit ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> user = self . hacker_news_api . get_user ( user_id ) <EOL> click . secho ( '<STR_LIT>' , nl = False , fg = self . config . clr_general ) <EOL> click . secho ( user_id , fg = self . config . clr_user ) <EOL> click . secho ( '<STR_LIT>' , nl = False , fg = self . config . clr_general ) <EOL> click . secho ( str ( user . created ) , fg = self . config . clr_user ) <EOL> click . secho ( '<STR_LIT>' , nl = False , fg = self . config . clr_general ) <EOL> click . secho ( str ( user . karma ) , fg = self . config . clr_user ) <EOL> self . print_items ( '<STR_LIT>' , <EOL> user . submitted [ <NUM_LIT:0> : submission_limit ] ) <EOL> except InvalidUserID : <EOL> self . print_item_not_found ( user_id ) <EOL> def view ( self , index , comments_query , comments , <EOL> comments_hide_non_matching , browser ) : <EOL> """<STR_LIT>""" <EOL> if self . config . item_ids is None : <EOL> click . secho ( '<STR_LIT>' <EOL> '<STR_LIT>' , <EOL> fg = '<STR_LIT>' ) <EOL> return <EOL> item_id = index <EOL> if index < self . MAX_LIST_INDEX : <EOL> try : <EOL> item_id = self . config . item_ids [ index - <NUM_LIT:1> ] <EOL> except IndexError : <EOL> self . print_item_not_found ( item_id ) <EOL> return <EOL> try : <EOL> item = self . hacker_news_api . get_item ( item_id ) <EOL> except InvalidItemID : <EOL> self . print_item_not_found ( self . config . item_ids [ index - <NUM_LIT:1> ] ) <EOL> return <EOL> if not comments and item . url is None : <EOL> click . secho ( '<STR_LIT>' , <EOL> nl = False , <EOL> fg = self . config . clr_general ) <EOL> comments = True <EOL> if comments : <EOL> comments_url = ( '<STR_LIT>' + <EOL> str ( item . item_id ) ) <EOL> click . secho ( '<STR_LIT>' + comments_url , <EOL> fg = self . config . clr_general ) <EOL> if browser : <EOL> webbrowser . open ( comments_url ) <EOL> else : <EOL> try : <EOL> self . print_comments ( <EOL> item , <EOL> regex_query = comments_query , <EOL> comments_hide_non_matching = comments_hide_non_matching ) <EOL> click . echo ( '<STR_LIT>' ) <EOL> except IOError : <EOL> sys . stderr . close ( ) <EOL> self . config . save_cache ( ) <EOL> else : <EOL> click . secho ( '<STR_LIT>' + item . url + '<STR_LIT>' , <EOL> fg = self . config . clr_general ) <EOL> if browser : <EOL> webbrowser . open ( item . url ) <EOL> else : <EOL> contents = self . web_viewer . generate_url_contents ( item . url ) <EOL> header = click . style ( '<STR_LIT>' + item . url + '<STR_LIT>' , <EOL> fg = self . config . clr_general ) <EOL> contents = header + contents <EOL> contents += click . style ( ( '<STR_LIT>' <EOL> '<STR_LIT>' ) , <EOL> fg = self . config . clr_general ) <EOL> contents += click . style ( ( '<STR_LIT>' <EOL> '<STR_LIT>' ) , <EOL> fg = self . config . clr_general ) <EOL> if platform . system ( ) == '<STR_LIT>' : <EOL> try : <EOL> click . echo ( contents ) <EOL> except IOError : <EOL> sys . stderr . close ( ) <EOL> else : <EOL> click . echo_via_pager ( contents ) <EOL> click . echo ( '<STR_LIT>' ) <EOL> def view_setup ( self , index , comments_regex_query , comments , <EOL> comments_recent , comments_unseen , <EOL> comments_hide_non_matching , clear_cache , browser ) : <EOL> """<STR_LIT>""" <EOL> if comments_regex_query is not None : <EOL> comments = True <EOL> if comments_recent : <EOL> comments_regex_query = '<STR_LIT>' <EOL> comments = True <EOL> if comments_unseen : <EOL> comments_regex_query = self . QUERY_UNSEEN <EOL> comments = True <EOL> if clear_cache : <EOL> self . config . clear_item_cache ( ) <EOL> self . view ( int ( index ) , <EOL> comments_regex_query , <EOL> comments , <EOL> comments_hide_non_matching , <EOL> browser ) </s>
