X-Git-Url: https://vcs.fsf.org/?p=rainbowstream.git;a=blobdiff_plain;f=rainbowstream%2Frainbow.py;h=3ecd9a6920a1b15af61956f73435352143d77a34;hp=ed3d07fdf61cb0bb658a9560bf8f4651090ccc3f;hb=2d34102927771794440b85c6b15c4a1d35f23dd0;hpb=ddb1e61513a7c363b5eb7a12e8fb296077aaaaa0 diff --git a/rainbowstream/rainbow.py b/rainbowstream/rainbow.py index ed3d07f..3ecd9a6 100644 --- a/rainbowstream/rainbow.py +++ b/rainbowstream/rainbow.py @@ -10,6 +10,7 @@ import signal import argparse import time import requests +import webbrowser from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup from twitter.api import * @@ -36,6 +37,7 @@ cmdset = [ 'mentions', 't', 'rt', + 'quote', 'allrt', 'fav', 'rep', @@ -44,6 +46,7 @@ cmdset = [ 's', 'mes', 'show', + 'open', 'ls', 'inbox', 'sent', @@ -57,6 +60,7 @@ cmdset = [ 'block', 'unblock', 'report', + 'list', 'cal', 'theme', 'h', @@ -137,8 +141,9 @@ def get_decorated_name(): g['decorated_name'] = color_func(c['DECORATED_NAME'])('[' + name + ']: ') g['ascii_art'] = True - files = os.listdir('rainbowstream/colorset') + files = os.listdir(os.path.dirname(__file__)+'/colorset') themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json'] + themes += ['custom'] g['themes'] = themes db.theme_store(c['theme']) @@ -309,6 +314,33 @@ def retweet(): t.statuses.retweet(id=tid, include_entities=False, trim_user=True) +def quote(): + """ + Quote a tweet + """ + t = Twitter(auth=authen()) + try: + id = int(g['stuff'].split()[0]) + except: + printNicely(red('Sorry I can\'t understand.')) + return + tid = db.rainbow_to_tweet_query(id)[0].tweet_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) + else: + printNicely(light_magenta('No text added.')) + + def allretweet(): """ List all retweet @@ -463,7 +495,27 @@ def show(): printNicely(red('Sorry I can\'t show this image.')) -def list(): +def urlopen(): + """ + Open url + """ + t = Twitter(auth=authen()) + try: + if not g['stuff'].isdigit(): + return + tid = db.rainbow_to_tweet_query(g['stuff'])[0].tweet_id + tweet = t.statuses.show(id=tid) + link_ary = [u for u in tweet['text'].split() if u.startswith('http://')] + if not link_ary: + printNicely(light_magenta('No url here @.@!')) + return + for link in link_ary: + webbrowser.open(link) + except: + printNicely(red('Sorry I can\'t open url in this tweet.')) + + +def ls(): """ List friends for followers """ @@ -499,9 +551,10 @@ def list(): rel[u['name']] = '@' + u['screen_name'] next_cursor = list['next_cursor'] # Print out result - printNicely('All: ' + str(len(rel)) + ' people.') + printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.') for name in rel: - user = ' ' + cycle_color(name) + grey(' ' + rel[name] + ' ') + user = ' ' + cycle_color(name) + user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') printNicely(user) @@ -693,7 +746,8 @@ def muting(): # Print out result printNicely('All: ' + str(len(rel)) + ' people.') for name in rel: - user = ' ' + cycle_color(name) + grey(' ' + rel[name] + ' ') + user = ' ' + cycle_color(name) + user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') printNicely(user) @@ -743,6 +797,139 @@ def report(): printNicely(red('Sorry I can\'t understand.')) +def show_lists(t): + """ + list list + """ + rel = t.lists.list(screen_name=g['original_name']) + if rel: + print_list(rel) + else: + printNicely(light_magenta('You belong to no lists :)')) + + +def list_home(t): + """ + List home + """ + # Get list name + list_name = raw_input(light_magenta('Give me the list\'s name: ')) + if not list_name: + printNicely(light_magenta('No list specified.')) + return + # Print timeline + l = db.list_name_to_id_query(list_name)[0] + res = t.lists.statuses( + list_id = l.list_id, + count = c['LIST_MAX'], + include_entities=False) + for tweet in res: + draw(t=tweet) + printNicely('') + + +def list_members(t): + """ + List members + """ + # Get list name + list_name = raw_input(light_magenta('Give me the list\'s name: ')) + if not list_name: + printNicely(light_magenta('No list specified.')) + return + # Members + l = db.list_name_to_id_query(list_name)[0] + rel = {} + next_cursor = -1 + while next_cursor != 0 : + m = t.lists.members( + list_id = l.list_id, + cursor = next_cursor, + include_entities=False) + for u in m['users']: + rel[u['name']] = '@' + u['screen_name'] + next_cursor = m['next_cursor'] + printNicely('All: ' + str(len(rel)) + ' members.') + for name in rel: + user = ' ' + cycle_color(name) + user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') + printNicely(user) + + +def list_subscribers(t): + """ + List subscribers + """ + # Get list name + list_name = raw_input(light_magenta('Give me the list\'s name: ')) + if not list_name: + printNicely(light_magenta('No list specified.')) + return + # Subscribers + l = db.list_name_to_id_query(list_name)[0] + rel = {} + next_cursor = -1 + while next_cursor != 0 : + m = t.lists.subscribers( + list_id = l.list_id, + cursor = next_cursor, + include_entities=False) + for u in m['users']: + rel[u['name']] = '@' + u['screen_name'] + next_cursor = m['next_cursor'] + printNicely('All: ' + str(len(rel)) + ' subscribers.') + for name in rel: + user = ' ' + cycle_color(name) + user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') + printNicely(user) + + +def list_remove(t): + """ + Remove specific user from a list + """ + # Get list name + list_name = raw_input(light_magenta('Give me the list\'s name: ')) + if not list_name: + printNicely(light_magenta('No list specified.')) + return + # Remove + l = db.list_name_to_id_query(list_name)[0] + user_name = raw_input(light_magenta('Give me the name of unlucky man: ')) + try: + t.lists.members.destroy( + list_id = l.list_id, + screen_name = user_name) + printNicely(light_green('Okay he\'s gone :)')) + except: + printNicely(light_magenta('I\'m sorry we can not remove him.')) + + +def list(): + """ + Twitter's list + """ + t = Twitter(auth=authen()) + # List all lists or base on action + try: + g['list_action'] = g['stuff'].split()[0] + except: + show_lists(t) + return + + # Sub function + action_ary = { + 'home': list_home, + 'all_mem': list_members, + 'all_sub': list_subscribers, + 'rm': list_remove, + } + try: + return action_ary[g['list_action']](t) + except: + printNicely(red('Sorry I can\'t understand.')) + + def cal(): """ Unix's command `cal` @@ -750,17 +937,8 @@ def cal(): # Format rel = os.popen('cal').read().split('\n') month = rel.pop(0) - month = random_rainbow(month) date = rel.pop(0) - date = ' '.join([cycle_color(i) for i in date.split(' ')]) - today = str(int(os.popen('date +\'%d\'').read().strip())) - # Display - printNicely(month) - printNicely(date) - for line in rel: - ary = line.split(' ') - ary = map(lambda x: on_grey(x) if x == today else grey(x), ary) - printNicely(' '.join(ary)) + show_calendar(month, date, rel) def theme(): @@ -774,12 +952,14 @@ def theme(): # Detect custom config if theme == 'custom': line += light_magenta('custom') - exists = db.theme_query() - themes = [t.theme_name for t in exists] - if themes[0] == 'custom': - line += light_magenta(' (applied)') + custom_path = os.environ.get( + 'HOME', + os.environ.get('USERPROFILE', + '')) + os.sep + '.rainbow_config.json' + if not os.path.exists(custom_path): + line += light_magenta(' (create your own config file at ~/.rainbow_config.json)') else: - line += light_magenta(' (not specified)') + line += light_magenta(' (loaded)') else: line += light_magenta(theme) if c['theme'] == theme : @@ -787,44 +967,51 @@ def theme(): else: line = ' '*4 + line printNicely(line) + elif g['stuff'] == 'current_as_default': + # Set default + path = os.path.dirname(__file__) + '/colorset/init' + f = open(path,'w') + f.write(c['theme']) + f.close() + os.system('chmod 777 ' + path) + printNicely(light_green('Okay it will be applied from next time :)')) else: # Change theme try: # Load new config - new_config = 'rainbowstream/colorset/' + g['stuff'] + '.json' + if g['stuff'] != 'custom': + new_config = os.path.dirname(__file__) + '/colorset/' + g['stuff'] + '.json' + else: + new_config = os.environ.get( + 'HOME',os.environ.get( + 'USERPROFILE', + '')) + os.sep + '.rainbow_config.json' new_config = load_config(new_config) if new_config: for nc in new_config: c[nc] = new_config[nc] - # Update db + # Update db and reset colors db.theme_update(g['stuff']) + c['theme'] = g['stuff'] + reset_cycle() g['decorated_name'] = color_func( c['DECORATED_NAME'])( '[@' + g['original_name'] + ']: ') printNicely(green('Theme changed.')) except: - printNicely(red('Sorry, config file is broken!')) + if g['stuff'] == 'custom': + printNicely(red('~/.rainbow_config.json is not exists!')) + else: + printNicely(red('No such theme exists.')) -def help(): +def help_discover(): """ - Help + Discover the world """ s = ' ' * 2 - h, w = os.popen('stty size', 'r').read().split() - - # Start - usage = '\n' - usage += s + 'Hi boss! I\'m ready to serve you right now!\n' - usage += s + '-' * (int(w) - 4) + '\n' - usage += s + 'You are ' + \ - 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' - # Discover the world - usage += '\n' + usage = '\n' usage += s + grey(u'\u266A' + ' Discover the world \n') usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \ 'You can try ' + light_green('trend US') + ' or ' + \ @@ -839,15 +1026,26 @@ def help(): ' will show ' + magenta('@mdo') + '\'s home.\n' usage += s * 2 + light_green('s #AKB48') + ' will search for "' + \ light_yellow('AKB48') + '" and return 5 newest tweet.\n' + printNicely(usage) + +def help_tweets(): + """ + Tweets + """ + s = ' ' * 2 # Tweet - usage += '\n' + usage = '\n' usage += s + grey(u'\u266A' + ' Tweets \n') usage += s * 2 + light_green('t oops ') + \ 'will tweet "' + light_yellow('oops') + '" immediately.\n' usage += s * 2 + \ light_green('rt 12 ') + ' will retweet to tweet with ' + \ light_yellow('[id=12]') + '.\n' + usage += s * 2 + \ + light_green('quote 12 ') + ' will quote the tweet with ' + \ + light_yellow('[id=12]') + '. If no extra text is added, ' + \ + 'the quote will be canceled.\n' usage += s * 2 + \ light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \ light_yellow('[id=12]') + '.\n' @@ -865,9 +1063,18 @@ def help(): light_yellow('[id=12]') + '.\n' usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \ light_yellow('[id=12]') + ' in your OS\'s image viewer.\n' + usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \ + light_yellow('[id=12]') + ' in your OS\'s default browser.\n' + printNicely(usage) + +def help_messages(): + """ + Messages + """ + s = ' ' * 2 # Direct message - usage += '\n' + usage = '\n' usage += s + grey(u'\u266A' + ' Direct messages \n') usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \ light_green('inbox 7') + ' will show newest 7 messages.\n' @@ -877,10 +1084,17 @@ def help(): magenta('@dtvd88') + '.\n' usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \ light_yellow('[message_id=5]') + '.\n' + printNicely(usage) + +def help_friends_and_followers(): + """ + Friends and Followers + """ + s = ' ' * 2 # Follower and following - usage += '\n' - usage += s + grey(u'\u266A' + ' Fiends and followers \n') + usage = '\n' + usage += s + grey(u'\u266A' + ' Friends and followers \n') usage += s * 2 + \ light_green('ls fl') + \ ' will list all followers (people who are following you).\n' @@ -902,9 +1116,38 @@ def help(): magenta('@dtvd88') + '.\n' usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \ magenta('@dtvd88') + ' as a spam account.\n' + printNicely(usage) + +def help_list(): + """ + Lists + """ + s = ' ' * 2 + # Twitter list + usage = '\n' + usage += s + grey(u'\u266A' + ' Twitter list\n') + usage += s * 2 + light_green('list') + \ + ' will show all lists you are belong to.\n' + usage += s * 2 + light_green('list home') + \ + ' will show timeline of list. You will be asked for list\'s name\n' + usage += s * 2 + light_green('list mem') + \ + ' will show list\'s all members.\n' + usage += s * 2 + light_green('list sub') + \ + ' will show list\'s all subscribers.\n' + usage += s * 2 + light_green('list rm') + \ + ' will remove specific person from a list owned by you.' + \ + ' You will be asked for list\'s name and person\'s name.\n' + printNicely(usage) + + +def help_stream(): + """ + Stream switch + """ + s = ' ' * 2 # Switch - usage += '\n' + usage = '\n' usage += s + grey(u'\u266A' + ' Switching streams \n') usage += s * 2 + light_green('switch public #AKB') + \ ' will switch to public stream and follow "' + \ @@ -919,6 +1162,41 @@ def help(): ' filter will decide nicks will be EXCLUDE.\n' usage += s * 2 + light_green('switch mine -d') + \ ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n' + printNicely(usage) + + +def help(): + """ + Help + """ + s = ' ' * 2 + h, w = os.popen('stty size', 'r').read().split() + + # Start + usage = '\n' + usage += s + 'Hi boss! I\'m ready to serve you right now!\n' + usage += s + '-' * (int(w) - 4) + '\n' + usage += s + 'You are ' + \ + 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' + + # Twitter help section + usage += '\n' + usage += s + grey(u'\u266A' + ' Twitter help\n') + usage += s * 2 + light_green('h discover') + \ + ' will show help for discover commands.\n' + usage += s * 2 + light_green('h tweets') + \ + ' will show help for tweets commands.\n' + usage += s * 2 + light_green('h messages') + \ + ' will show help for messages commands.\n' + usage += s * 2 + light_green('h friends_and_followers') + \ + ' will show help for friends and followers commands.\n' + usage += s * 2 + light_green('h list') + \ + ' will show help for list commands.\n' + usage += s * 2 + light_green('h stream') + \ + ' will show help for stream commands.\n' # Smart shell usage += '\n' @@ -942,7 +1220,20 @@ def help(): usage += '\n' usage += s + '-' * (int(w) - 4) + '\n' usage += s + 'Have fun and hang tight! \n' - printNicely(usage) + + # Show help + d = { + 'discover' : help_discover, + 'tweets' : help_tweets, + 'messages' : help_messages, + 'friends_and_followers' : help_friends_and_followers, + 'list' : help_list, + 'stream' : help_stream, + } + if g['stuff']: + d[g['stuff'].strip()]() + else: + printNicely(usage) def clear(): @@ -970,8 +1261,8 @@ def reset(): printNicely(magenta('Need tips ? Type "h" and hit Enter key!')) g['reset'] = False try: - printNicely(eval(g['cmd'])) - except: + printNicely(str(eval(g['cmd']))) + except Exception: pass @@ -989,6 +1280,7 @@ def process(cmd): mentions, tweet, retweet, + quote, allretweet, favorite, reply, @@ -997,7 +1289,8 @@ def process(cmd): search, message, show, - list, + urlopen, + ls, inbox, sent, trash, @@ -1010,6 +1303,7 @@ def process(cmd): block, unblock, report, + list, cal, theme, help, @@ -1033,6 +1327,7 @@ def listen(): [], # mentions [], # tweet [], # retweet + [], # quote [], # allretweet [], # favorite [], # reply @@ -1041,6 +1336,7 @@ def listen(): ['#'], # search ['@'], # message ['image'], # show image + [''], # open url ['fl', 'fr'], # list [], # inbox [], # sent @@ -1054,9 +1350,10 @@ def listen(): ['@'], # block ['@'], # unblock ['@'], # report + ['home','all_mem','all_sub','rm'], # list [], # cal - g['themes'], # theme - [], # help + g['themes'] + ['current_as_default'], # theme + ['discover','tweets','messages','friends_and_followers','list','stream'], # help [], # clear [], # quit ] @@ -1078,8 +1375,7 @@ def listen(): try: g['stuff'] = ' '.join(line.split()[1:]) process(cmd)() - except Exception as e: - print e + except Exception: printNicely(red('OMG something is wrong with Twitter right now.')) # Not redisplay prefix if cmd in ['switch', 't', 'rt', 'rep']: @@ -1119,18 +1415,18 @@ def stream(domain, args, name='Rainbow Stream'): domain=domain, **stream_args) - if domain == c['USER_DOMAIN']: - tweet_iter = stream.user(**query_args) - elif domain == c['SITE_DOMAIN']: - tweet_iter = stream.site(**query_args) - else: - if args.track_keywords: - tweet_iter = stream.statuses.filter(**query_args) + try: + if domain == c['USER_DOMAIN']: + tweet_iter = stream.user(**query_args) + elif domain == c['SITE_DOMAIN']: + tweet_iter = stream.site(**query_args) else: - tweet_iter = stream.statuses.sample() + if args.track_keywords: + tweet_iter = stream.statuses.filter(**query_args) + else: + tweet_iter = stream.statuses.sample() - # Iterate over the stream. - try: + # Iterate over the stream. for tweet in tweet_iter: if tweet is None: printNicely("-- None --") @@ -1148,10 +1444,10 @@ def stream(domain, args, name='Rainbow Stream'): fil=args.filter, ig=args.ignore, ) - except: + except TwitterHTTPError: + printNicely('') printNicely( - magenta("I'm afraid we have problem with twitter'S maximum connection.")) - printNicely(magenta("Let's try again later.")) + magenta("We have maximum connection problem with twitter'stream API right now :(")) def fly(): @@ -1160,11 +1456,22 @@ def fly(): """ # Spawn stream process args = parse_arguments() - get_decorated_name() + try: + get_decorated_name() + + except TwitterHTTPError: + printNicely('') + printNicely( + magenta("I'm afraid we have maximum connection problem with twitter right now :(")) + printNicely(magenta("Let's try again later.")) + save_history() + os.system('rm -rf rainbow.db') + sys.exit() + p = Process( target=stream, args=( - c['USER_DOMAIN'], + c['USER_DOMAIN'], args, g['original_name'])) p.start()