X-Git-Url: https://vcs.fsf.org/?p=rainbowstream.git;a=blobdiff_plain;f=rainbowstream%2Frainbow.py;h=c4979378e76bed6ac86d0ac9ad9e45d246bad54a;hp=133a31e9e65ee4bbb9e6053fde812a2d9ecff903;hb=39b8e6b3486c527291e91838c9adf139a5c95af6;hpb=f1c1dfea32823074f7b5dcf05d15defb773dd7c0 diff --git a/rainbowstream/rainbow.py b/rainbowstream/rainbow.py index 133a31e..c497937 100644 --- a/rainbowstream/rainbow.py +++ b/rainbowstream/rainbow.py @@ -1,6 +1,3 @@ -""" -Colorful user's timeline stream -""" import os import os.path import sys @@ -41,16 +38,6 @@ def parse_arguments(): '-to', '--timeout', help='Timeout for the stream (seconds).') - parser.add_argument( - '-ht', - '--heartbeat-timeout', - help='Set heartbeat timeout.', - default=90) - parser.add_argument( - '-nb', - '--no-block', - action='store_true', - help='Set stream to non-blocking.') parser.add_argument( '-tt', '--track-keywords', @@ -155,67 +142,6 @@ def init(args): c['IGNORE_LIST'] += build_mute_dict() -def switch(): - """ - Switch stream - """ - try: - target = g['stuff'].split()[0] - # Filter and ignore - args = parse_arguments() - try: - if g['stuff'].split()[-1] == '-f': - guide = 'To ignore an option, just hit Enter key.' - printNicely(light_magenta(guide)) - only = raw_input('Only nicks [Ex: @xxx,@yy]: ') - ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ') - args.filter = filter(None, only.split(',')) - args.ignore = filter(None, ignore.split(',')) - elif g['stuff'].split()[-1] == '-d': - args.filter = c['ONLY_LIST'] - args.ignore = c['IGNORE_LIST'] - except: - printNicely(red('Sorry, wrong format.')) - return - # Public stream - if target == 'public': - keyword = g['stuff'].split()[1] - if keyword[0] == '#': - keyword = keyword[1:] - # Kill old thread - g['stream_stop'] = True - args.track_keywords = keyword - # Start new thread - th = threading.Thread( - target=stream, - args=( - c['PUBLIC_DOMAIN'], - args)) - th.daemon = True - th.start() - # Personal stream - elif target == 'mine': - # Kill old thread - g['stream_stop'] = True - # Start new thread - th = threading.Thread( - target=stream, - args=( - c['USER_DOMAIN'], - args, - g['original_name'])) - th.daemon = True - th.start() - printNicely('') - if args.filter: - printNicely(cyan('Only: ' + str(args.filter))) - if args.ignore: - printNicely(red('Ignore: ' + str(args.ignore))) - printNicely('') - except: - printNicely(red('Sorry I can\'t understand.')) - - def trend(): """ Trend @@ -265,6 +191,37 @@ def home(): printNicely('') +def mentions(): + """ + Mentions timeline + """ + t = Twitter(auth=authen()) + num = c['HOME_TWEET_NUM'] + if g['stuff'].isdigit(): + num = int(g['stuff']) + for tweet in reversed(t.statuses.mentions_timeline(count=num)): + draw(t=tweet) + printNicely('') + + +def whois(): + """ + Show profile of a specific user + """ + t = Twitter(auth=authen()) + screen_name = g['stuff'].split()[0] + if screen_name.startswith('@'): + try: + user = t.users.show( + screen_name=screen_name[1:], + include_entities=False) + show_profile(user) + except: + printNicely(red('Omg no user.')) + else: + printNicely(red('A name should begin with a \'@\'')) + + def view(): """ Friend view @@ -283,17 +240,21 @@ def view(): printNicely(red('A name should begin with a \'@\'')) -def mentions(): +def search(): """ - Mentions timeline + Search """ t = Twitter(auth=authen()) - num = c['HOME_TWEET_NUM'] - if g['stuff'].isdigit(): - num = int(g['stuff']) - for tweet in reversed(t.statuses.mentions_timeline(count=num)): - draw(t=tweet) - printNicely('') + g['stuff'] = g['stuff'].strip() + rel = t.search.tweets(q=g['stuff'])['statuses'] + if rel: + printNicely('Newest tweets:') + for i in reversed(xrange(c['SEARCH_MAX_RECORD'])): + draw(t=rel[i], + keyword=g['stuff']) + printNicely('') + else: + printNicely(magenta('I\'m afraid there is no result')) def tweet(): @@ -322,6 +283,7 @@ def quote(): """ Quote a tweet """ + # Get tweet t = Twitter(auth=authen()) try: id = int(g['stuff'].split()[0]) @@ -330,17 +292,16 @@ def quote(): return tid = c['tweet_dict'][id] tweet = t.statuses.show(id=tid) - screen_name = tweet['user']['screen_name'] - text = tweet['text'] - quote = '\"@' + screen_name + ': ' + text + '\"' - quote = quote.encode('utf8') - notice = light_magenta('Compose mode ') - notice += light_yellow('(Enter nothing will cancel the quote)') - notice += light_magenta(':') - printNicely(notice) - extra = raw_input(quote) - if extra: - t.statuses.update(status=quote + extra) + # Get formater + formater = format_quote(tweet) + if not formater: + return + # Get comment + prefix = light_magenta('Compose your ') + light_green('#comment: ') + comment = raw_input(prefix) + if comment: + quote = comment.join(formater.split('#comment')) + t.statuses.update(status=quote) else: printNicely(light_magenta('No text added.')) @@ -372,9 +333,9 @@ def allretweet(): printNicely('') -def favorite(): +def conversation(): """ - Favorite + Conversation view """ t = Twitter(auth=authen()) try: @@ -383,9 +344,19 @@ def favorite(): printNicely(red('Sorry I can\'t understand.')) return tid = c['tweet_dict'][id] - t.favorites.create(_id=tid, include_entities=False) - printNicely(green('Favorited.')) - draw(t.statuses.show(id=tid)) + tweet = t.statuses.show(id=tid) + limit = c['CONVERSATION_MAX'] + thread_ref = [] + thread_ref.append(tweet) + prev_tid = tweet['in_reply_to_status_id'] + while prev_tid and limit: + limit -= 1 + tweet = t.statuses.show(id=prev_tid) + prev_tid = tweet['in_reply_to_status_id'] + thread_ref.append(tweet) + + for tweet in reversed(thread_ref): + draw(t=tweet) printNicely('') @@ -402,13 +373,13 @@ def reply(): tid = c['tweet_dict'][id] user = t.statuses.show(id=tid)['user']['screen_name'] status = ' '.join(g['stuff'].split()[1:]) - status = '@' + user + ' ' + unc(status) + status = '@' + user + ' ' + str2u(status) t.statuses.update(status=status, in_reply_to_status_id=tid) -def delete(): +def favorite(): """ - Delete + Favorite """ t = Twitter(auth=authen()) try: @@ -417,8 +388,10 @@ def delete(): printNicely(red('Sorry I can\'t understand.')) return tid = c['tweet_dict'][id] - t.statuses.destroy(id=tid) - printNicely(green('Okay it\'s gone.')) + t.favorites.create(_id=tid, include_entities=False) + printNicely(green('Favorited.')) + draw(t.statuses.show(id=tid)) + printNicely('') def unfavorite(): @@ -438,41 +411,19 @@ def unfavorite(): printNicely('') -def search(): - """ - Search - """ - t = Twitter(auth=authen()) - g['stuff'] = g['stuff'].strip() - rel = t.search.tweets(q=g['stuff'])['statuses'] - if rel: - printNicely('Newest tweets:') - for i in reversed(xrange(c['SEARCH_MAX_RECORD'])): - draw(t=rel[i], - keyword=g['stuff']) - printNicely('') - else: - printNicely(magenta('I\'m afraid there is no result')) - - -def message(): +def delete(): """ - Send a direct message + Delete """ t = Twitter(auth=authen()) - user = g['stuff'].split()[0] - if user[0].startswith('@'): - try: - content = g['stuff'].split()[1] - except: - printNicely(red('Sorry I can\'t understand.')) - t.direct_messages.new( - screen_name=user[1:], - text=content - ) - printNicely(green('Message sent.')) - else: - printNicely(red('A name should begin with a \'@\'')) + try: + id = int(g['stuff'].split()[0]) + except: + printNicely(red('Sorry I can\'t understand.')) + return + tid = c['tweet_dict'][id] + t.statuses.destroy(id=tid) + printNicely(green('Okay it\'s gone.')) def show(): @@ -517,49 +468,6 @@ def urlopen(): printNicely(red('Sorry I can\'t open url in this tweet.')) -def ls(): - """ - List friends for followers - """ - t = Twitter(auth=authen()) - # Get name - try: - name = g['stuff'].split()[1] - if name.startswith('@'): - name = name[1:] - else: - printNicely(red('A name should begin with a \'@\'')) - raise Exception('Invalid name') - except: - name = g['original_name'] - # Get list followers or friends - try: - target = g['stuff'].split()[0] - except: - printNicely(red('Omg some syntax is wrong.')) - # Init cursor - d = {'fl': 'followers', 'fr': 'friends'} - next_cursor = -1 - rel = {} - # Cursor loop - while next_cursor != 0: - list = getattr(t, d[target]).list( - screen_name=name, - cursor=next_cursor, - skip_status=True, - include_entities=False, - ) - for u in list['users']: - rel[u['name']] = '@' + u['screen_name'] - next_cursor = list['next_cursor'] - # Print out result - printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.') - for name in rel: - user = ' ' + cycle_color(name) - user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') - printNicely(user) - - def inbox(): """ Inbox direct messages @@ -626,6 +534,26 @@ def sent(): printNicely('') +def message(): + """ + Send a direct message + """ + t = Twitter(auth=authen()) + user = g['stuff'].split()[0] + if user[0].startswith('@'): + try: + content = g['stuff'].split()[1] + except: + printNicely(red('Sorry I can\'t understand.')) + t.direct_messages.new( + screen_name=user[1:], + text=content + ) + printNicely(green('Message sent.')) + else: + printNicely(red('A name should begin with a \'@\'')) + + def trash(): """ Remove message @@ -640,22 +568,47 @@ def trash(): printNicely(green('Message deleted.')) -def whois(): +def ls(): """ - Show profile of a specific user + List friends for followers """ t = Twitter(auth=authen()) - screen_name = g['stuff'].split()[0] - if screen_name.startswith('@'): - try: - user = t.users.show( - screen_name=screen_name[1:], - include_entities=False) - show_profile(user) - except: - printNicely(red('Omg no user.')) - else: - printNicely(red('A name should begin with a \'@\'')) + # Get name + try: + name = g['stuff'].split()[1] + if name.startswith('@'): + name = name[1:] + else: + printNicely(red('A name should begin with a \'@\'')) + raise Exception('Invalid name') + except: + name = g['original_name'] + # Get list followers or friends + try: + target = g['stuff'].split()[0] + except: + printNicely(red('Omg some syntax is wrong.')) + # Init cursor + d = {'fl': 'followers', 'fr': 'friends'} + next_cursor = -1 + rel = {} + # Cursor loop + while next_cursor != 0: + list = getattr(t, d[target]).list( + screen_name=name, + cursor=next_cursor, + skip_status=True, + include_entities=False, + ) + for u in list['users']: + rel[u['name']] = '@' + u['screen_name'] + next_cursor = list['next_cursor'] + # Print out result + printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.') + for name in rel: + user = ' ' + cycle_color(name) + user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') + printNicely(user) def follow(): @@ -1024,7 +977,7 @@ def list_delete(t): """ Delete a list """ - slug = raw_input(light_magenta('Your list that you want to update: ')) + slug = raw_input(light_magenta('Your list that you want to delete: ')) try: t.lists.destroy( slug='-'.join(slug.split()), @@ -1065,6 +1018,67 @@ def twitterlist(): printNicely(red('Please try again.')) +def switch(): + """ + Switch stream + """ + try: + target = g['stuff'].split()[0] + # Filter and ignore + args = parse_arguments() + try: + if g['stuff'].split()[-1] == '-f': + guide = 'To ignore an option, just hit Enter key.' + printNicely(light_magenta(guide)) + only = raw_input('Only nicks [Ex: @xxx,@yy]: ') + ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ') + args.filter = filter(None, only.split(',')) + args.ignore = filter(None, ignore.split(',')) + elif g['stuff'].split()[-1] == '-d': + args.filter = c['ONLY_LIST'] + args.ignore = c['IGNORE_LIST'] + except: + printNicely(red('Sorry, wrong format.')) + return + # Public stream + if target == 'public': + keyword = g['stuff'].split()[1] + if keyword[0] == '#': + keyword = keyword[1:] + # Kill old thread + g['stream_stop'] = True + args.track_keywords = keyword + # Start new thread + th = threading.Thread( + target=stream, + args=( + c['PUBLIC_DOMAIN'], + args)) + th.daemon = True + th.start() + # Personal stream + elif target == 'mine': + # Kill old thread + g['stream_stop'] = True + # Start new thread + th = threading.Thread( + target=stream, + args=( + c['USER_DOMAIN'], + args, + g['original_name'])) + th.daemon = True + th.start() + printNicely('') + if args.filter: + printNicely(cyan('Only: ' + str(args.filter))) + if args.ignore: + printNicely(red('Ignore: ' + str(args.ignore))) + printNicely('') + except: + printNicely(red('Sorry I can\'t understand.')) + + def cal(): """ Unix's command `cal` @@ -1076,6 +1090,33 @@ def cal(): show_calendar(month, date, rel) +def theme(): + """ + List and change theme + """ + if not g['stuff']: + # List themes + for theme in g['themes']: + line = light_magenta(theme) + if c['THEME'] == theme: + line = ' ' * 2 + light_yellow('* ') + line + else: + line = ' ' * 4 + line + printNicely(line) + else: + # Change theme + try: + # Load new theme + c['THEME'] = reload_theme(g['stuff'], c['THEME']) + # Redefine decorated_name + g['decorated_name'] = lambda x: color_func( + c['DECORATED_NAME'])( + '[' + x + ']: ') + printNicely(green('Theme changed.')) + except: + printNicely(red('No such theme exists.')) + + def config(): """ Browse and change config @@ -1140,33 +1181,6 @@ def config(): printNicely(light_magenta('Sorry I can\'s understand.')) -def theme(): - """ - List and change theme - """ - if not g['stuff']: - # List themes - for theme in g['themes']: - line = light_magenta(theme) - if c['THEME'] == theme: - line = ' ' * 2 + light_yellow('* ') + line - else: - line = ' ' * 4 + line - printNicely(line) - else: - # Change theme - try: - # Load new theme - c['THEME'] = reload_theme(g['stuff'], c['THEME']) - # Redefine decorated_name - g['decorated_name'] = lambda x: color_func( - c['DECORATED_NAME'])( - '[' + x + ']: ') - printNicely(green('Theme changed.')) - except: - printNicely(red('No such theme exists.')) - - def help_discover(): """ Discover the world @@ -1212,6 +1226,8 @@ def help_tweets(): usage += s * 2 + \ light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \ light_yellow('[id=12]') + '.\n' + usage += s * 2 + light_green('conversation 12') + ' will show the chain of ' + \ + 'replies prior to the tweet with ' + light_yellow('[id=12]') + '.\n' usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \ light_yellow('oops') + '" to tweet with ' + \ light_yellow('[id=12]') + '.\n' @@ -1357,7 +1373,7 @@ def help(): light_yellow('already') + ' on your personal stream.\n' usage += s + 'Any update from Twitter will show up ' + \ light_yellow('immediately') + '.\n' - usage += s + 'In addtion, following commands are available right now:\n' + usage += s + 'In addition, following commands are available right now:\n' # Twitter help section usage += '\n' usage += s + grey(u'\u266A' + ' Twitter help\n') @@ -1493,6 +1509,7 @@ cmdset = [ 'rt', 'quote', 'allrt', + 'conversation', 'fav', 'rep', 'del', @@ -1536,6 +1553,7 @@ funcset = [ retweet, quote, allretweet, + conversation, favorite, reply, delete, @@ -1592,6 +1610,7 @@ def listen(): [], # retweet [], # quote [], # allretweet + [], # conversation [], # favorite [], # reply [], # delete @@ -1647,19 +1666,19 @@ def listen(): read_history() reset() while True: - # raw_input - if g['prefix']: - line = raw_input(g['decorated_name'](c['PREFIX'])) - else: - line = raw_input() - # Save cmd to compare with readline buffer - g['cmd'] = line.strip() - # Get short cmd to pass to handle function - try: - cmd = line.split()[0] - except: - cmd = '' try: + # raw_input + if g['prefix']: + line = raw_input(g['decorated_name'](c['PREFIX'])) + else: + line = raw_input() + # Save cmd to compare with readline buffer + g['cmd'] = line.strip() + # Get short cmd to pass to handle function + try: + cmd = line.split()[0] + except: + cmd = '' # Lock the semaphore c['lock'] = True # Save cmd to global variable and call process @@ -1673,6 +1692,8 @@ def listen(): g['prefix'] = True # Release the semaphore lock c['lock'] = False + except EOFError: + printNicely('') except Exception: printNicely(red('OMG something is wrong with Twitter right now.')) @@ -1692,8 +1713,8 @@ def stream(domain, args, name='Rainbow Stream'): # These arguments are optional: stream_args = dict( timeout=0.5, # To check g['stream_stop'] after each 0.5 s - block=not args.no_block, - heartbeat_timeout=args.heartbeat_timeout) + block=True, + heartbeat_timeout=c['HEARTBEAT_TIMEOUT'] * 60) # Track keyword query_args = dict() if args.track_keywords: @@ -1725,12 +1746,24 @@ def stream(domain, args, name='Rainbow Stream'): break elif tweet is HeartbeatTimeout: printNicely("-- Heartbeat Timeout --") + guide = light_magenta("You can use ") + \ + light_green("switch") + \ + light_magenta(" command to return to your stream.\n") + guide += light_magenta("Type ") + \ + light_green("h stream") + \ + light_magenta(" for more details.") + printNicely(guide) + sys.stdout.write(g['decorated_name'](c['PREFIX'])) + sys.stdout.flush() + StreamLock.release() + break elif tweet is Hangup: printNicely("-- Hangup --") elif tweet.get('text'): draw( t=tweet, keyword=args.track_keywords, + humanize=False, check_semaphore=True, fil=args.filter, ig=args.ignore, @@ -1743,7 +1776,7 @@ def stream(domain, args, name='Rainbow Stream'): # the 1st character of that word if current_buffer and g['cmd'] != current_buffer: sys.stdout.write( - g['decorated_name'](c['PREFIX']) + unc(current_buffer)) + g['decorated_name'](c['PREFIX']) + str2u(current_buffer)) sys.stdout.flush() elif not c['HIDE_PROMPT']: sys.stdout.write(g['decorated_name'](c['PREFIX']))