16 from io
import BytesIO
17 from twitter
.stream
import TwitterStream
, Timeout
, HeartbeatTimeout
, Hangup
18 from twitter
.api
import *
19 from twitter
.oauth
import OAuth
, read_token_file
20 from twitter
.oauth_dance
import oauth_dance
21 from twitter
.util
import printNicely
23 from pocket
import Pocket
28 from .consumer
import *
29 from .interactive
import *
30 from .c_image
import *
31 from .py3patch
import *
39 StreamLock
= threading
.Lock()
42 def parse_arguments():
46 parser
= argparse
.ArgumentParser(description
=__doc__
or "")
51 help='Default stream after program start. (Default: mine)')
55 help='Timeout for the stream (seconds).')
59 help='Search the stream for specific text.')
63 help='Filter specific screen_name.')
67 help='Ignore specific screen_name.')
72 help='Display all image on terminal.')
77 help='Display images using 24bit color codes.')
81 help='Use HTTP/SOCKS proxy for network connections.')
86 help='HTTP/SOCKS proxy port (Default: 8080).')
91 help='Proxy type (HTTP, SOCKS4, SOCKS5; Default: SOCKS5).')
95 default
=os
.environ
.get('HOME', os
.environ
.get('USERPROFILE', '')) + os
.sep
+ '.rainbow_oauth',
96 help='Specify which OAuth profile to use for twitter. Default: ~/.rainbow_oauth.')
100 default
=os
.environ
.get('HOME', os
.environ
.get('USERPROFILE', '')) + os
.sep
+ '.rainbow_pckt_oauth',
101 help='Specify which OAuth profile to use for pocket. Default: ~/.rainbow_pckt_oauth.')
102 return parser
.parse_args()
105 def proxy_connect(args
):
107 Connect to specified proxy
110 # Setup proxy by monkeypatching the standard lib
111 if args
.proxy_type
.lower() == "socks5" or not args
.proxy_type
:
112 socks
.set_default_proxy(
113 socks
.SOCKS5
, args
.proxy_host
,
114 int(args
.proxy_port
))
115 elif args
.proxy_type
.lower() == "http":
116 socks
.set_default_proxy(
117 socks
.HTTP
, args
.proxy_host
,
118 int(args
.proxy_port
))
119 elif args
.proxy_type
.lower() == "socks4":
120 socks
.set_default_proxy(
121 socks
.SOCKS4
, args
.proxy_host
,
122 int(args
.proxy_port
))
125 magenta('Sorry, wrong proxy type specified! Aborting...'))
127 socket
.socket
= socks
.socksocket
132 Authenticate with Twitter OAuth
134 # When using rainbow stream you must authorize.
135 twitter_credential
= g
['twitter_oauth_path']
136 if not os
.path
.exists(twitter_credential
):
137 oauth_dance('Rainbow Stream',
141 oauth_token
, oauth_token_secret
= read_token_file(twitter_credential
)
151 Authenticate with Pocket OAuth
153 pocket_credential
= g
['pocket_oauth_path']
154 if not os
.path
.exists(pocket_credential
):
155 request_token
= Pocket
.get_request_token(consumer_key
=PCKT_CONSUMER_KEY
)
156 auth_url
= Pocket
.get_auth_url(code
=request_token
, redirect_uri
="/")
157 webbrowser
.open(auth_url
)
158 printNicely(green("*** Press [ENTER] after authorization ***"))
160 user_credentials
= Pocket
.get_credentials(consumer_key
=PCKT_CONSUMER_KEY
, code
=request_token
)
161 access_token
= user_credentials
['access_token']
162 f
= open(pocket_credential
, 'w')
163 f
.write(access_token
)
166 with
open(pocket_credential
, 'r') as f
:
167 access_token
= str(f
.readlines()[0])
170 return Pocket(PCKT_CONSUMER_KEY
, access_token
)
173 def build_mute_dict(dict_data
=False):
177 t
= Twitter(auth
=authen())
180 screen_name_list
= []
183 while next_cursor
!= 0:
184 list = t
.mutes
.users
.list(
185 screen_name
=g
['original_name'],
188 include_entities
=False,
190 screen_name_list
+= ['@' + u
['screen_name'] for u
in list['users']]
191 name_list
+= [u
['name'] for u
in list['users']]
192 next_cursor
= list['next_cursor']
193 # Return dict or list
195 return dict(zip(screen_name_list
, name_list
))
197 return screen_name_list
202 Save traceback when run in debug mode
205 g
['traceback'].append(traceback
.format_exc())
208 def upgrade_center():
210 Check latest and notify to upgrade
213 current
= pkg_resources
.get_distribution('rainbowstream').version
214 url
= 'https://raw.githubusercontent.com/DTVD/rainbowstream/master/setup.py'
215 readme
= requests
.get(url
).text
216 latest
= readme
.split('version = \'')[1].split('\'')[0]
217 g
['using_latest'] = current
== latest
218 if not g
['using_latest']:
219 notice
= light_magenta('RainbowStream latest version is ')
220 notice
+= light_green(latest
)
221 notice
+= light_magenta(' while your current version is ')
222 notice
+= light_yellow(current
) + '\n'
223 notice
+= light_magenta('You should upgrade with ')
224 notice
+= light_green('pip install -U rainbowstream')
226 notice
= light_yellow('You are running latest version (')
227 notice
+= light_green(current
)
228 notice
+= light_yellow(')')
240 ctrl_c_handler
= lambda signum
, frame
: quit()
241 signal
.signal(signal
.SIGINT
, ctrl_c_handler
)
242 # Set OAuth file path (needs to happen before authen is called)
243 g
['twitter_oauth_path'] = args
.twitter_auth
244 g
['pocket_oauth_path'] = args
.pocket_auth
248 t
= Twitter(auth
=authen())
249 credential
= t
.account
.verify_credentials()
250 screen_name
= '@' + credential
['screen_name']
251 name
= credential
['name']
252 g
['id_str'] = credential
['id_str']
253 c
['original_name'] = g
['original_name'] = screen_name
[1:]
254 g
['listname'] = g
['keyword'] = ''
255 g
['PREFIX'] = u2str(emojize(format_prefix()))
256 g
['full_name'] = name
257 g
['decorated_name'] = lambda x
: color_func(
258 c
['DECORATED_NAME'])('[' + x
+ ']: ', rl
=True)
260 files
= os
.listdir(os
.path
.dirname(__file__
) + '/colorset')
261 themes
= [f
.split('.')[0] for f
in files
if f
.split('.')[-1] == 'json']
264 g
['message_threads'] = {}
267 # Debug option default = True
274 # Init tweet dict and message dict
276 c
['message_dict'] = []
278 c
['IMAGE_ON_TERM'] = args
.image_on_term
280 c
['24BIT'] = args
.color_24bit
281 # Check type of ONLY_LIST and IGNORE_LIST
282 if not isinstance(c
['ONLY_LIST'], list):
283 printNicely(red('ONLY_LIST is not a valid list value.'))
285 if not isinstance(c
['IGNORE_LIST'], list):
286 printNicely(red('IGNORE_LIST is not a valid list value.'))
287 c
['IGNORE_LIST'] = []
289 c
['IGNORE_LIST'] += build_mute_dict()
291 pckt
= pckt_authen() if c
['POCKET_SUPPORT'] else None
298 t
= Twitter(auth
=authen())
299 # Get country and town
301 country
= g
['stuff'].split()[0]
305 town
= g
['stuff'].split()[1]
308 avail
= t
.trends
.available()
311 trends
= t
.trends
.place(_id
=1)[0]['trends']
314 for location
in avail
:
315 # Search for country and Town
317 if location
['countryCode'] == country \
318 and location
['placeType']['name'] == 'Town' \
319 and location
['name'] == town
:
320 trends
= t
.trends
.place(_id
=location
['woeid'])[0]['trends']
322 # Search for country only
324 if location
['countryCode'] == country \
325 and location
['placeType']['name'] == 'Country':
326 trends
= t
.trends
.place(_id
=location
['woeid'])[0]['trends']
332 Fetch stream based on since_id
334 t
= Twitter(auth
=authen())
336 num
= c
['HOME_TWEET_NUM']
337 kwargs
= {'count': num
}
340 kwargs
['since_id'] = g
['since_id']
342 kwargs
= add_tweetmode_parameter(kwargs
)
343 result
= t
.statuses
.home_timeline(**kwargs
)
345 g
['since_id'] = result
[0]['id']
346 for tweet
in reversed(result
):
355 t
= Twitter(auth
=authen())
356 num
= c
['HOME_TWEET_NUM']
357 if g
['stuff'].isdigit():
358 num
= int(g
['stuff'])
359 kwargs
= {'count': num
}
360 kwargs
= add_tweetmode_parameter(kwargs
)
361 for tweet
in reversed(t
.statuses
.home_timeline(**kwargs
)):
371 for e
in c
['events']:
375 printNicely(magenta('Nothing at this time.'))
382 t
= Twitter(auth
=authen())
383 num
= c
['HOME_TWEET_NUM']
384 if g
['stuff'].isdigit():
385 num
= int(g
['stuff'])
386 kwargs
= {'count': num
}
387 kwargs
= add_tweetmode_parameter(kwargs
)
388 for tweet
in reversed(t
.statuses
.mentions_timeline(**kwargs
)):
395 Show profile of a specific user
397 t
= Twitter(auth
=authen())
399 screen_name
= g
['stuff'].split()[0]
401 printNicely(red('Sorry I can\'t understand.'))
403 if screen_name
.startswith('@'):
406 screen_name
=screen_name
[1:],
407 include_entities
=False)
411 printNicely(red('No user.'))
413 printNicely(red('A name should begin with a \'@\''))
420 t
= Twitter(auth
=authen())
422 user
= g
['stuff'].split()[0]
424 printNicely(red('Sorry I can\'t understand.'))
428 num
= int(g
['stuff'].split()[1])
430 num
= c
['HOME_TWEET_NUM']
431 kwargs
= {'count': num
, 'screen_name': user
[1:]}
432 kwargs
= add_tweetmode_parameter(kwargs
)
433 for tweet
in reversed(t
.statuses
.user_timeline(**kwargs
)):
437 printNicely(red('A name should begin with a \'@\''))
440 def view_my_tweets():
442 Display user's recent tweets.
444 t
= Twitter(auth
=authen())
446 num
= int(g
['stuff'])
448 num
= c
['HOME_TWEET_NUM']
449 kwargs
= {'count': num
, 'screen_name': g
['original_name']}
450 kwargs
= add_tweetmode_parameter(kwargs
)
451 for tweet
in reversed(
452 t
.statuses
.user_timeline(**kwargs
)):
461 t
= Twitter(auth
=authen())
463 query
= g
['stuff'].strip()
465 printNicely(red('Sorry I can\'t understand.'))
467 type = c
['SEARCH_TYPE']
468 if type not in ['mixed', 'recent', 'popular']:
470 max_record
= c
['SEARCH_MAX_RECORD']
471 count
= min(max_record
, 100)
477 kwargs
= add_tweetmode_parameter(kwargs
)
479 rel
= t
.search
.tweets(**kwargs
)['statuses']
482 printNicely('Newest tweets:')
483 for i
in reversed(xrange(min(len(rel
), count
))):
484 draw(t
=rel
[i
], keyword
=query
)
487 printNicely(magenta('I\'m afraid there is no result'))
494 # Regex to check if tweet contains '--i' pattern
495 pattern
= '(.*) --i (.+)'
496 m
= re
.match(pattern
, g
['stuff'])
500 t
= Twitter(auth
=authen())
501 t
.statuses
.update(status
=g
['stuff'])
503 # A tweet with media items
505 imagePaths
= m
.group(2)
507 # Generating image ids
509 for impath
in imagePaths
.split(','):
510 imagedata
= open(impath
, 'rb').read()
513 t_up
= Twitter(domain
='upload.twitter.com',
515 img_id
= t_up
.media
.upload(media
=imagedata
)["media_id_string"]
516 imageIds
.append(img_id
)
518 # send your tweet with the list of media ids:
519 t
= Twitter(auth
=authen())
520 t
.statuses
.update(status
=body
, media_ids
=",".join(imageIds
))
524 Add new link to Pocket along with tweet id
526 if not c
['POCKET_SUPPORT']:
527 printNicely(yellow('Pocket isn\'t enabled.'))
528 printNicely(yellow('You need to "config POCKET_SUPPORT = true"'))
534 t
= Twitter(auth
=authen())
536 id = int(g
['stuff'].split()[0])
537 tid
= c
['tweet_dict'][id]
539 printNicely(red('Sorry I can\'t understand.'))
542 tweet
= t
.statuses
.show(id=tid
)
544 if len(tweet
['entities']['urls']) > 0:
545 url
= tweet
['entities']['urls'][0]['expanded_url']
547 url
= "https://twitter.com/" + \
548 tweet
['user']['screen_name'] + '/status/' + str(tid
)
552 p
.add(title
=re
.sub(r
'(http:\/\/\S+)', r
'', tweet
['text']),
556 printNicely(red('Something is wrong about your Pocket account,'+ \
557 ' please restart Rainbowstream.'))
558 pocket_credential
= os
.environ
.get(
562 '')) + os
.sep
+ '.rainbow_pckt_oauth'
563 if os
.path
.exists(pocket_credential
):
564 os
.remove(pocket_credential
)
567 printNicely(green('Pocketed !'))
575 t
= Twitter(auth
=authen())
577 id = int(g
['stuff'].split()[0])
579 printNicely(red('Sorry I can\'t understand.'))
581 tid
= c
['tweet_dict'][id]
582 t
.statuses
.retweet(id=tid
, include_entities
=False, trim_user
=True)
590 t
= Twitter(auth
=authen())
592 id = int(g
['stuff'].split()[0])
594 printNicely(red('Sorry I can\'t understand.'))
596 tid
= c
['tweet_dict'][id]
598 kwargs
= add_tweetmode_parameter(kwargs
)
599 tweet
= t
.statuses
.show(**kwargs
)
601 formater
= format_quote(tweet
)
605 prefix
= light_magenta('Compose your ', rl
=True) + \
606 light_green('#comment: ', rl
=True)
607 comment
= raw_input(prefix
)
609 quote
= comment
.join(formater
.split('#comment'))
610 t
.statuses
.update(status
=quote
)
612 printNicely(light_magenta('No text added.'))
619 t
= Twitter(auth
=authen())
622 id = int(g
['stuff'].split()[0])
624 printNicely(red('Sorry I can\'t understand.'))
626 tid
= c
['tweet_dict'][id]
627 # Get display num if exist
629 num
= int(g
['stuff'].split()[1])
631 num
= c
['RETWEETS_SHOW_NUM']
632 # Get result and display
633 kwargs
= {'id': tid
, 'count': num
}
634 kwargs
= add_tweetmode_parameter(kwargs
)
635 rt_ary
= t
.statuses
.retweets(**kwargs
)
637 printNicely(magenta('This tweet has no retweet.'))
639 for tweet
in reversed(rt_ary
):
648 t
= Twitter(auth
=authen())
650 id = int(g
['stuff'].split()[0])
652 printNicely(red('Sorry I can\'t understand.'))
654 tid
= c
['tweet_dict'][id]
656 kwargs
= add_tweetmode_parameter(kwargs
)
657 tweet
= t
.statuses
.show(**kwargs
)
658 limit
= c
['CONVERSATION_MAX']
660 thread_ref
.append(tweet
)
661 prev_tid
= tweet
['in_reply_to_status_id']
662 while prev_tid
and limit
:
664 kwargs
['id'] = prev_tid
665 tweet
= t
.statuses
.show(**kwargs
)
666 prev_tid
= tweet
['in_reply_to_status_id']
667 thread_ref
.append(tweet
)
669 for tweet
in reversed(thread_ref
):
678 t
= Twitter(auth
=authen())
680 id = int(g
['stuff'].split()[0])
682 printNicely(red('Sorry I can\'t understand.'))
684 tid
= c
['tweet_dict'][id]
685 user
= t
.statuses
.show(id=tid
)['user']['screen_name']
686 status
= ' '.join(g
['stuff'].split()[1:])
687 # don't include own username for tweet chains
688 # for details see issue https://github.com/DTVD/rainbowstream/issues/163
689 if user
== g
['original_name']:
690 status
= str2u(status
)
692 status
= '@' + user
+ ' ' + str2u(status
)
693 t
.statuses
.update(status
=status
, in_reply_to_status_id
=tid
)
700 t
= Twitter(auth
=authen())
702 id = int(g
['stuff'].split()[0])
704 printNicely(red('Sorry I can\'t understand.'))
706 tid
= c
['tweet_dict'][id]
707 original_tweet
= t
.statuses
.show(id=tid
)
708 text
= original_tweet
['text']
709 nick_ary
= [original_tweet
['user']['screen_name']]
710 for user
in list(original_tweet
['entities']['user_mentions']):
711 if user
['screen_name'] not in nick_ary \
712 and user
['screen_name'] != g
['original_name']:
713 nick_ary
.append(user
['screen_name'])
714 status
= ' '.join(g
['stuff'].split()[1:])
715 status
= ' '.join(['@' + nick
for nick
in nick_ary
]) + ' ' + str2u(status
)
716 t
.statuses
.update(status
=status
, in_reply_to_status_id
=tid
)
723 t
= Twitter(auth
=authen())
725 id = int(g
['stuff'].split()[0])
727 printNicely(red('Sorry I can\'t understand.'))
729 tid
= c
['tweet_dict'][id]
730 t
.favorites
.create(_id
=tid
, include_entities
=False)
731 printNicely(green('Favorited.'))
733 kwargs
= add_tweetmode_parameter(kwargs
)
734 draw(t
.statuses
.show(**kwargs
))
742 t
= Twitter(auth
=authen())
744 id = int(g
['stuff'].split()[0])
746 printNicely(red('Sorry I can\'t understand.'))
748 tid
= c
['tweet_dict'][id]
749 t
.favorites
.destroy(_id
=tid
)
750 printNicely(green('Okay it\'s unfavorited.'))
752 kwargs
= add_tweetmode_parameter(kwargs
)
753 draw(t
.statuses
.show(**kwargs
))
759 Copy url of a tweet to clipboard
761 t
= Twitter(auth
=authen())
763 id = int(g
['stuff'].split()[0])
764 tid
= c
['tweet_dict'][id]
766 printNicely(red('Tweet id is not valid.'))
769 kwargs
= add_tweetmode_parameter(kwargs
)
770 tweet
= t
.statuses
.show(**kwargs
)
771 url
= 'https://twitter.com/' + \
772 tweet
['user']['screen_name'] + '/status/' + str(tid
)
774 if platform
.system().lower() == 'darwin':
775 os
.system("echo '%s' | pbcopy" % url
)
776 printNicely(green('Copied tweet\'s url to clipboard.'))
778 printNicely('Direct link: ' + yellow(url
))
785 t
= Twitter(auth
=authen())
787 id = int(g
['stuff'].split()[0])
789 printNicely(red('Sorry I can\'t understand.'))
791 tid
= c
['tweet_dict'][id]
792 t
.statuses
.destroy(id=tid
)
793 printNicely(green('Okay it\'s gone.'))
800 t
= Twitter(auth
=authen())
802 target
= g
['stuff'].split()[0]
803 if target
!= 'image':
805 id = int(g
['stuff'].split()[1])
806 tid
= c
['tweet_dict'][id]
807 tweet
= t
.statuses
.show(id=tid
)
808 media
= tweet
['entities']['media']
810 res
= requests
.get(m
['media_url'])
811 img
= Image
.open(BytesIO(res
.content
))
815 printNicely(red('Sorry I can\'t show this image.'))
822 t
= Twitter(auth
=authen())
824 if not g
['stuff'].isdigit():
826 tid
= c
['tweet_dict'][int(g
['stuff'])]
827 tweet
= t
.statuses
.show(id=tid
)
828 urls
= tweet
['entities']['urls']
830 printNicely(light_magenta('No url here @.@!'))
834 expanded_url
= url
['expanded_url']
835 webbrowser
.open(expanded_url
)
838 printNicely(red('Sorry I can\'t open url in this tweet.'))
845 t
= Twitter(auth
=authen())
846 num
= c
['MESSAGES_DISPLAY']
847 if g
['stuff'].isdigit():
850 def inboxFilter(message
):
851 return message
['message_create']['sender_id'] == g
['id_str']
852 def sentFilter(message
):
853 return message
['message_create']['target']['recipient_id'] == g
['id_str']
855 def map_message(message
):
856 message_create
= message
['message_create']
857 sender
= t
.users
.show(id=int(message_create
['sender_id']),include_entities
=False)
858 recipient
= t
.users
.show(id=int(message_create
['target']['recipient_id']),include_entities
=False)
859 message
['sender_screen_name'] = sender
['screen_name']
860 message
['sender_name'] = sender
['name']
861 message
['recipient_screen_name'] = recipient
['screen_name']
862 message
['recipient_name'] = recipient
['name']
863 message
['text'] = message
['message_create']['message_data']['text']
864 message
['created_at'] = message
['created_timestamp']
868 messages
= t
.direct_messages
.events
.list()['events']
869 messages
= list(map(map_message
, messages
))
870 inbox
= list(filter(inboxFilter
, messages
))
871 sent
= list(filter(sentFilter
, messages
))
874 uniq_inbox
= list(set(
875 [(m
['sender_screen_name'], m
['sender_name']) for m
in inbox
]
877 uniq_sent
= list(set(
878 [(m
['recipient_screen_name'], m
['recipient_name']) for m
in sent
]
880 for partner
in uniq_inbox
:
881 inbox_ary
= [m
for m
in inbox
if m
['sender_screen_name'] == partner
[0]]
883 m
for m
in sent
if m
['recipient_screen_name'] == partner
[0]]
884 d
[partner
] = inbox_ary
+ sent_ary
885 for partner
in uniq_sent
:
888 m
for m
in sent
if m
['recipient_screen_name'] == partner
[0]]
889 g
['message_threads'] = print_threads(d
)
894 View a thread of message
897 thread_id
= int(g
['stuff'])
899 g
['message_threads'][thread_id
],
904 printNicely(red('No such thread.'))
909 Send a direct message
911 t
= Twitter(auth
=authen())
913 user
= g
['stuff'].split()[0]
914 if user
[0].startswith('@'):
915 content
= ' '.join(g
['stuff'].split()[1:])
916 t
.direct_messages
.new(
917 screen_name
=user
[1:],
920 printNicely(green('Message sent.'))
922 printNicely(red('A name should begin with a \'@\''))
925 printNicely(red('Sorry I can\'t understand.'))
932 t
= Twitter(auth
=authen())
934 id = int(g
['stuff'].split()[0])
936 printNicely(red('Sorry I can\'t understand.'))
937 mid
= c
['message_dict'][id]
938 t
.direct_messages
.destroy(id=mid
)
939 printNicely(green('Message deleted.'))
944 List friends for followers
946 t
= Twitter(auth
=authen())
949 name
= g
['stuff'].split()[1]
950 if name
.startswith('@'):
953 printNicely(red('A name should begin with a \'@\''))
954 raise Exception('Invalid name')
956 name
= g
['original_name']
957 # Get list followers or friends
959 target
= g
['stuff'].split()[0]
961 printNicely(red('Omg some syntax is wrong.'))
964 d
= {'fl': 'followers', 'fr': 'friends'}
968 printNicely('All ' + d
[target
] + ':')
972 while next_cursor
!= 0:
974 list = getattr(t
, d
[target
]).list(
978 include_entities
=False,
981 for u
in list['users']:
987 + cycle_color( u
['name'] ) \
988 + color_func(c
['TWEET']['nick'])( ' @' \
992 next_cursor
= list['next_cursor']
994 # 300 users means 15 calls to the related API. The rate limit is 15
995 # calls per 15mn periods (see Twitter documentation).
996 if ( number_of_users
% 300 == 0 ):
997 printNicely(light_yellow( 'We reached the limit of Twitter API.' ))
998 printNicely(light_yellow( 'You may need to wait about 15 minutes.' ))
1001 printNicely('All: ' + str(number_of_users
) + ' ' + d
[target
] + '.')
1007 t
= Twitter(auth
=authen())
1008 screen_name
= g
['stuff'].split()[0]
1009 if screen_name
.startswith('@'):
1010 t
.friendships
.create(screen_name
=screen_name
[1:], follow
=True)
1011 printNicely(green('You are following ' + screen_name
+ ' now!'))
1013 printNicely(red('A name should begin with a \'@\''))
1020 t
= Twitter(auth
=authen())
1021 screen_name
= g
['stuff'].split()[0]
1022 if screen_name
.startswith('@'):
1023 t
.friendships
.destroy(
1024 screen_name
=screen_name
[1:],
1025 include_entities
=False)
1026 printNicely(green('Unfollow ' + screen_name
+ ' success!'))
1028 printNicely(red('A name should begin with a \'@\''))
1035 t
= Twitter(auth
=authen())
1037 screen_name
= g
['stuff'].split()[0]
1039 printNicely(red('A name should be specified. '))
1041 if screen_name
.startswith('@'):
1043 rel
= t
.mutes
.users
.create(screen_name
=screen_name
[1:])
1044 if isinstance(rel
, dict):
1045 printNicely(green(screen_name
+ ' is muted.'))
1046 c
['IGNORE_LIST'] += [screen_name
]
1047 c
['IGNORE_LIST'] = list(set(c
['IGNORE_LIST']))
1049 printNicely(red(rel
))
1052 printNicely(red('Something is wrong, can not mute now :('))
1054 printNicely(red('A name should begin with a \'@\''))
1061 t
= Twitter(auth
=authen())
1063 screen_name
= g
['stuff'].split()[0]
1065 printNicely(red('A name should be specified. '))
1067 if screen_name
.startswith('@'):
1069 rel
= t
.mutes
.users
.destroy(screen_name
=screen_name
[1:])
1070 if isinstance(rel
, dict):
1071 printNicely(green(screen_name
+ ' is unmuted.'))
1072 c
['IGNORE_LIST'].remove(screen_name
)
1074 printNicely(red(rel
))
1076 printNicely(red('Maybe you are not muting this person ?'))
1078 printNicely(red('A name should begin with a \'@\''))
1085 # Get dict of muting users
1086 md
= build_mute_dict(dict_data
=True)
1087 printNicely('All: ' + str(len(md
)) + ' people.')
1089 user
= ' ' + cycle_color(md
[name
])
1090 user
+= color_func(c
['TWEET']['nick'])(' ' + name
+ ' ')
1092 # Update from Twitter
1093 c
['IGNORE_LIST'] = [n
for n
in md
]
1100 t
= Twitter(auth
=authen())
1101 screen_name
= g
['stuff'].split()[0]
1102 if screen_name
.startswith('@'):
1104 screen_name
=screen_name
[1:],
1105 include_entities
=False,
1107 printNicely(green('You blocked ' + screen_name
+ '.'))
1109 printNicely(red('A name should begin with a \'@\''))
1116 t
= Twitter(auth
=authen())
1117 screen_name
= g
['stuff'].split()[0]
1118 if screen_name
.startswith('@'):
1120 screen_name
=screen_name
[1:],
1121 include_entities
=False,
1123 printNicely(green('Unblock ' + screen_name
+ ' success!'))
1125 printNicely(red('A name should begin with a \'@\''))
1130 Report a user as a spam account
1132 t
= Twitter(auth
=authen())
1133 screen_name
= g
['stuff'].split()[0]
1134 if screen_name
.startswith('@'):
1135 t
.users
.report_spam(
1136 screen_name
=screen_name
[1:])
1137 printNicely(green('You reported ' + screen_name
+ '.'))
1139 printNicely(red('Sorry I can\'t understand.'))
1147 list_name
= raw_input(
1148 light_magenta('Give me the list\'s name ("@owner/list_name"): ', rl
=True))
1149 # Get list name and owner
1151 owner
, slug
= list_name
.split('/')
1152 if slug
.startswith('@'):
1157 light_magenta('List name should follow "@owner/list_name" format.'))
1158 raise Exception('Wrong list name')
1161 def check_slug(list_name
):
1165 # Get list name and owner
1167 owner
, slug
= list_name
.split('/')
1168 if slug
.startswith('@'):
1173 light_magenta('List name should follow "@owner/list_name" format.'))
1174 raise Exception('Wrong list name')
1181 rel
= t
.lists
.list(screen_name
=g
['original_name'])
1185 printNicely(light_magenta('You belong to no lists :)'))
1192 owner
, slug
= get_slug()
1193 res
= t
.lists
.statuses(
1195 owner_screen_name
=owner
,
1196 count
=c
['LIST_MAX'],
1197 include_entities
=False)
1198 for tweet
in reversed(res
):
1203 def list_members(t
):
1207 owner
, slug
= get_slug()
1211 while next_cursor
!= 0:
1212 m
= t
.lists
.members(
1214 owner_screen_name
=owner
,
1216 include_entities
=False)
1217 for u
in m
['users']:
1218 rel
[u
['name']] = '@' + u
['screen_name']
1219 next_cursor
= m
['next_cursor']
1220 printNicely('All: ' + str(len(rel
)) + ' members.')
1222 user
= ' ' + cycle_color(name
)
1223 user
+= color_func(c
['TWEET']['nick'])(' ' + rel
[name
] + ' ')
1227 def list_subscribers(t
):
1231 owner
, slug
= get_slug()
1235 while next_cursor
!= 0:
1236 m
= t
.lists
.subscribers(
1238 owner_screen_name
=owner
,
1240 include_entities
=False)
1241 for u
in m
['users']:
1242 rel
[u
['name']] = '@' + u
['screen_name']
1243 next_cursor
= m
['next_cursor']
1244 printNicely('All: ' + str(len(rel
)) + ' subscribers.')
1246 user
= ' ' + cycle_color(name
)
1247 user
+= color_func(c
['TWEET']['nick'])(' ' + rel
[name
] + ' ')
1253 Add specific user to a list
1255 owner
, slug
= get_slug()
1257 user_name
= raw_input(
1259 'Give me name of the newbie: ',
1261 if user_name
.startswith('@'):
1262 user_name
= user_name
[1:]
1264 t
.lists
.members
.create(
1266 owner_screen_name
=owner
,
1267 screen_name
=user_name
)
1268 printNicely(green('Added.'))
1271 printNicely(light_magenta('I\'m sorry we can not add him/her.'))
1276 Remove specific user from a list
1278 owner
, slug
= get_slug()
1280 user_name
= raw_input(
1282 'Give me name of the unlucky one: ',
1284 if user_name
.startswith('@'):
1285 user_name
= user_name
[1:]
1287 t
.lists
.members
.destroy(
1289 owner_screen_name
=owner
,
1290 screen_name
=user_name
)
1291 printNicely(green('Gone.'))
1294 printNicely(light_magenta('I\'m sorry we can not remove him/her.'))
1297 def list_subscribe(t
):
1301 owner
, slug
= get_slug()
1304 t
.lists
.subscribers
.create(
1306 owner_screen_name
=owner
)
1307 printNicely(green('Done.'))
1311 light_magenta('I\'m sorry you can not subscribe to this list.'))
1314 def list_unsubscribe(t
):
1318 owner
, slug
= get_slug()
1321 t
.lists
.subscribers
.destroy(
1323 owner_screen_name
=owner
)
1324 printNicely(green('Done.'))
1328 light_magenta('I\'m sorry you can not unsubscribe to this list.'))
1337 while next_cursor
!= 0:
1338 res
= t
.lists
.ownerships(
1339 screen_name
=g
['original_name'],
1342 next_cursor
= res
['next_cursor']
1346 printNicely(light_magenta('You own no lists :)'))
1353 name
= raw_input(light_magenta('New list\'s name: ', rl
=True))
1356 'New list\'s mode (public/private): ',
1358 description
= raw_input(
1360 'New list\'s description: ',
1366 description
=description
)
1367 printNicely(green(name
+ ' list is created.'))
1370 printNicely(red('Oops something is wrong with Twitter :('))
1379 'Your list that you want to update: ',
1383 'Update name (leave blank to unchange): ',
1385 mode
= raw_input(light_magenta('Update mode (public/private): ', rl
=True))
1386 description
= raw_input(light_magenta('Update description: ', rl
=True))
1390 slug
='-'.join(slug
.split()),
1391 owner_screen_name
=g
['original_name'],
1394 description
=description
)
1398 owner_screen_name
=g
['original_name'],
1400 description
=description
)
1401 printNicely(green(slug
+ ' list is updated.'))
1404 printNicely(red('Oops something is wrong with Twitter :('))
1413 'Your list that you want to delete: ',
1417 slug
='-'.join(slug
.split()),
1418 owner_screen_name
=g
['original_name'])
1419 printNicely(green(slug
+ ' list is deleted.'))
1422 printNicely(red('Oops something is wrong with Twitter :('))
1429 t
= Twitter(auth
=authen())
1430 # List all lists or base on action
1432 g
['list_action'] = g
['stuff'].split()[0]
1439 'all_mem': list_members
,
1440 'all_sub': list_subscribers
,
1443 'sub': list_subscribe
,
1444 'unsub': list_unsubscribe
,
1447 'update': list_update
,
1451 return action_ary
[g
['list_action']](t
)
1453 printNicely(red('Please try again.'))
1461 target
= g
['stuff'].split()[0]
1463 args
= parse_arguments()
1465 if g
['stuff'].split()[-1] == '-f':
1466 guide
= 'To ignore an option, just hit Enter key.'
1467 printNicely(light_magenta(guide
))
1468 only
= raw_input('Only nicks [Ex: @xxx,@yy]: ')
1469 ignore
= raw_input('Ignore nicks [Ex: @xxx,@yy]: ')
1470 args
.filter = list(filter(None, only
.split(',')))
1471 args
.ignore
= list(filter(None, ignore
.split(',')))
1473 printNicely(red('Sorry, wrong format.'))
1476 g
['stream_stop'] = True
1478 stuff
= g
['stuff'].split()[1]
1483 'public': spawn_public_stream
,
1484 'list': spawn_list_stream
,
1485 'mine': spawn_personal_stream
,
1487 spawn_dict
.get(target
)(args
, stuff
)
1490 printNicely(red('Sorry I can\'t understand.'))
1495 Unix's command `cal`
1498 rel
= os
.popen('cal').read().split('\n')
1501 show_calendar(month
, date
, rel
)
1506 List and change theme
1510 for theme
in g
['themes']:
1511 line
= light_magenta(theme
)
1512 if c
['THEME'] == theme
:
1513 line
= ' ' * 2 + light_yellow('* ') + line
1515 line
= ' ' * 4 + line
1521 c
['THEME'] = reload_theme(g
['stuff'], c
['THEME'])
1522 # Redefine decorated_name
1523 g
['decorated_name'] = lambda x
: color_func(
1524 c
['DECORATED_NAME'])(
1525 '[' + x
+ ']: ', rl
=True)
1526 printNicely(green('Theme changed.'))
1528 printNicely(red('No such theme exists.'))
1533 Browse and change config
1535 all_config
= get_all_config()
1536 g
['stuff'] = g
['stuff'].strip()
1539 for k
in all_config
:
1541 green(k
) + ': ' + light_yellow(str(all_config
[k
]))
1543 guide
= 'Detailed explanation can be found at ' + \
1544 color_func(c
['TWEET']['link'])(
1545 'http://rainbowstream.readthedocs.org/en/latest/#config-explanation')
1547 # Print specific config
1548 elif len(g
['stuff'].split()) == 1:
1549 if g
['stuff'] in all_config
:
1552 green(k
) + ': ' + light_yellow(str(all_config
[k
]))
1555 printNicely(red('No such config key.'))
1556 # Print specific config's default value
1557 elif len(g
['stuff'].split()) == 2 and g
['stuff'].split()[-1] == 'default':
1558 key
= g
['stuff'].split()[0]
1560 value
= get_default_config(key
)
1561 line
= ' ' * 2 + green(key
) + ': ' + light_magenta(value
)
1565 printNicely(red('Just can not get the default.'))
1566 # Delete specific config key in config file
1567 elif len(g
['stuff'].split()) == 2 and g
['stuff'].split()[-1] == 'drop':
1568 key
= g
['stuff'].split()[0]
1571 printNicely(green('Config key is dropped.'))
1574 printNicely(red('Just can not drop the key.'))
1575 # Set specific config
1576 elif len(g
['stuff'].split()) == 3 and g
['stuff'].split()[1] == '=':
1577 key
= g
['stuff'].split()[0]
1578 value
= g
['stuff'].split()[-1]
1579 if key
== 'THEME' and not validate_theme(value
):
1580 printNicely(red('Invalid theme\'s value.'))
1583 set_config(key
, value
)
1584 # Keys that needs to be apply immediately
1586 c
['THEME'] = reload_theme(value
, c
['THEME'])
1587 g
['decorated_name'] = lambda x
: color_func(
1588 c
['DECORATED_NAME'])('[' + x
+ ']: ', rl
=True)
1589 elif key
== 'PREFIX':
1590 g
['PREFIX'] = u2str(emojize(format_prefix(
1591 listname
=g
['listname'],
1592 keyword
=g
['keyword']
1595 printNicely(green('Updated successfully.'))
1598 printNicely(red('Just can not set the key.'))
1600 printNicely(light_magenta('Sorry I can\'t understand.'))
1603 def help_discover():
1608 # Discover the world
1610 usage
+= s
+ grey(u
'\u266A' + ' Discover the world \n')
1611 usage
+= s
* 2 + light_green('trend') + ' will show global trending topics. ' + \
1612 'You can try ' + light_green('trend US') + ' or ' + \
1613 light_green('trend JP Tokyo') + '.\n'
1614 usage
+= s
* 2 + light_green('home') + ' will show your timeline. ' + \
1615 light_green('home 7') + ' will show 7 tweets.\n'
1616 usage
+= s
* 2 + light_green('me') + ' will show your latest tweets. ' + \
1617 light_green('me 2') + ' will show your last 2 tweets.\n'
1619 light_green('notification') + ' will show your recent notification.\n'
1620 usage
+= s
* 2 + light_green('mentions') + ' will show mentions timeline. ' + \
1621 light_green('mentions 7') + ' will show 7 mention tweets.\n'
1622 usage
+= s
* 2 + light_green('whois @mdo') + ' will show profile of ' + \
1623 magenta('@mdo') + '.\n'
1624 usage
+= s
* 2 + light_green('view @mdo') + \
1625 ' will show ' + magenta('@mdo') + '\'s home.\n'
1626 usage
+= s
* 2 + light_green('s AKB48') + ' will search for "' + \
1627 light_yellow('AKB48') + '" and return 5 newest tweet. ' + \
1628 'Search can be performed with or without hashtag.\n'
1639 usage
+= s
+ grey(u
'\u266A' + ' Tweets \n')
1640 usage
+= s
* 2 + light_green('t oops ') + \
1641 'will tweet "' + light_yellow('oops') + '" immediately.\n' + \
1642 s
* 3 + ' Optionally you can add --i <img1path>[,<img2path>,...] argument, e.g:\n' + \
1643 s
* 3 + light_yellow(' t This tweet has images --i /path/to/test1.png,relative_test.jpg') + '\n'
1645 light_green('rt 12 ') + ' will retweet to tweet with ' + \
1646 light_yellow('[id=12]') + '.\n'
1648 light_green('quote 12 ') + ' will quote the tweet with ' + \
1649 light_yellow('[id=12]') + '. If no extra text is added, ' + \
1650 'the quote will be canceled.\n'
1652 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
1653 light_yellow('[id=12]') + '.\n'
1654 usage
+= s
* 2 + light_green('conversation 12') + ' will show the chain of ' + \
1655 'replies prior to the tweet with ' + light_yellow('[id=12]') + '.\n'
1656 usage
+= s
* 2 + light_green('rep 12 oops') + ' will reply "' + \
1657 light_yellow('oops') + '" to the owner of the tweet with ' + \
1658 light_yellow('[id=12]') + '.\n'
1659 usage
+= s
* 2 + light_green('repall 12 oops') + ' will reply "' + \
1660 light_yellow('oops') + '" to all people in the tweet with ' + \
1661 light_yellow('[id=12]') + '.\n'
1663 light_green('fav 12 ') + ' will favorite the tweet with ' + \
1664 light_yellow('[id=12]') + '.\n'
1666 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
1667 light_yellow('[id=12]') + '.\n'
1669 light_green('share 12 ') + ' will get the direct link of the tweet with ' + \
1670 light_yellow('[id=12]') + '.\n'
1672 light_green('del 12 ') + ' will delete tweet with ' + \
1673 light_yellow('[id=12]') + '.\n'
1674 usage
+= s
* 2 + light_green('show image 12') + ' will show image in tweet with ' + \
1675 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
1676 usage
+= s
* 2 + light_green('open 12') + ' will open url in tweet with ' + \
1677 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
1678 usage
+= s
* 2 + light_green('pt 12') + ' will add tweet with ' + \
1679 light_yellow('[id=12]') + ' in your Pocket list.\n'
1683 def help_messages():
1690 usage
+= s
+ grey(u
'\u266A' + ' Direct messages \n')
1691 usage
+= s
* 2 + light_green('inbox') + ' will show inbox messages. ' + \
1692 light_green('inbox 7') + ' will show newest 7 messages.\n'
1693 usage
+= s
* 2 + light_green('thread 2') + ' will show full thread with ' + \
1694 light_yellow('[thread_id=2]') + '.\n'
1695 usage
+= s
* 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
1696 magenta('@dtvd88') + '.\n'
1697 usage
+= s
* 2 + light_green('trash 5') + ' will remove message with ' + \
1698 light_yellow('[message_id=5]') + '.\n'
1702 def help_friends_and_followers():
1704 Friends and Followers
1707 # Follower and following
1709 usage
+= s
+ grey(u
'\u266A' + ' Friends and followers \n')
1711 light_green('ls fl') + \
1712 ' will list all followers (people who are following you).\n'
1714 light_green('ls fr') + \
1715 ' will list all friends (people who you are following).\n'
1716 usage
+= s
* 2 + light_green('fl @dtvd88') + ' will follow ' + \
1717 magenta('@dtvd88') + '.\n'
1718 usage
+= s
* 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
1719 magenta('@dtvd88') + '.\n'
1720 usage
+= s
* 2 + light_green('mute @dtvd88') + ' will mute ' + \
1721 magenta('@dtvd88') + '.\n'
1722 usage
+= s
* 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
1723 magenta('@dtvd88') + '.\n'
1724 usage
+= s
* 2 + light_green('muting') + ' will list muting users.\n'
1725 usage
+= s
* 2 + light_green('block @dtvd88') + ' will block ' + \
1726 magenta('@dtvd88') + '.\n'
1727 usage
+= s
* 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
1728 magenta('@dtvd88') + '.\n'
1729 usage
+= s
* 2 + light_green('report @dtvd88') + ' will report ' + \
1730 magenta('@dtvd88') + ' as a spam account.\n'
1741 usage
+= s
+ grey(u
'\u266A' + ' Twitter list\n')
1742 usage
+= s
* 2 + light_green('list') + \
1743 ' will show all lists you are belong to.\n'
1744 usage
+= s
* 2 + light_green('list home') + \
1745 ' will show timeline of list. You will be asked for list\'s name.\n'
1746 usage
+= s
* 2 + light_green('list all_mem') + \
1747 ' will show list\'s all members.\n'
1748 usage
+= s
* 2 + light_green('list all_sub') + \
1749 ' will show list\'s all subscribers.\n'
1750 usage
+= s
* 2 + light_green('list add') + \
1751 ' will add specific person to a list owned by you.' + \
1752 ' You will be asked for list\'s name and person\'s name.\n'
1753 usage
+= s
* 2 + light_green('list rm') + \
1754 ' will remove specific person from a list owned by you.' + \
1755 ' You will be asked for list\'s name and person\'s name.\n'
1756 usage
+= s
* 2 + light_green('list sub') + \
1757 ' will subscribe you to a specific list.\n'
1758 usage
+= s
* 2 + light_green('list unsub') + \
1759 ' will unsubscribe you from a specific list.\n'
1760 usage
+= s
* 2 + light_green('list own') + \
1761 ' will show all list owned by you.\n'
1762 usage
+= s
* 2 + light_green('list new') + \
1763 ' will create a new list.\n'
1764 usage
+= s
* 2 + light_green('list update') + \
1765 ' will update a list owned by you.\n'
1766 usage
+= s
* 2 + light_green('list del') + \
1767 ' will delete a list owned by you.\n'
1778 usage
+= s
+ grey(u
'\u266A' + ' Switching streams \n')
1779 usage
+= s
* 2 + light_green('switch public #AKB') + \
1780 ' will switch to public stream and follow "' + \
1781 light_yellow('AKB') + '" keyword.\n'
1782 usage
+= s
* 2 + light_green('switch mine') + \
1783 ' will switch to your personal stream.\n'
1784 usage
+= s
* 2 + light_green('switch mine -f ') + \
1785 ' will prompt to enter the filter.\n'
1786 usage
+= s
* 3 + light_yellow('Only nicks') + \
1787 ' filter will decide nicks will be INCLUDE ONLY.\n'
1788 usage
+= s
* 3 + light_yellow('Ignore nicks') + \
1789 ' filter will decide nicks will be EXCLUDE.\n'
1790 usage
+= s
* 2 + light_green('switch list') + \
1791 ' will switch to a Twitter list\'s stream. You will be asked for list name\n'
1800 h
, w
= os
.popen('stty size', 'r').read().split()
1803 usage
+= s
+ 'Hi boss! I\'m ready to serve you right now!\n'
1804 usage
+= s
+ '-' * (int(w
) - 4) + '\n'
1805 usage
+= s
+ 'You are ' + \
1806 light_yellow('already') + ' on your personal stream.\n'
1807 usage
+= s
+ 'Any update from Twitter will show up ' + \
1808 light_yellow('immediately') + '.\n'
1809 usage
+= s
+ 'In addition, following commands are available right now:\n'
1810 # Twitter help section
1812 usage
+= s
+ grey(u
'\u266A' + ' Twitter help\n')
1813 usage
+= s
* 2 + light_green('h discover') + \
1814 ' will show help for discover commands.\n'
1815 usage
+= s
* 2 + light_green('h tweets') + \
1816 ' will show help for tweets commands.\n'
1817 usage
+= s
* 2 + light_green('h messages') + \
1818 ' will show help for messages commands.\n'
1819 usage
+= s
* 2 + light_green('h friends_and_followers') + \
1820 ' will show help for friends and followers commands.\n'
1821 usage
+= s
* 2 + light_green('h list') + \
1822 ' will show help for list commands.\n'
1823 usage
+= s
* 2 + light_green('h stream') + \
1824 ' will show help for stream commands.\n'
1827 usage
+= s
+ grey(u
'\u266A' + ' Smart shell\n')
1828 usage
+= s
* 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
1829 'will be evaluate by Python interpreter.\n'
1830 usage
+= s
* 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
1831 ' for current month.\n'
1834 usage
+= s
+ grey(u
'\u266A' + ' Config \n')
1835 usage
+= s
* 2 + light_green('theme') + ' will list available theme. ' + \
1836 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
1837 ' theme immediately.\n'
1838 usage
+= s
* 2 + light_green('config') + ' will list all config.\n'
1840 light_green('config ASCII_ART') + ' will output current value of ' +\
1841 light_yellow('ASCII_ART') + ' config key.\n'
1843 light_green('config TREND_MAX default') + ' will output default value of ' + \
1844 light_yellow('TREND_MAX') + ' config key.\n'
1846 light_green('config CUSTOM_CONFIG drop') + ' will drop ' + \
1847 light_yellow('CUSTOM_CONFIG') + ' config key.\n'
1849 light_green('config IMAGE_ON_TERM = true') + ' will set value of ' + \
1850 light_yellow('IMAGE_ON_TERM') + ' config key to ' + \
1851 light_yellow('True') + '.\n'
1854 usage
+= s
+ grey(u
'\u266A' + ' Screening \n')
1855 usage
+= s
* 2 + light_green('h') + ' will show this help again.\n'
1856 usage
+= s
* 2 + light_green('p') + ' will pause the stream.\n'
1857 usage
+= s
* 2 + light_green('r') + ' will unpause the stream.\n'
1858 usage
+= s
* 2 + light_green('c') + ' will clear the screen.\n'
1859 usage
+= s
* 2 + light_green('v') + ' will show version info.\n'
1860 usage
+= s
* 2 + light_green('q') + ' will quit.\n'
1863 usage
+= s
+ '-' * (int(w
) - 4) + '\n'
1864 usage
+= s
+ 'Have fun and hang tight! \n'
1867 'discover': help_discover
,
1868 'tweets': help_tweets
,
1869 'messages': help_messages
,
1870 'friends_and_followers': help_friends_and_followers
,
1872 'stream': help_stream
,
1877 lambda: printNicely(red('No such command.'))
1885 Pause stream display
1888 printNicely(green('Stream is paused'))
1896 printNicely(green('Stream is running back now'))
1912 printNicely(green('See you next time :)'))
1920 Reset prefix of line
1923 if c
.get('USER_JSON_ERROR'):
1924 printNicely(red('Your ~/.rainbow_config.json is messed up:'))
1925 printNicely(red('>>> ' + c
['USER_JSON_ERROR']))
1927 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
1930 printNicely(str(eval(g
['cmd'])))
1985 # Handle function set
2040 return dict(zip(cmdset
, funcset
)).get(cmd
, reset
)
2045 Listen to user's input
2050 ['public', 'mine', 'list'], # switch
2059 [], # view_my_tweets
2070 ['image'], # show image
2072 ['fl', 'fr'], # list
2074 [i
for i
in g
['message_threads']], # sent
2099 [key
for key
in dict(get_all_config())], # config
2100 g
['themes'], # theme
2105 'friends_and_followers',
2117 init_interactive_shell(d
)
2124 # Only use PREFIX as a string with raw_input
2125 line
= raw_input(g
['decorated_name'](g
['PREFIX']))
2128 # Save cmd to compare with readline buffer
2129 g
['cmd'] = line
.strip()
2130 # Get short cmd to pass to handle function
2132 cmd
= line
.split()[0]
2135 # Lock the semaphore
2137 # Save cmd to global variable and call process
2138 g
['stuff'] = ' '.join(line
.split()[1:])
2139 # Check tweet length
2140 # Process the command
2143 if cmd
in ['switch', 't', 'rt', 'rep']:
2149 except TwitterHTTPError
as e
:
2150 detail_twitter_error(e
)
2152 # Release the semaphore lock
2156 def reconn_notice():
2158 Notice when Hangup or Timeout
2160 guide
= light_magenta('You can use ') + \
2161 light_green('switch') + \
2162 light_magenta(' command to return to your stream.\n')
2163 guide
+= light_magenta('Type ') + \
2164 light_green('h stream') + \
2165 light_magenta(' for more details.')
2167 sys
.stdout
.write(g
['decorated_name'](g
['PREFIX']))
2171 def stream(domain
, args
, name
='Rainbow Stream'):
2177 c
['USER_DOMAIN']: name
,
2178 c
['PUBLIC_DOMAIN']: args
.track_keywords
or 'Global',
2179 c
['SITE_DOMAIN']: name
,
2182 ascii_art(art_dict
.get(domain
, name
))
2183 # These arguments are optional:
2185 timeout
=0.5, # To check g['stream_stop'] after each 0.5 s
2187 heartbeat_timeout
=c
['HEARTBEAT_TIMEOUT'] * 60)
2190 if args
.track_keywords
:
2191 query_args
['track'] = args
.track_keywords
2195 time
.sleep(polling_time
)
2198 def spawn_public_stream(args
, keyword
=None):
2200 Spawn a new public stream
2202 # Only set keyword if specified
2204 if keyword
[0] == '#':
2205 keyword
= keyword
[1:]
2206 args
.track_keywords
= keyword
2207 g
['keyword'] = keyword
2209 g
['keyword'] = 'Global'
2210 g
['PREFIX'] = u2str(emojize(format_prefix(keyword
=g
['keyword'])))
2213 th
= threading
.Thread(
2222 def spawn_list_stream(args
, stuff
=None):
2224 Spawn a new list stream
2227 owner
, slug
= check_slug(stuff
)
2229 owner
, slug
= get_slug()
2231 # Force python 2 not redraw readline buffer
2232 listname
= '/'.join([owner
, slug
])
2233 # Set the listname variable
2234 # and reset tracked keyword
2235 g
['listname'] = listname
2237 g
['PREFIX'] = g
['cmd'] = u2str(emojize(format_prefix(
2238 listname
=g
['listname']
2240 printNicely(light_yellow('getting list members ...'))
2242 t
= Twitter(auth
=authen())
2245 while next_cursor
!= 0:
2246 m
= t
.lists
.members(
2248 owner_screen_name
=owner
,
2250 include_entities
=False)
2251 for u
in m
['users']:
2252 members
.append('@' + u
['screen_name'])
2253 next_cursor
= m
['next_cursor']
2254 printNicely(light_yellow('... done.'))
2255 # Build thread filter array
2256 args
.filter = members
2258 th
= threading
.Thread(
2268 printNicely(cyan('Include: ' + str(len(args
.filter)) + ' people.'))
2270 printNicely(red('Ignore: ' + str(len(args
.ignore
)) + ' people.'))
2274 def spawn_personal_stream(args
, stuff
=None):
2276 Spawn a new personal stream
2278 # Reset the tracked keyword and listname
2279 g
['keyword'] = g
['listname'] = ''
2281 g
['PREFIX'] = u2str(emojize(format_prefix()))
2283 th
= threading
.Thread(
2288 g
['original_name']))
2298 args
= parse_arguments()
2302 # Twitter API connection problem
2303 except TwitterHTTPError
as e
:
2306 magenta('We have connection problem with twitter REST API right now :('))
2307 detail_twitter_error(e
)
2310 # Proxy connection problem
2311 except (socks
.ProxyConnectionError
, URLError
):
2313 magenta('There seems to be a connection problem.'))
2315 magenta('You might want to check your proxy settings (host, port and type)!'))
2319 # Spawn stream thread
2320 target
= args
.stream
.split()[0]
2321 if target
== 'mine':
2322 spawn_personal_stream(args
)
2325 stuff
= args
.stream
.split()[1]
2329 'public': spawn_public_stream
,
2330 'list': spawn_list_stream
,
2332 spawn_dict
.get(target
)(args
, stuff
)
2334 # Start listen process