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