fixed issue 19, stream is thread now
[rainbowstream.git] / rainbowstream / rainbow.py
1 """
2 Colorful user's timeline stream
3 """
4 from multiprocessing import Process
5
6 import os
7 import os.path
8 import sys
9 import signal
10 import argparse
11 import time
12 import threading
13 import requests
14 import webbrowser
15
16 from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
17 from twitter.api import *
18 from twitter.oauth import OAuth, read_token_file
19 from twitter.oauth_dance import oauth_dance
20 from twitter.util import printNicely
21
22 from .draw import *
23 from .colors import *
24 from .config import *
25 from .consumer import *
26 from .interactive import *
27 from .db import *
28 from .c_image import *
29 from .py3patch import *
30
31 # Global values
32 g = {}
33
34 # Database
35 db = RainbowDB()
36
37 # Lock for streams
38
39 StreamLock = threading.Lock()
40
41 # Commands
42 cmdset = [
43 'switch',
44 'trend',
45 'home',
46 'view',
47 'mentions',
48 't',
49 'rt',
50 'quote',
51 'allrt',
52 'fav',
53 'rep',
54 'del',
55 'ufav',
56 's',
57 'mes',
58 'show',
59 'open',
60 'ls',
61 'inbox',
62 'sent',
63 'trash',
64 'whois',
65 'fl',
66 'ufl',
67 'mute',
68 'unmute',
69 'muting',
70 'block',
71 'unblock',
72 'report',
73 'list',
74 'cal',
75 'config',
76 'theme',
77 'h',
78 'p',
79 'r',
80 'c',
81 'q'
82 ]
83
84
85 def parse_arguments():
86 """
87 Parse the arguments
88 """
89 parser = argparse.ArgumentParser(description=__doc__ or "")
90 parser.add_argument(
91 '-to',
92 '--timeout',
93 help='Timeout for the stream (seconds).')
94 parser.add_argument(
95 '-ht',
96 '--heartbeat-timeout',
97 help='Set heartbeat timeout.',
98 default=90)
99 parser.add_argument(
100 '-nb',
101 '--no-block',
102 action='store_true',
103 help='Set stream to non-blocking.')
104 parser.add_argument(
105 '-tt',
106 '--track-keywords',
107 help='Search the stream for specific text.')
108 parser.add_argument(
109 '-fil',
110 '--filter',
111 help='Filter specific screen_name.')
112 parser.add_argument(
113 '-ig',
114 '--ignore',
115 help='Ignore specific screen_name.')
116 parser.add_argument(
117 '-iot',
118 '--image-on-term',
119 action='store_true',
120 help='Display all image on terminal.')
121 return parser.parse_args()
122
123
124 def authen():
125 """
126 Authenticate with Twitter OAuth
127 """
128 # When using rainbow stream you must authorize.
129 twitter_credential = os.environ.get(
130 'HOME',
131 os.environ.get(
132 'USERPROFILE',
133 '')) + os.sep + '.rainbow_oauth'
134 if not os.path.exists(twitter_credential):
135 oauth_dance("Rainbow Stream",
136 CONSUMER_KEY,
137 CONSUMER_SECRET,
138 twitter_credential)
139 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
140 return OAuth(
141 oauth_token,
142 oauth_token_secret,
143 CONSUMER_KEY,
144 CONSUMER_SECRET)
145
146
147 def init(args):
148 """
149 Init function
150 """
151 # Handle Ctrl C
152 ctrl_c_handler = lambda signum, frame: quit()
153 signal.signal(signal.SIGINT, ctrl_c_handler)
154 # Get name
155 t = Twitter(auth=authen())
156 name = '@' + t.account.verify_credentials()['screen_name']
157 if not get_config('PREFIX'):
158 set_config('PREFIX', name)
159 g['original_name'] = name[1:]
160 g['decorated_name'] = lambda x: color_func(
161 c['DECORATED_NAME'])(
162 '[' + x + ']: ')
163 # Theme init
164 files = os.listdir(os.path.dirname(__file__) + '/colorset')
165 themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json']
166 g['themes'] = themes
167 db.theme_store(c['THEME'])
168 # Semaphore init
169 db.semaphore_store(False, False)
170 # Image on term
171 c['IMAGE_ON_TERM'] = args.image_on_term
172
173
174 def switch():
175 """
176 Switch stream
177 """
178 try:
179 target = g['stuff'].split()[0]
180 # Filter and ignore
181 args = parse_arguments()
182 try:
183 if g['stuff'].split()[-1] == '-f':
184 guide = 'To ignore an option, just hit Enter key.'
185 printNicely(light_magenta(guide))
186 only = raw_input('Only nicks [Ex: @xxx,@yy]: ')
187 ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ')
188 args.filter = filter(None, only.split(','))
189 args.ignore = filter(None, ignore.split(','))
190 elif g['stuff'].split()[-1] == '-d':
191 args.filter = c['ONLY_LIST']
192 args.ignore = c['IGNORE_LIST']
193 except:
194 printNicely(red('Sorry, wrong format.'))
195 return
196 # Public stream
197 if target == 'public':
198 keyword = g['stuff'].split()[1]
199 if keyword[0] == '#':
200 keyword = keyword[1:]
201 # Kill old thread
202 g['stream_stop'] = True
203 args.track_keywords = keyword
204 # Start new thread
205 th = threading.Thread(target=stream, args=(c['PUBLIC_DOMAIN'], args))
206 th.daemon = True
207 th.start()
208 # Personal stream
209 elif target == 'mine':
210 # Kill old thread
211 g['stream_stop'] = True
212 # Start new thread
213 th = threading.Thread(target=stream, args=(c['USER_DOMAIN'], args, g['original_name']))
214 th.daemon = True
215 th.start()
216 g['prefix'] = True
217 printNicely('')
218 if args.filter:
219 printNicely(cyan('Only: ' + str(args.filter)))
220 if args.ignore:
221 printNicely(red('Ignore: ' + str(args.ignore)))
222 printNicely('')
223 except Exception:
224 printNicely(red('Sorry I can\'t understand.'))
225
226
227 def trend():
228 """
229 Trend
230 """
231 t = Twitter(auth=authen())
232 # Get country and town
233 try:
234 country = g['stuff'].split()[0]
235 except:
236 country = ''
237 try:
238 town = g['stuff'].split()[1]
239 except:
240 town = ''
241 avail = t.trends.available()
242 # World wide
243 if not country:
244 trends = t.trends.place(_id=1)[0]['trends']
245 print_trends(trends)
246 else:
247 for location in avail:
248 # Search for country and Town
249 if town:
250 if location['countryCode'] == country \
251 and location['placeType']['name'] == 'Town' \
252 and location['name'] == town:
253 trends = t.trends.place(_id=location['woeid'])[0]['trends']
254 print_trends(trends)
255 # Search for country only
256 else:
257 if location['countryCode'] == country \
258 and location['placeType']['name'] == 'Country':
259 trends = t.trends.place(_id=location['woeid'])[0]['trends']
260 print_trends(trends)
261
262
263 def home():
264 """
265 Home
266 """
267 t = Twitter(auth=authen())
268 num = c['HOME_TWEET_NUM']
269 if g['stuff'].isdigit():
270 num = int(g['stuff'])
271 for tweet in reversed(t.statuses.home_timeline(count=num)):
272 draw(t=tweet)
273 printNicely('')
274
275
276 def view():
277 """
278 Friend view
279 """
280 t = Twitter(auth=authen())
281 user = g['stuff'].split()[0]
282 if user[0] == '@':
283 try:
284 num = int(g['stuff'].split()[1])
285 except:
286 num = c['HOME_TWEET_NUM']
287 for tweet in reversed(t.statuses.user_timeline(count=num, screen_name=user[1:])):
288 draw(t=tweet)
289 printNicely('')
290 else:
291 printNicely(red('A name should begin with a \'@\''))
292
293
294 def mentions():
295 """
296 Mentions timeline
297 """
298 t = Twitter(auth=authen())
299 num = c['HOME_TWEET_NUM']
300 if g['stuff'].isdigit():
301 num = int(g['stuff'])
302 for tweet in reversed(t.statuses.mentions_timeline(count=num)):
303 draw(t=tweet)
304 printNicely('')
305
306
307 def tweet():
308 """
309 Tweet
310 """
311 t = Twitter(auth=authen())
312 t.statuses.update(status=g['stuff'])
313
314
315 def retweet():
316 """
317 ReTweet
318 """
319 t = Twitter(auth=authen())
320 try:
321 id = int(g['stuff'].split()[0])
322 except:
323 printNicely(red('Sorry I can\'t understand.'))
324 return
325 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
326 t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
327
328
329 def quote():
330 """
331 Quote a tweet
332 """
333 t = Twitter(auth=authen())
334 try:
335 id = int(g['stuff'].split()[0])
336 except:
337 printNicely(red('Sorry I can\'t understand.'))
338 return
339 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
340 tweet = t.statuses.show(id=tid)
341 screen_name = tweet['user']['screen_name']
342 text = tweet['text']
343 quote = '\"@' + screen_name + ': ' + text + '\"'
344 quote = quote.encode('utf8')
345 notice = light_magenta('Compose mode ')
346 notice += light_yellow('(Enter nothing will cancel the quote)')
347 notice += light_magenta(':')
348 printNicely(notice)
349 extra = raw_input(quote)
350 if extra:
351 t.statuses.update(status=quote + extra)
352 else:
353 printNicely(light_magenta('No text added.'))
354
355
356 def allretweet():
357 """
358 List all retweet
359 """
360 t = Twitter(auth=authen())
361 # Get rainbow id
362 try:
363 id = int(g['stuff'].split()[0])
364 except:
365 printNicely(red('Sorry I can\'t understand.'))
366 return
367 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
368 # Get display num if exist
369 try:
370 num = int(g['stuff'].split()[1])
371 except:
372 num = c['RETWEETS_SHOW_NUM']
373 # Get result and display
374 rt_ary = t.statuses.retweets(id=tid, count=num)
375 if not rt_ary:
376 printNicely(magenta('This tweet has no retweet.'))
377 return
378 for tweet in reversed(rt_ary):
379 draw(t=tweet)
380 printNicely('')
381
382
383 def favorite():
384 """
385 Favorite
386 """
387 t = Twitter(auth=authen())
388 try:
389 id = int(g['stuff'].split()[0])
390 except:
391 printNicely(red('Sorry I can\'t understand.'))
392 return
393 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
394 t.favorites.create(_id=tid, include_entities=False)
395 printNicely(green('Favorited.'))
396 draw(t.statuses.show(id=tid))
397 printNicely('')
398
399
400 def reply():
401 """
402 Reply
403 """
404 t = Twitter(auth=authen())
405 try:
406 id = int(g['stuff'].split()[0])
407 except:
408 printNicely(red('Sorry I can\'t understand.'))
409 return
410 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
411 user = t.statuses.show(id=tid)['user']['screen_name']
412 status = ' '.join(g['stuff'].split()[1:])
413 status = '@' + user + ' ' + status.decode('utf-8')
414 t.statuses.update(status=status, in_reply_to_status_id=tid)
415
416
417 def delete():
418 """
419 Delete
420 """
421 t = Twitter(auth=authen())
422 try:
423 rid = int(g['stuff'].split()[0])
424 except:
425 printNicely(red('Sorry I can\'t understand.'))
426 return
427 tid = db.rainbow_to_tweet_query(rid)[0].tweet_id
428 t.statuses.destroy(id=tid)
429 printNicely(green('Okay it\'s gone.'))
430
431
432 def unfavorite():
433 """
434 Unfavorite
435 """
436 t = Twitter(auth=authen())
437 try:
438 id = int(g['stuff'].split()[0])
439 except:
440 printNicely(red('Sorry I can\'t understand.'))
441 return
442 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
443 t.favorites.destroy(_id=tid)
444 printNicely(green('Okay it\'s unfavorited.'))
445 draw(t.statuses.show(id=tid))
446 printNicely('')
447
448
449 def search():
450 """
451 Search
452 """
453 t = Twitter(auth=authen())
454 g['stuff'] = g['stuff'].strip()
455 rel = t.search.tweets(q=g['stuff'])['statuses']
456 if rel:
457 printNicely('Newest tweets:')
458 for i in reversed(xrange(c['SEARCH_MAX_RECORD'])):
459 draw(t=rel[i],
460 keyword=g['stuff'])
461 printNicely('')
462 else:
463 printNicely(magenta('I\'m afraid there is no result'))
464
465
466 def message():
467 """
468 Send a direct message
469 """
470 t = Twitter(auth=authen())
471 user = g['stuff'].split()[0]
472 if user[0].startswith('@'):
473 try:
474 content = g['stuff'].split()[1]
475 except:
476 printNicely(red('Sorry I can\'t understand.'))
477 t.direct_messages.new(
478 screen_name=user[1:],
479 text=content
480 )
481 printNicely(green('Message sent.'))
482 else:
483 printNicely(red('A name should begin with a \'@\''))
484
485
486 def show():
487 """
488 Show image
489 """
490 t = Twitter(auth=authen())
491 try:
492 target = g['stuff'].split()[0]
493 if target != 'image':
494 return
495 id = int(g['stuff'].split()[1])
496 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
497 tweet = t.statuses.show(id=tid)
498 media = tweet['entities']['media']
499 for m in media:
500 res = requests.get(m['media_url'])
501 img = Image.open(BytesIO(res.content))
502 img.show()
503 except:
504 printNicely(red('Sorry I can\'t show this image.'))
505
506
507 def urlopen():
508 """
509 Open url
510 """
511 t = Twitter(auth=authen())
512 try:
513 if not g['stuff'].isdigit():
514 return
515 tid = db.rainbow_to_tweet_query(g['stuff'])[0].tweet_id
516 tweet = t.statuses.show(id=tid)
517 link_ary = [
518 u for u in tweet['text'].split() if u.startswith('http://')]
519 if not link_ary:
520 printNicely(light_magenta('No url here @.@!'))
521 return
522 for link in link_ary:
523 webbrowser.open(link)
524 except:
525 printNicely(red('Sorry I can\'t open url in this tweet.'))
526
527
528 def ls():
529 """
530 List friends for followers
531 """
532 t = Twitter(auth=authen())
533 # Get name
534 try:
535 name = g['stuff'].split()[1]
536 if name.startswith('@'):
537 name = name[1:]
538 else:
539 printNicely(red('A name should begin with a \'@\''))
540 raise Exception('Invalid name')
541 except:
542 name = g['original_name']
543 # Get list followers or friends
544 try:
545 target = g['stuff'].split()[0]
546 except:
547 printNicely(red('Omg some syntax is wrong.'))
548 # Init cursor
549 d = {'fl': 'followers', 'fr': 'friends'}
550 next_cursor = -1
551 rel = {}
552 # Cursor loop
553 while next_cursor != 0:
554 list = getattr(t, d[target]).list(
555 screen_name=name,
556 cursor=next_cursor,
557 skip_status=True,
558 include_entities=False,
559 )
560 for u in list['users']:
561 rel[u['name']] = '@' + u['screen_name']
562 next_cursor = list['next_cursor']
563 # Print out result
564 printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.')
565 for name in rel:
566 user = ' ' + cycle_color(name)
567 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
568 printNicely(user)
569
570
571 def inbox():
572 """
573 Inbox direct messages
574 """
575 t = Twitter(auth=authen())
576 num = c['MESSAGES_DISPLAY']
577 rel = []
578 if g['stuff'].isdigit():
579 num = g['stuff']
580 cur_page = 1
581 # Max message per page is 20 so we have to loop
582 while num > 20:
583 rel = rel + t.direct_messages(
584 count=20,
585 page=cur_page,
586 include_entities=False,
587 skip_status=False
588 )
589 num -= 20
590 cur_page += 1
591 rel = rel + t.direct_messages(
592 count=num,
593 page=cur_page,
594 include_entities=False,
595 skip_status=False
596 )
597 # Display
598 printNicely('Inbox: newest ' + str(len(rel)) + ' messages.')
599 for m in reversed(rel):
600 print_message(m)
601 printNicely('')
602
603
604 def sent():
605 """
606 Sent direct messages
607 """
608 t = Twitter(auth=authen())
609 num = c['MESSAGES_DISPLAY']
610 rel = []
611 if g['stuff'].isdigit():
612 num = int(g['stuff'])
613 cur_page = 1
614 # Max message per page is 20 so we have to loop
615 while num > 20:
616 rel = rel + t.direct_messages.sent(
617 count=20,
618 page=cur_page,
619 include_entities=False,
620 skip_status=False
621 )
622 num -= 20
623 cur_page += 1
624 rel = rel + t.direct_messages.sent(
625 count=num,
626 page=cur_page,
627 include_entities=False,
628 skip_status=False
629 )
630 # Display
631 printNicely('Sent: newest ' + str(len(rel)) + ' messages.')
632 for m in reversed(rel):
633 print_message(m)
634 printNicely('')
635
636
637 def trash():
638 """
639 Remove message
640 """
641 t = Twitter(auth=authen())
642 try:
643 rid = int(g['stuff'].split()[0])
644 except:
645 printNicely(red('Sorry I can\'t understand.'))
646 mid = db.rainbow_to_message_query(rid)[0].message_id
647 t.direct_messages.destroy(id=mid)
648 printNicely(green('Message deleted.'))
649
650
651 def whois():
652 """
653 Show profile of a specific user
654 """
655 t = Twitter(auth=authen())
656 screen_name = g['stuff'].split()[0]
657 if screen_name.startswith('@'):
658 try:
659 user = t.users.show(
660 screen_name=screen_name[1:],
661 include_entities=False)
662 show_profile(user)
663 except:
664 printNicely(red('Omg no user.'))
665 else:
666 printNicely(red('A name should begin with a \'@\''))
667
668
669 def follow():
670 """
671 Follow a user
672 """
673 t = Twitter(auth=authen())
674 screen_name = g['stuff'].split()[0]
675 if screen_name.startswith('@'):
676 t.friendships.create(screen_name=screen_name[1:], follow=True)
677 printNicely(green('You are following ' + screen_name + ' now!'))
678 else:
679 printNicely(red('A name should begin with a \'@\''))
680
681
682 def unfollow():
683 """
684 Unfollow a user
685 """
686 t = Twitter(auth=authen())
687 screen_name = g['stuff'].split()[0]
688 if screen_name.startswith('@'):
689 t.friendships.destroy(
690 screen_name=screen_name[1:],
691 include_entities=False)
692 printNicely(green('Unfollow ' + screen_name + ' success!'))
693 else:
694 printNicely(red('A name should begin with a \'@\''))
695
696
697 def mute():
698 """
699 Mute a user
700 """
701 t = Twitter(auth=authen())
702 try:
703 screen_name = g['stuff'].split()[0]
704 except:
705 printNicely(red('A name should be specified. '))
706 return
707 if screen_name.startswith('@'):
708 rel = t.mutes.users.create(screen_name=screen_name[1:])
709 if isinstance(rel, dict):
710 printNicely(green(screen_name + ' is muted.'))
711 else:
712 printNicely(red(rel))
713 else:
714 printNicely(red('A name should begin with a \'@\''))
715
716
717 def unmute():
718 """
719 Unmute a user
720 """
721 t = Twitter(auth=authen())
722 try:
723 screen_name = g['stuff'].split()[0]
724 except:
725 printNicely(red('A name should be specified. '))
726 return
727 if screen_name.startswith('@'):
728 rel = t.mutes.users.destroy(screen_name=screen_name[1:])
729 if isinstance(rel, dict):
730 printNicely(green(screen_name + ' is unmuted.'))
731 else:
732 printNicely(red(rel))
733 else:
734 printNicely(red('A name should begin with a \'@\''))
735
736
737 def muting():
738 """
739 List muting user
740 """
741 t = Twitter(auth=authen())
742 # Init cursor
743 next_cursor = -1
744 rel = {}
745 # Cursor loop
746 while next_cursor != 0:
747 list = t.mutes.users.list(
748 screen_name=g['original_name'],
749 cursor=next_cursor,
750 skip_status=True,
751 include_entities=False,
752 )
753 for u in list['users']:
754 rel[u['name']] = '@' + u['screen_name']
755 next_cursor = list['next_cursor']
756 # Print out result
757 printNicely('All: ' + str(len(rel)) + ' people.')
758 for name in rel:
759 user = ' ' + cycle_color(name)
760 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
761 printNicely(user)
762
763
764 def block():
765 """
766 Block a user
767 """
768 t = Twitter(auth=authen())
769 screen_name = g['stuff'].split()[0]
770 if screen_name.startswith('@'):
771 t.blocks.create(
772 screen_name=screen_name[1:],
773 include_entities=False,
774 skip_status=True)
775 printNicely(green('You blocked ' + screen_name + '.'))
776 else:
777 printNicely(red('A name should begin with a \'@\''))
778
779
780 def unblock():
781 """
782 Unblock a user
783 """
784 t = Twitter(auth=authen())
785 screen_name = g['stuff'].split()[0]
786 if screen_name.startswith('@'):
787 t.blocks.destroy(
788 screen_name=screen_name[1:],
789 include_entities=False,
790 skip_status=True)
791 printNicely(green('Unblock ' + screen_name + ' success!'))
792 else:
793 printNicely(red('A name should begin with a \'@\''))
794
795
796 def report():
797 """
798 Report a user as a spam account
799 """
800 t = Twitter(auth=authen())
801 screen_name = g['stuff'].split()[0]
802 if screen_name.startswith('@'):
803 t.users.report_spam(
804 screen_name=screen_name[1:])
805 printNicely(green('You reported ' + screen_name + '.'))
806 else:
807 printNicely(red('Sorry I can\'t understand.'))
808
809
810 def get_slug():
811 """
812 Get Slug Decorator
813 """
814 # Get list name
815 list_name = raw_input(light_magenta('Give me the list\'s name: '))
816 # Get list name and owner
817 try:
818 owner, slug = list_name.split('/')
819 if slug.startswith('@'):
820 slug = slug[1:]
821 return owner, slug
822 except:
823 printNicely(
824 light_magenta('List name should follow "@owner/list_name" format.'))
825 raise Exception('Wrong list name')
826
827
828 def show_lists(t):
829 """
830 List list
831 """
832 rel = t.lists.list(screen_name=g['original_name'])
833 if rel:
834 print_list(rel)
835 else:
836 printNicely(light_magenta('You belong to no lists :)'))
837
838
839 def list_home(t):
840 """
841 List home
842 """
843 owner, slug = get_slug()
844 res = t.lists.statuses(
845 slug=slug,
846 owner_screen_name=owner,
847 count=c['LIST_MAX'],
848 include_entities=False)
849 for tweet in res:
850 draw(t=tweet)
851 printNicely('')
852
853
854 def list_members(t):
855 """
856 List members
857 """
858 owner, slug = get_slug()
859 # Get members
860 rel = {}
861 next_cursor = -1
862 while next_cursor != 0:
863 m = t.lists.members(
864 slug=slug,
865 owner_screen_name=owner,
866 cursor=next_cursor,
867 include_entities=False)
868 for u in m['users']:
869 rel[u['name']] = '@' + u['screen_name']
870 next_cursor = m['next_cursor']
871 printNicely('All: ' + str(len(rel)) + ' members.')
872 for name in rel:
873 user = ' ' + cycle_color(name)
874 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
875 printNicely(user)
876
877
878 def list_subscribers(t):
879 """
880 List subscribers
881 """
882 owner, slug = get_slug()
883 # Get subscribers
884 rel = {}
885 next_cursor = -1
886 while next_cursor != 0:
887 m = t.lists.subscribers(
888 slug=slug,
889 owner_screen_name=owner,
890 cursor=next_cursor,
891 include_entities=False)
892 for u in m['users']:
893 rel[u['name']] = '@' + u['screen_name']
894 next_cursor = m['next_cursor']
895 printNicely('All: ' + str(len(rel)) + ' subscribers.')
896 for name in rel:
897 user = ' ' + cycle_color(name)
898 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
899 printNicely(user)
900
901
902 def list_add(t):
903 """
904 Add specific user to a list
905 """
906 owner, slug = get_slug()
907 # Add
908 user_name = raw_input(light_magenta('Give me name of the newbie: '))
909 if user_name.startswith('@'):
910 user_name = user_name[1:]
911 try:
912 t.lists.members.create(
913 slug=slug,
914 owner_screen_name=owner,
915 screen_name=user_name)
916 printNicely(green('Added.'))
917 except:
918 printNicely(light_magenta('I\'m sorry we can not add him/her.'))
919
920
921 def list_remove(t):
922 """
923 Remove specific user from a list
924 """
925 owner, slug = get_slug()
926 # Remove
927 user_name = raw_input(light_magenta('Give me name of the unlucky one: '))
928 if user_name.startswith('@'):
929 user_name = user_name[1:]
930 try:
931 t.lists.members.destroy(
932 slug=slug,
933 owner_screen_name=owner,
934 screen_name=user_name)
935 printNicely(green('Gone.'))
936 except:
937 printNicely(light_magenta('I\'m sorry we can not remove him/her.'))
938
939
940 def list_subscribe(t):
941 """
942 Subscribe to a list
943 """
944 owner, slug = get_slug()
945 # Subscribe
946 try:
947 t.lists.subscribers.create(
948 slug=slug,
949 owner_screen_name=owner)
950 printNicely(green('Done.'))
951 except:
952 printNicely(
953 light_magenta('I\'m sorry you can not subscribe to this list.'))
954
955
956 def list_unsubscribe(t):
957 """
958 Unsubscribe a list
959 """
960 owner, slug = get_slug()
961 # Subscribe
962 try:
963 t.lists.subscribers.destroy(
964 slug=slug,
965 owner_screen_name=owner)
966 printNicely(green('Done.'))
967 except:
968 printNicely(
969 light_magenta('I\'m sorry you can not unsubscribe to this list.'))
970
971
972 def list_own(t):
973 """
974 List own
975 """
976 rel = []
977 next_cursor = -1
978 while next_cursor != 0:
979 res = t.lists.ownerships(
980 screen_name=g['original_name'],
981 cursor=next_cursor)
982 rel += res['lists']
983 next_cursor = res['next_cursor']
984 if rel:
985 print_list(rel)
986 else:
987 printNicely(light_magenta('You own no lists :)'))
988
989
990 def list_new(t):
991 """
992 Create a new list
993 """
994 name = raw_input(light_magenta('New list\'s name: '))
995 mode = raw_input(light_magenta('New list\'s mode (public/private): '))
996 description = raw_input(light_magenta('New list\'s description: '))
997 try:
998 t.lists.create(
999 name=name,
1000 mode=mode,
1001 description=description)
1002 printNicely(green(name + ' list is created.'))
1003 except:
1004 printNicely(red('Oops something is wrong with Twitter :('))
1005
1006
1007 def list_update(t):
1008 """
1009 Update a list
1010 """
1011 slug = raw_input(light_magenta('Your list that you want to update: '))
1012 name = raw_input(light_magenta('Update name (leave blank to unchange): '))
1013 mode = raw_input(light_magenta('Update mode (public/private): '))
1014 description = raw_input(light_magenta('Update description: '))
1015 try:
1016 if name:
1017 t.lists.update(
1018 slug='-'.join(slug.split()),
1019 owner_screen_name=g['original_name'],
1020 name=name,
1021 mode=mode,
1022 description=description)
1023 else:
1024 t.lists.update(
1025 slug=slug,
1026 owner_screen_name=g['original_name'],
1027 mode=mode,
1028 description=description)
1029 printNicely(green(slug + ' list is updated.'))
1030 except:
1031 printNicely(red('Oops something is wrong with Twitter :('))
1032
1033
1034 def list_delete(t):
1035 """
1036 Delete a list
1037 """
1038 slug = raw_input(light_magenta('Your list that you want to update: '))
1039 try:
1040 t.lists.destroy(
1041 slug='-'.join(slug.split()),
1042 owner_screen_name=g['original_name'])
1043 printNicely(green(slug + ' list is deleted.'))
1044 except:
1045 printNicely(red('Oops something is wrong with Twitter :('))
1046
1047
1048 def list():
1049 """
1050 Twitter's list
1051 """
1052 t = Twitter(auth=authen())
1053 # List all lists or base on action
1054 try:
1055 g['list_action'] = g['stuff'].split()[0]
1056 except:
1057 show_lists(t)
1058 return
1059 # Sub-function
1060 action_ary = {
1061 'home': list_home,
1062 'all_mem': list_members,
1063 'all_sub': list_subscribers,
1064 'add': list_add,
1065 'rm': list_remove,
1066 'sub': list_subscribe,
1067 'unsub': list_unsubscribe,
1068 'own': list_own,
1069 'new': list_new,
1070 'update': list_update,
1071 'del': list_delete,
1072 }
1073 try:
1074 return action_ary[g['list_action']](t)
1075 except:
1076 printNicely(red('Please try again.'))
1077
1078
1079 def cal():
1080 """
1081 Unix's command `cal`
1082 """
1083 # Format
1084 rel = os.popen('cal').read().split('\n')
1085 month = rel.pop(0)
1086 date = rel.pop(0)
1087 show_calendar(month, date, rel)
1088
1089
1090 def config():
1091 """
1092 Browse and change config
1093 """
1094 all_config = get_all_config()
1095 g['stuff'] = g['stuff'].strip()
1096 # List all config
1097 if not g['stuff']:
1098 for k in all_config:
1099 line = ' ' * 2 + \
1100 green(k) + ': ' + light_yellow(str(all_config[k]))
1101 printNicely(line)
1102 guide = 'Detailed explanation can be found at ' + \
1103 color_func(c['TWEET']['link'])(
1104 'http://rainbowstream.readthedocs.org/en/latest/#config-explanation')
1105 printNicely(guide)
1106 # Print specific config
1107 elif len(g['stuff'].split()) == 1:
1108 if g['stuff'] in all_config:
1109 k = g['stuff']
1110 line = ' ' * 2 + \
1111 green(k) + ': ' + light_yellow(str(all_config[k]))
1112 printNicely(line)
1113 else:
1114 printNicely(red('No such config key.'))
1115 # Print specific config's default value
1116 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'default':
1117 key = g['stuff'].split()[0]
1118 try:
1119 value = get_default_config(key)
1120 line = ' ' * 2 + green(key) + ': ' + light_magenta(value)
1121 printNicely(line)
1122 except:
1123 printNicely(
1124 light_magenta('This config key does not exist in default.'))
1125 # Delete specific config key in config file
1126 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'drop':
1127 key = g['stuff'].split()[0]
1128 try:
1129 delete_config(key)
1130 printNicely(green('Config key is dropped.'))
1131 except:
1132 printNicely(red('No such config key.'))
1133 # Set specific config
1134 elif len(g['stuff'].split()) == 3 and g['stuff'].split()[1] == '=':
1135 key = g['stuff'].split()[0]
1136 value = g['stuff'].split()[-1]
1137 if key == 'THEME' and not validate_theme(value):
1138 printNicely(red('Invalid theme\'s value.'))
1139 return
1140 try:
1141 set_config(key, value)
1142 # Apply theme immediately
1143 if key == 'THEME':
1144 reload_theme(value)
1145 g['decorated_name'] = lambda x: color_func(
1146 c['DECORATED_NAME'])(
1147 '[' + x + ']: ')
1148 printNicely(green('Updated successfully.'))
1149 except:
1150 printNicely(light_magenta('Not valid value.'))
1151 return
1152 reload_config()
1153 else:
1154 printNicely(light_magenta('Sorry I can\'s understand.'))
1155
1156
1157 def theme():
1158 """
1159 List and change theme
1160 """
1161 if not g['stuff']:
1162 # List themes
1163 for theme in g['themes']:
1164 line = light_magenta(theme)
1165 if c['THEME'] == theme:
1166 line = ' ' * 2 + light_yellow('* ') + line
1167 else:
1168 line = ' ' * 4 + line
1169 printNicely(line)
1170 else:
1171 # Change theme
1172 try:
1173 # Load new theme
1174 reload_theme(g['stuff'])
1175 # Redefine decorated_name
1176 g['decorated_name'] = lambda x: color_func(
1177 c['DECORATED_NAME'])(
1178 '[' + x + ']: ')
1179 printNicely(green('Theme changed.'))
1180 except:
1181 printNicely(red('No such theme exists.'))
1182
1183
1184 def help_discover():
1185 """
1186 Discover the world
1187 """
1188 s = ' ' * 2
1189 # Discover the world
1190 usage = '\n'
1191 usage += s + grey(u'\u266A' + ' Discover the world \n')
1192 usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \
1193 'You can try ' + light_green('trend US') + ' or ' + \
1194 light_green('trend JP Tokyo') + '.\n'
1195 usage += s * 2 + light_green('home') + ' will show your timeline. ' + \
1196 light_green('home 7') + ' will show 7 tweets.\n'
1197 usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \
1198 light_green('mentions 7') + ' will show 7 mention tweets.\n'
1199 usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \
1200 magenta('@mdo') + '.\n'
1201 usage += s * 2 + light_green('view @mdo') + \
1202 ' will show ' + magenta('@mdo') + '\'s home.\n'
1203 usage += s * 2 + light_green('s AKB48') + ' will search for "' + \
1204 light_yellow('AKB48') + '" and return 5 newest tweet. ' + \
1205 'Search can be performed with or without hashtag.\n'
1206 printNicely(usage)
1207
1208
1209 def help_tweets():
1210 """
1211 Tweets
1212 """
1213 s = ' ' * 2
1214 # Tweet
1215 usage = '\n'
1216 usage += s + grey(u'\u266A' + ' Tweets \n')
1217 usage += s * 2 + light_green('t oops ') + \
1218 'will tweet "' + light_yellow('oops') + '" immediately.\n'
1219 usage += s * 2 + \
1220 light_green('rt 12 ') + ' will retweet to tweet with ' + \
1221 light_yellow('[id=12]') + '.\n'
1222 usage += s * 2 + \
1223 light_green('quote 12 ') + ' will quote the tweet with ' + \
1224 light_yellow('[id=12]') + '. If no extra text is added, ' + \
1225 'the quote will be canceled.\n'
1226 usage += s * 2 + \
1227 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
1228 light_yellow('[id=12]') + '.\n'
1229 usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \
1230 light_yellow('oops') + '" to tweet with ' + \
1231 light_yellow('[id=12]') + '.\n'
1232 usage += s * 2 + \
1233 light_green('fav 12 ') + ' will favorite the tweet with ' + \
1234 light_yellow('[id=12]') + '.\n'
1235 usage += s * 2 + \
1236 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
1237 light_yellow('[id=12]') + '.\n'
1238 usage += s * 2 + \
1239 light_green('del 12 ') + ' will delete tweet with ' + \
1240 light_yellow('[id=12]') + '.\n'
1241 usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \
1242 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
1243 usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \
1244 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
1245 printNicely(usage)
1246
1247
1248 def help_messages():
1249 """
1250 Messages
1251 """
1252 s = ' ' * 2
1253 # Direct message
1254 usage = '\n'
1255 usage += s + grey(u'\u266A' + ' Direct messages \n')
1256 usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \
1257 light_green('inbox 7') + ' will show newest 7 messages.\n'
1258 usage += s * 2 + light_green('sent') + ' will show sent messages. ' + \
1259 light_green('sent 7') + ' will show newest 7 messages.\n'
1260 usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
1261 magenta('@dtvd88') + '.\n'
1262 usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \
1263 light_yellow('[message_id=5]') + '.\n'
1264 printNicely(usage)
1265
1266
1267 def help_friends_and_followers():
1268 """
1269 Friends and Followers
1270 """
1271 s = ' ' * 2
1272 # Follower and following
1273 usage = '\n'
1274 usage += s + grey(u'\u266A' + ' Friends and followers \n')
1275 usage += s * 2 + \
1276 light_green('ls fl') + \
1277 ' will list all followers (people who are following you).\n'
1278 usage += s * 2 + \
1279 light_green('ls fr') + \
1280 ' will list all friends (people who you are following).\n'
1281 usage += s * 2 + light_green('fl @dtvd88') + ' will follow ' + \
1282 magenta('@dtvd88') + '.\n'
1283 usage += s * 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
1284 magenta('@dtvd88') + '.\n'
1285 usage += s * 2 + light_green('mute @dtvd88') + ' will mute ' + \
1286 magenta('@dtvd88') + '.\n'
1287 usage += s * 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
1288 magenta('@dtvd88') + '.\n'
1289 usage += s * 2 + light_green('muting') + ' will list muting users.\n'
1290 usage += s * 2 + light_green('block @dtvd88') + ' will block ' + \
1291 magenta('@dtvd88') + '.\n'
1292 usage += s * 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
1293 magenta('@dtvd88') + '.\n'
1294 usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \
1295 magenta('@dtvd88') + ' as a spam account.\n'
1296 printNicely(usage)
1297
1298
1299 def help_list():
1300 """
1301 Lists
1302 """
1303 s = ' ' * 2
1304 # Twitter list
1305 usage = '\n'
1306 usage += s + grey(u'\u266A' + ' Twitter list\n')
1307 usage += s * 2 + light_green('list') + \
1308 ' will show all lists you are belong to.\n'
1309 usage += s * 2 + light_green('list home') + \
1310 ' will show timeline of list. You will be asked for list\'s name.\n'
1311 usage += s * 2 + light_green('list all_mem') + \
1312 ' will show list\'s all members.\n'
1313 usage += s * 2 + light_green('list all_sub') + \
1314 ' will show list\'s all subscribers.\n'
1315 usage += s * 2 + light_green('list add') + \
1316 ' will add specific person to a list owned by you.' + \
1317 ' You will be asked for list\'s name and person\'s name.\n'
1318 usage += s * 2 + light_green('list rm') + \
1319 ' will remove specific person from a list owned by you.' + \
1320 ' You will be asked for list\'s name and person\'s name.\n'
1321 usage += s * 2 + light_green('list sub') + \
1322 ' will subscribe you to a specific list.\n'
1323 usage += s * 2 + light_green('list unsub') + \
1324 ' will unsubscribe you from a specific list.\n'
1325 usage += s * 2 + light_green('list own') + \
1326 ' will show all list owned by you.\n'
1327 usage += s * 2 + light_green('list new') + \
1328 ' will create a new list.\n'
1329 usage += s * 2 + light_green('list update') + \
1330 ' will update a list owned by you.\n'
1331 usage += s * 2 + light_green('list del') + \
1332 ' will delete a list owned by you.\n'
1333 printNicely(usage)
1334
1335
1336 def help_stream():
1337 """
1338 Stream switch
1339 """
1340 s = ' ' * 2
1341 # Switch
1342 usage = '\n'
1343 usage += s + grey(u'\u266A' + ' Switching streams \n')
1344 usage += s * 2 + light_green('switch public #AKB') + \
1345 ' will switch to public stream and follow "' + \
1346 light_yellow('AKB') + '" keyword.\n'
1347 usage += s * 2 + light_green('switch mine') + \
1348 ' will switch to your personal stream.\n'
1349 usage += s * 2 + light_green('switch mine -f ') + \
1350 ' will prompt to enter the filter.\n'
1351 usage += s * 3 + light_yellow('Only nicks') + \
1352 ' filter will decide nicks will be INCLUDE ONLY.\n'
1353 usage += s * 3 + light_yellow('Ignore nicks') + \
1354 ' filter will decide nicks will be EXCLUDE.\n'
1355 usage += s * 2 + light_green('switch mine -d') + \
1356 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
1357 printNicely(usage)
1358
1359
1360 def help():
1361 """
1362 Help
1363 """
1364 s = ' ' * 2
1365 h, w = os.popen('stty size', 'r').read().split()
1366 # Start
1367 usage = '\n'
1368 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
1369 usage += s + '-' * (int(w) - 4) + '\n'
1370 usage += s + 'You are ' + \
1371 light_yellow('already') + ' on your personal stream.\n'
1372 usage += s + 'Any update from Twitter will show up ' + \
1373 light_yellow('immediately') + '.\n'
1374 usage += s + 'In addtion, following commands are available right now:\n'
1375 # Twitter help section
1376 usage += '\n'
1377 usage += s + grey(u'\u266A' + ' Twitter help\n')
1378 usage += s * 2 + light_green('h discover') + \
1379 ' will show help for discover commands.\n'
1380 usage += s * 2 + light_green('h tweets') + \
1381 ' will show help for tweets commands.\n'
1382 usage += s * 2 + light_green('h messages') + \
1383 ' will show help for messages commands.\n'
1384 usage += s * 2 + light_green('h friends_and_followers') + \
1385 ' will show help for friends and followers commands.\n'
1386 usage += s * 2 + light_green('h list') + \
1387 ' will show help for list commands.\n'
1388 usage += s * 2 + light_green('h stream') + \
1389 ' will show help for stream commands.\n'
1390 # Smart shell
1391 usage += '\n'
1392 usage += s + grey(u'\u266A' + ' Smart shell\n')
1393 usage += s * 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
1394 'will be evaluate by Python interpreter.\n'
1395 usage += s * 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
1396 ' for current month.\n'
1397 # Config
1398 usage += '\n'
1399 usage += s + grey(u'\u266A' + ' Config \n')
1400 usage += s * 2 + light_green('theme') + ' will list available theme. ' + \
1401 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
1402 ' theme immediately.\n'
1403 usage += s * 2 + light_green('config') + ' will list all config.\n'
1404 usage += s * 3 + \
1405 light_green('config ASCII_ART') + ' will output current value of ' +\
1406 light_yellow('ASCII_ART') + ' config key.\n'
1407 usage += s * 3 + \
1408 light_green('config TREND_MAX default') + ' will output default value of ' + \
1409 light_yellow('TREND_MAX') + ' config key.\n'
1410 usage += s * 3 + \
1411 light_green('config CUSTOM_CONFIG drop') + ' will drop ' + \
1412 light_yellow('CUSTOM_CONFIG') + ' config key.\n'
1413 usage += s * 3 + \
1414 light_green('config IMAGE_ON_TERM = true') + ' will set value of ' + \
1415 light_yellow('IMAGE_ON_TERM') + ' config key to ' + \
1416 light_yellow('True') + '.\n'
1417 # Screening
1418 usage += '\n'
1419 usage += s + grey(u'\u266A' + ' Screening \n')
1420 usage += s * 2 + light_green('h') + ' will show this help again.\n'
1421 usage += s * 2 + light_green('p') + ' will pause the stream.\n'
1422 usage += s * 2 + light_green('r') + ' will unpause the stream.\n'
1423 usage += s * 2 + light_green('c') + ' will clear the screen.\n'
1424 usage += s * 2 + light_green('q') + ' will quit.\n'
1425 # End
1426 usage += '\n'
1427 usage += s + '-' * (int(w) - 4) + '\n'
1428 usage += s + 'Have fun and hang tight! \n'
1429 # Show help
1430 d = {
1431 'discover': help_discover,
1432 'tweets': help_tweets,
1433 'messages': help_messages,
1434 'friends_and_followers': help_friends_and_followers,
1435 'list': help_list,
1436 'stream': help_stream,
1437 }
1438 if g['stuff']:
1439 d[g['stuff'].strip()]()
1440 else:
1441 printNicely(usage)
1442
1443
1444 def pause():
1445 """
1446 Pause stream display
1447 """
1448 db.semaphore_update_pause(True)
1449 printNicely(green('Stream is paused'))
1450
1451
1452 def replay():
1453 """
1454 Replay stream
1455 """
1456 db.semaphore_update_pause(False)
1457 printNicely(green('Stream is running back now'))
1458
1459
1460 def clear():
1461 """
1462 Clear screen
1463 """
1464 os.system('clear')
1465
1466
1467 def quit():
1468 """
1469 Exit all
1470 """
1471 try:
1472 save_history()
1473 os.system('rm -rf rainbow.db')
1474 printNicely(green('See you next time :)'))
1475 except:
1476 pass
1477 sys.exit()
1478
1479
1480 def reset():
1481 """
1482 Reset prefix of line
1483 """
1484 if g['reset']:
1485 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
1486 g['reset'] = False
1487 try:
1488 printNicely(str(eval(g['cmd'])))
1489 except Exception:
1490 pass
1491
1492
1493 def process(cmd):
1494 """
1495 Process switch
1496 """
1497 return dict(zip(
1498 cmdset,
1499 [
1500 switch,
1501 trend,
1502 home,
1503 view,
1504 mentions,
1505 tweet,
1506 retweet,
1507 quote,
1508 allretweet,
1509 favorite,
1510 reply,
1511 delete,
1512 unfavorite,
1513 search,
1514 message,
1515 show,
1516 urlopen,
1517 ls,
1518 inbox,
1519 sent,
1520 trash,
1521 whois,
1522 follow,
1523 unfollow,
1524 mute,
1525 unmute,
1526 muting,
1527 block,
1528 unblock,
1529 report,
1530 list,
1531 cal,
1532 config,
1533 theme,
1534 help,
1535 pause,
1536 replay,
1537 clear,
1538 quit
1539 ]
1540 )).get(cmd, reset)
1541
1542
1543 def listen():
1544 """
1545 Listen to user's input
1546 """
1547 d = dict(zip(
1548 cmdset,
1549 [
1550 ['public', 'mine'], # switch
1551 [], # trend
1552 [], # home
1553 ['@'], # view
1554 [], # mentions
1555 [], # tweet
1556 [], # retweet
1557 [], # quote
1558 [], # allretweet
1559 [], # favorite
1560 [], # reply
1561 [], # delete
1562 [], # unfavorite
1563 ['#'], # search
1564 ['@'], # message
1565 ['image'], # show image
1566 [''], # open url
1567 ['fl', 'fr'], # list
1568 [], # inbox
1569 [], # sent
1570 [], # trash
1571 ['@'], # whois
1572 ['@'], # follow
1573 ['@'], # unfollow
1574 ['@'], # mute
1575 ['@'], # unmute
1576 ['@'], # muting
1577 ['@'], # block
1578 ['@'], # unblock
1579 ['@'], # report
1580 [
1581 'home',
1582 'all_mem',
1583 'all_sub',
1584 'add',
1585 'rm',
1586 'sub',
1587 'unsub',
1588 'own',
1589 'new',
1590 'update',
1591 'del'
1592 ], # list
1593 [], # cal
1594 [key for key in dict(get_all_config())], # config
1595 g['themes'], # theme
1596 [
1597 'discover',
1598 'tweets',
1599 'messages',
1600 'friends_and_followers',
1601 'list',
1602 'stream'
1603 ], # help
1604 [], # pause
1605 [], # reconnect
1606 [], # clear
1607 [], # quit
1608 ]
1609 ))
1610 init_interactive_shell(d)
1611 read_history()
1612 reset()
1613 while True:
1614 if g['prefix']:
1615 line = raw_input(g['decorated_name'](c['PREFIX']))
1616 else:
1617 print('prefix is false')
1618 line = raw_input()
1619 try:
1620 cmd = line.split()[0]
1621 except:
1622 cmd = ''
1623 g['cmd'] = cmd
1624 try:
1625 # Lock the semaphore
1626 db.semaphore_update_lock(True)
1627 # Save cmd to global variable and call process
1628 g['stuff'] = ' '.join(line.split()[1:])
1629 # Process the command
1630 process(cmd)()
1631 # Not re-display
1632 if cmd in ['t', 'rt', 'rep']:
1633 g['prefix'] = False
1634 else:
1635 g['prefix'] = True
1636 # Release the semaphore lock
1637 db.semaphore_update_lock(False)
1638 except Exception:
1639 printNicely(red('OMG something is wrong with Twitter right now.'))
1640
1641
1642 def stream(domain, args, name='Rainbow Stream'):
1643 """
1644 Track the stream
1645 """
1646 # The Logo
1647 art_dict = {
1648 c['USER_DOMAIN']: name,
1649 c['PUBLIC_DOMAIN']: args.track_keywords,
1650 c['SITE_DOMAIN']: name,
1651 }
1652 if c['ASCII_ART']:
1653 ascii_art(art_dict[domain])
1654 # These arguments are optional:
1655 stream_args = dict(
1656 timeout=args.timeout,
1657 block=False,
1658 heartbeat_timeout=args.heartbeat_timeout)
1659 # Track keyword
1660 query_args = dict()
1661 if args.track_keywords:
1662 query_args['track'] = args.track_keywords
1663 # Get stream
1664 stream = TwitterStream(
1665 auth=authen(),
1666 domain=domain,
1667 **stream_args)
1668 try:
1669 if domain == c['USER_DOMAIN']:
1670 tweet_iter = stream.user(**query_args)
1671 elif domain == c['SITE_DOMAIN']:
1672 tweet_iter = stream.site(**query_args)
1673 else:
1674 if args.track_keywords:
1675 tweet_iter = stream.statuses.filter(**query_args)
1676 else:
1677 tweet_iter = stream.statuses.sample()
1678 # Block new stream until other one exits
1679 StreamLock.acquire()
1680 g['stream_stop'] = False
1681 for tweet in tweet_iter:
1682 if(g['stream_stop'] == True):
1683 StreamLock.release()
1684 break
1685 if tweet is None:
1686 pass
1687 elif tweet is Timeout:
1688 printNicely("-- Timeout --")
1689 elif tweet is HeartbeatTimeout:
1690 printNicely("-- Heartbeat Timeout --")
1691 elif tweet is Hangup:
1692 printNicely("-- Hangup --")
1693 elif tweet.get('text'):
1694 draw(
1695 t=tweet,
1696 keyword=args.track_keywords,
1697 check_semaphore=True,
1698 fil=args.filter,
1699 ig=args.ignore,
1700 )
1701 sys.stdout.write(g['decorated_name'](c['PREFIX']) + readline.get_line_buffer())
1702 sys.stdout.flush()
1703 elif tweet.get('direct_message'):
1704 print_message(tweet['direct_message'], check_semaphore=True)
1705 except TwitterHTTPError:
1706 printNicely('')
1707 printNicely(
1708 magenta("We have maximum connection problem with twitter'stream API right now :("))
1709
1710
1711 def fly():
1712 """
1713 Main function
1714 """
1715 # Initial
1716 args = parse_arguments()
1717 try:
1718 init(args)
1719 except TwitterHTTPError:
1720 printNicely('')
1721 printNicely(
1722 magenta("We have maximum connection problem with twitter'stream API right now :("))
1723 printNicely(magenta("Let's try again later."))
1724 save_history()
1725 os.system('rm -rf rainbow.db')
1726 sys.exit()
1727 # Spawn stream thread
1728 th = threading.Thread(target=stream, args=(c['USER_DOMAIN'], args, g['original_name']))
1729 th.daemon = True
1730 th.start()
1731 # Start listen process
1732 time.sleep(0.5)
1733 g['reset'] = True
1734 g['prefix'] = True
1735 listen()