change theme base on config
[rainbowstream.git] / rainbowstream / rainbow.py
CommitLineData
91476ec3
O
1"""
2Colorful user's timeline stream
3"""
78b81730 4from multiprocessing import Process
78b81730 5
b2b933a9 6import os
7import os.path
8import sys
9import signal
10import argparse
11import time
991c30af 12import requests
91476ec3 13
91476ec3 14from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
54277114 15from twitter.api import *
91476ec3 16from twitter.oauth import OAuth, read_token_file
8c840a83 17from twitter.oauth_dance import oauth_dance
91476ec3 18from twitter.util import printNicely
991c30af 19from StringIO import StringIO
91476ec3 20
7500d90b 21from .draw import *
2a6238f5
O
22from .colors import *
23from .config import *
777c52d4 24from .consumer import *
94a5f62e 25from .interactive import *
18cab06a 26from .db import *
991c30af 27from .c_image import *
2a6238f5 28
f405a7d0 29g = {}
18cab06a 30db = RainbowDB()
94a5f62e 31cmdset = [
42fde775 32 'switch',
4592d231 33 'trend',
94a5f62e 34 'home',
35 'view',
305ce127 36 'mentions',
94a5f62e 37 't',
38 'rt',
1f24a05a 39 'allrt',
7e4ccbf3 40 'fav',
94a5f62e 41 'rep',
42 'del',
7e4ccbf3 43 'ufav',
94a5f62e 44 's',
305ce127 45 'mes',
f5677fb1 46 'show',
0f6e4daf 47 'ls',
305ce127 48 'inbox',
49 'sent',
50 'trash',
e2b81717 51 'whois',
94a5f62e 52 'fl',
f5677fb1 53 'ufl',
5b2c4faf 54 'mute',
55 'unmute',
56 'muting',
305ce127 57 'block',
58 'unblock',
59 'report',
813a5d80 60 'cal',
632c6fa5 61 'theme',
94a5f62e 62 'h',
63 'c',
64 'q'
65]
22be990e 66
91476ec3
O
67def parse_arguments():
68 """
69 Parse the arguments
70 """
91476ec3 71 parser = argparse.ArgumentParser(description=__doc__ or "")
2a6238f5
O
72 parser.add_argument(
73 '-to',
74 '--timeout',
75 help='Timeout for the stream (seconds).')
76 parser.add_argument(
77 '-ht',
78 '--heartbeat-timeout',
79 help='Set heartbeat timeout.',
80 default=90)
81 parser.add_argument(
82 '-nb',
83 '--no-block',
84 action='store_true',
85 help='Set stream to non-blocking.')
86 parser.add_argument(
87 '-tt',
88 '--track-keywords',
89 help='Search the stream for specific text.')
d51b4107
O
90 parser.add_argument(
91 '-fil',
92 '--filter',
93 help='Filter specific screen_name.')
94 parser.add_argument(
95 '-ig',
96 '--ignore',
97 help='Ignore specific screen_name.')
88af38d8 98 parser.add_argument(
c1fa7c94
O
99 '-iot',
100 '--image-on-term',
101 action='store_true',
102 help='Display all image on terminal.')
91476ec3
O
103 return parser.parse_args()
104
105
54277114
O
106def authen():
107 """
7b674cef 108 Authenticate with Twitter OAuth
54277114 109 """
8c840a83 110 # When using rainbow stream you must authorize.
2a6238f5
O
111 twitter_credential = os.environ.get(
112 'HOME',
113 os.environ.get(
114 'USERPROFILE',
115 '')) + os.sep + '.rainbow_oauth'
8c840a83
O
116 if not os.path.exists(twitter_credential):
117 oauth_dance("Rainbow Stream",
118 CONSUMER_KEY,
119 CONSUMER_SECRET,
120 twitter_credential)
121 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
54277114 122 return OAuth(
2a6238f5
O
123 oauth_token,
124 oauth_token_secret,
125 CONSUMER_KEY,
126 CONSUMER_SECRET)
91476ec3 127
54277114
O
128
129def get_decorated_name():
130 """
131 Beginning of every line
132 """
133 t = Twitter(auth=authen())
c5ff542b 134 name = '@' + t.account.verify_credentials()['screen_name']
42fde775 135 g['original_name'] = name[1:]
f405a7d0 136 g['decorated_name'] = grey('[') + grey(name) + grey(']: ')
54277114 137
632c6fa5
O
138 files = os.listdir('rainbowstream/colorset')
139 themes = [f.split('.')[0] for f in files if f.split('.')[-1]=='json']
140 g['themes'] = themes
141
f405a7d0 142
42fde775 143def switch():
144 """
145 Switch stream
146 """
147 try:
148 target = g['stuff'].split()[0]
149
d51b4107
O
150 # Filter and ignore
151 args = parse_arguments()
7e4ccbf3 152 try:
d51b4107
O
153 if g['stuff'].split()[-1] == '-f':
154 only = raw_input('Only nicks: ')
155 ignore = raw_input('Ignore nicks: ')
7e4ccbf3 156 args.filter = filter(None, only.split(','))
157 args.ignore = filter(None, ignore.split(','))
d51b4107 158 elif g['stuff'].split()[-1] == '-d':
632c6fa5
O
159 args.filter = c['ONLY_LIST']
160 args.ignore = c['IGNORE_LIST']
d51b4107
O
161 except:
162 printNicely(red('Sorry, wrong format.'))
163 return
164
42fde775 165 # Public stream
166 if target == 'public':
167 keyword = g['stuff'].split()[1]
168 if keyword[0] == '#':
169 keyword = keyword[1:]
42fde775 170 # Kill old process
171 os.kill(g['stream_pid'], signal.SIGKILL)
42fde775 172 args.track_keywords = keyword
42fde775 173 # Start new process
174 p = Process(
d51b4107 175 target=stream,
42fde775 176 args=(
632c6fa5 177 c['PUBLIC_DOMAIN'],
42fde775 178 args))
179 p.start()
180 g['stream_pid'] = p.pid
181
182 # Personal stream
183 elif target == 'mine':
42fde775 184 # Kill old process
185 os.kill(g['stream_pid'], signal.SIGKILL)
42fde775 186 # Start new process
187 p = Process(
188 target=stream,
189 args=(
632c6fa5 190 c['USER_DOMAIN'],
42fde775 191 args,
192 g['original_name']))
193 p.start()
194 g['stream_pid'] = p.pid
d51b4107 195 printNicely('')
1551a7d3 196 printNicely(green('Stream switched.'))
d51b4107
O
197 if args.filter:
198 printNicely(cyan('Only: ' + str(args.filter)))
199 if args.ignore:
200 printNicely(red('Ignore: ' + str(args.ignore)))
201 printNicely('')
42fde775 202 except:
203 printNicely(red('Sorry I can\'t understand.'))
42fde775 204
205
4592d231 206def trend():
207 """
208 Trend
209 """
210 t = Twitter(auth=authen())
48a25fe8 211 # Get country and town
4592d231 212 try:
213 country = g['stuff'].split()[0]
214 except:
215 country = ''
48a25fe8 216 try:
217 town = g['stuff'].split()[1]
218 except:
219 town = ''
220
221 avail = t.trends.available()
222 # World wide
223 if not country:
224 trends = t.trends.place(_id=1)[0]['trends']
225 print_trends(trends)
226 else:
227 for location in avail:
228 # Search for country and Town
229 if town:
230 if location['countryCode'] == country \
231 and location['placeType']['name'] == 'Town' \
232 and location['name'] == town:
233 trends = t.trends.place(_id=location['woeid'])[0]['trends']
234 print_trends(trends)
235 # Search for country only
236 else:
237 if location['countryCode'] == country \
238 and location['placeType']['name'] == 'Country':
239 trends = t.trends.place(_id=location['woeid'])[0]['trends']
240 print_trends(trends)
4592d231 241
242
7b674cef 243def home():
244 """
245 Home
246 """
247 t = Twitter(auth=authen())
632c6fa5 248 num = c['HOME_TWEET_NUM']
7b674cef 249 if g['stuff'].isdigit():
305ce127 250 num = int(g['stuff'])
94a5f62e 251 for tweet in reversed(t.statuses.home_timeline(count=num)):
c1fa7c94 252 draw(t=tweet, iot=g['iot'])
94a5f62e 253 printNicely('')
7b674cef 254
255
256def view():
257 """
258 Friend view
259 """
260 t = Twitter(auth=authen())
261 user = g['stuff'].split()[0]
b8fbcb70 262 if user[0] == '@':
263 try:
94a5f62e 264 num = int(g['stuff'].split()[1])
b8fbcb70 265 except:
632c6fa5 266 num = c['HOME_TWEET_NUM']
94a5f62e 267 for tweet in reversed(t.statuses.user_timeline(count=num, screen_name=user[1:])):
c1fa7c94 268 draw(t=tweet, iot=g['iot'])
94a5f62e 269 printNicely('')
b8fbcb70 270 else:
c91f75f2 271 printNicely(red('A name should begin with a \'@\''))
7b674cef 272
273
305ce127 274def mentions():
275 """
276 Mentions timeline
277 """
278 t = Twitter(auth=authen())
632c6fa5 279 num = c['HOME_TWEET_NUM']
305ce127 280 if g['stuff'].isdigit():
281 num = int(g['stuff'])
282 for tweet in reversed(t.statuses.mentions_timeline(count=num)):
283 draw(t=tweet, iot=g['iot'])
284 printNicely('')
285
286
f405a7d0 287def tweet():
54277114 288 """
7b674cef 289 Tweet
54277114
O
290 """
291 t = Twitter(auth=authen())
f405a7d0 292 t.statuses.update(status=g['stuff'])
f405a7d0 293
b2b933a9 294
1ba4abfd
O
295def retweet():
296 """
297 ReTweet
298 """
299 t = Twitter(auth=authen())
300 try:
301 id = int(g['stuff'].split()[0])
1ba4abfd 302 except:
b8c1f42a
O
303 printNicely(red('Sorry I can\'t understand.'))
304 return
305 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
306 t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
1ba4abfd
O
307
308
1f24a05a 309def allretweet():
310 """
311 List all retweet
312 """
313 t = Twitter(auth=authen())
314 # Get rainbow id
315 try:
316 id = int(g['stuff'].split()[0])
317 except:
318 printNicely(red('Sorry I can\'t understand.'))
319 return
320 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
321 # Get display num if exist
322 try:
323 num = int(g['stuff'].split()[1])
324 except:
632c6fa5 325 num = c['RETWEETS_SHOW_NUM']
1f24a05a 326 # Get result and display
d8e901a4 327 rt_ary = t.statuses.retweets(id=tid, count=num)
1f24a05a 328 if not rt_ary:
329 printNicely(magenta('This tweet has no retweet.'))
330 return
331 for tweet in reversed(rt_ary):
332 draw(t=tweet, iot=g['iot'])
333 printNicely('')
334
335
7e4ccbf3 336def favorite():
337 """
338 Favorite
339 """
340 t = Twitter(auth=authen())
341 try:
342 id = int(g['stuff'].split()[0])
7e4ccbf3 343 except:
b8c1f42a
O
344 printNicely(red('Sorry I can\'t understand.'))
345 return
346 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
347 t.favorites.create(_id=tid, include_entities=False)
348 printNicely(green('Favorited.'))
349 draw(t.statuses.show(id=tid), iot=g['iot'])
350 printNicely('')
7e4ccbf3 351
352
7b674cef 353def reply():
829cc2d8 354 """
7b674cef 355 Reply
829cc2d8
O
356 """
357 t = Twitter(auth=authen())
7b674cef 358 try:
359 id = int(g['stuff'].split()[0])
7b674cef 360 except:
c91f75f2 361 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
362 return
363 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
364 user = t.statuses.show(id=tid)['user']['screen_name']
365 status = ' '.join(g['stuff'].split()[1:])
366 status = '@' + user + ' ' + status.decode('utf-8')
367 t.statuses.update(status=status, in_reply_to_status_id=tid)
7b674cef 368
369
370def delete():
371 """
372 Delete
373 """
374 t = Twitter(auth=authen())
375 try:
305ce127 376 rid = int(g['stuff'].split()[0])
7b674cef 377 except:
305ce127 378 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
379 return
380 tid = db.rainbow_to_tweet_query(rid)[0].tweet_id
381 t.statuses.destroy(id=tid)
382 printNicely(green('Okay it\'s gone.'))
829cc2d8
O
383
384
7e4ccbf3 385def unfavorite():
386 """
387 Unfavorite
388 """
389 t = Twitter(auth=authen())
390 try:
391 id = int(g['stuff'].split()[0])
7e4ccbf3 392 except:
b8c1f42a
O
393 printNicely(red('Sorry I can\'t understand.'))
394 return
395 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
396 t.favorites.destroy(_id=tid)
397 printNicely(green('Okay it\'s unfavorited.'))
398 draw(t.statuses.show(id=tid), iot=g['iot'])
399 printNicely('')
7e4ccbf3 400
401
f405a7d0
O
402def search():
403 """
7b674cef 404 Search
f405a7d0
O
405 """
406 t = Twitter(auth=authen())
b8c1f42a
O
407 if g['stuff'].startswith('#'):
408 rel = t.search.tweets(q=g['stuff'])['statuses']
5b2c4faf 409 if rel:
b8c1f42a 410 printNicely('Newest tweets:')
632c6fa5 411 for i in reversed(xrange(c['SEARCH_MAX_RECORD'])):
b8c1f42a
O
412 draw(t=rel[i],
413 iot=g['iot'],
414 keyword=g['stuff'].strip()[1:])
415 printNicely('')
94a5f62e 416 else:
b8c1f42a
O
417 printNicely(magenta('I\'m afraid there is no result'))
418 else:
419 printNicely(red('A keyword should be a hashtag (like \'#AKB48\')'))
b2b933a9 420
f405a7d0 421
305ce127 422def message():
423 """
424 Send a direct message
425 """
426 t = Twitter(auth=authen())
427 user = g['stuff'].split()[0]
b8c1f42a 428 if user[0].startswith('@'):
305ce127 429 try:
430 content = g['stuff'].split()[1]
305ce127 431 except:
432 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
433 t.direct_messages.new(
434 screen_name=user[1:],
435 text=content
436 )
437 printNicely(green('Message sent.'))
305ce127 438 else:
439 printNicely(red('A name should begin with a \'@\''))
440
441
f5677fb1 442def show():
843647ad 443 """
f5677fb1 444 Show image
843647ad
O
445 """
446 t = Twitter(auth=authen())
f5677fb1
O
447 try:
448 target = g['stuff'].split()[0]
449 if target != 'image':
450 return
451 id = int(g['stuff'].split()[1])
305ce127 452 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
f5677fb1
O
453 tweet = t.statuses.show(id=tid)
454 media = tweet['entities']['media']
455 for m in media:
456 res = requests.get(m['media_url'])
457 img = Image.open(StringIO(res.content))
458 img.show()
459 except:
460 printNicely(red('Sorry I can\'t show this image.'))
843647ad
O
461
462
0f6e4daf 463def list():
464 """
465 List friends for followers
466 """
467 t = Twitter(auth=authen())
e2b81717
O
468 # Get name
469 try:
470 name = g['stuff'].split()[1]
b8c1f42a 471 if name.startswith('@'):
e2b81717
O
472 name = name[1:]
473 else:
474 printNicely(red('A name should begin with a \'@\''))
475 raise Exception('Invalid name')
476 except:
477 name = g['original_name']
478 # Get list followers or friends
0f6e4daf 479 try:
480 target = g['stuff'].split()[0]
0f6e4daf 481 except:
482 printNicely(red('Omg some syntax is wrong.'))
b8c1f42a
O
483 # Init cursor
484 d = {'fl': 'followers', 'fr': 'friends'}
485 next_cursor = -1
486 rel = {}
487 # Cursor loop
488 while next_cursor != 0:
489 list = getattr(t, d[target]).list(
490 screen_name=name,
491 cursor=next_cursor,
492 skip_status=True,
493 include_entities=False,
494 )
495 for u in list['users']:
496 rel[u['name']] = '@' + u['screen_name']
497 next_cursor = list['next_cursor']
498 # Print out result
499 printNicely('All: ' + str(len(rel)) + ' people.')
500 for name in rel:
501 user = ' ' + cycle_color(name) + grey(' ' + rel[name] + ' ')
502 printNicely(user)
0f6e4daf 503
504
305ce127 505def inbox():
506 """
507 Inbox direct messages
508 """
509 t = Twitter(auth=authen())
632c6fa5 510 num = c['MESSAGES_DISPLAY']
305ce127 511 rel = []
512 if g['stuff'].isdigit():
513 num = g['stuff']
514 cur_page = 1
515 # Max message per page is 20 so we have to loop
516 while num > 20:
517 rel = rel + t.direct_messages(
518 count=20,
519 page=cur_page,
520 include_entities=False,
521 skip_status=False
48a25fe8 522 )
305ce127 523 num -= 20
524 cur_page += 1
525 rel = rel + t.direct_messages(
526 count=num,
527 page=cur_page,
528 include_entities=False,
529 skip_status=False
48a25fe8 530 )
e2b81717 531 # Display
305ce127 532 printNicely('Inbox: newest ' + str(len(rel)) + ' messages.')
533 for m in reversed(rel):
534 print_message(m)
535 printNicely('')
536
e2b81717 537
305ce127 538def sent():
539 """
540 Sent direct messages
541 """
542 t = Twitter(auth=authen())
632c6fa5 543 num = c['MESSAGES_DISPLAY']
305ce127 544 rel = []
545 if g['stuff'].isdigit():
546 num = int(g['stuff'])
547 cur_page = 1
548 # Max message per page is 20 so we have to loop
549 while num > 20:
550 rel = rel + t.direct_messages.sent(
551 count=20,
552 page=cur_page,
553 include_entities=False,
554 skip_status=False
48a25fe8 555 )
305ce127 556 num -= 20
557 cur_page += 1
558 rel = rel + t.direct_messages.sent(
559 count=num,
560 page=cur_page,
561 include_entities=False,
562 skip_status=False
48a25fe8 563 )
e2b81717 564 # Display
305ce127 565 printNicely('Sent: newest ' + str(len(rel)) + ' messages.')
566 for m in reversed(rel):
567 print_message(m)
568 printNicely('')
e2b81717 569
305ce127 570
571def trash():
572 """
573 Remove message
574 """
575 t = Twitter(auth=authen())
576 try:
577 rid = int(g['stuff'].split()[0])
305ce127 578 except:
579 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
580 mid = db.rainbow_to_message_query(rid)[0].message_id
581 t.direct_messages.destroy(id=mid)
582 printNicely(green('Message deleted.'))
305ce127 583
584
e2b81717
O
585def whois():
586 """
587 Show profile of a specific user
588 """
589 t = Twitter(auth=authen())
590 screen_name = g['stuff'].split()[0]
b8c1f42a 591 if screen_name.startswith('@'):
e2b81717
O
592 try:
593 user = t.users.show(
594 screen_name=screen_name[1:],
595 include_entities=False)
7500d90b 596 show_profile(user, g['iot'])
e2b81717
O
597 except:
598 printNicely(red('Omg no user.'))
599 else:
b8c1f42a 600 printNicely(red('A name should begin with a \'@\''))
e2b81717
O
601
602
f5677fb1 603def follow():
843647ad 604 """
f5677fb1 605 Follow a user
843647ad
O
606 """
607 t = Twitter(auth=authen())
f5677fb1 608 screen_name = g['stuff'].split()[0]
b8c1f42a
O
609 if screen_name.startswith('@'):
610 t.friendships.create(screen_name=screen_name[1:], follow=True)
611 printNicely(green('You are following ' + screen_name + ' now!'))
f5677fb1 612 else:
b8c1f42a 613 printNicely(red('A name should begin with a \'@\''))
f5677fb1
O
614
615
616def unfollow():
617 """
618 Unfollow a user
619 """
620 t = Twitter(auth=authen())
621 screen_name = g['stuff'].split()[0]
b8c1f42a
O
622 if screen_name.startswith('@'):
623 t.friendships.destroy(
624 screen_name=screen_name[1:],
625 include_entities=False)
626 printNicely(green('Unfollow ' + screen_name + ' success!'))
f5677fb1 627 else:
b8c1f42a 628 printNicely(red('A name should begin with a \'@\''))
843647ad
O
629
630
5b2c4faf 631def mute():
632 """
633 Mute a user
634 """
635 t = Twitter(auth=authen())
636 try:
637 screen_name = g['stuff'].split()[0]
638 except:
639 printNicely(red('A name should be specified. '))
640 return
641 if screen_name.startswith('@'):
642 rel = t.mutes.users.create(screen_name=screen_name[1:])
643 if isinstance(rel, dict):
644 printNicely(green(screen_name + ' is muted.'))
645 else:
646 printNicely(red(rel))
647 else:
648 printNicely(red('A name should begin with a \'@\''))
649
650
651def unmute():
652 """
653 Unmute a user
654 """
655 t = Twitter(auth=authen())
656 try:
657 screen_name = g['stuff'].split()[0]
658 except:
659 printNicely(red('A name should be specified. '))
660 return
661 if screen_name.startswith('@'):
662 rel = t.mutes.users.destroy(screen_name=screen_name[1:])
663 if isinstance(rel, dict):
664 printNicely(green(screen_name + ' is unmuted.'))
665 else:
666 printNicely(red(rel))
667 else:
668 printNicely(red('A name should begin with a \'@\''))
669
670
671def muting():
672 """
673 List muting user
674 """
675 t = Twitter(auth=authen())
676 # Init cursor
5b2c4faf 677 next_cursor = -1
678 rel = {}
679 # Cursor loop
680 while next_cursor != 0:
681 list = t.mutes.users.list(
682 screen_name=g['original_name'],
683 cursor=next_cursor,
684 skip_status=True,
685 include_entities=False,
686 )
687 for u in list['users']:
688 rel[u['name']] = '@' + u['screen_name']
689 next_cursor = list['next_cursor']
690 # Print out result
691 printNicely('All: ' + str(len(rel)) + ' people.')
692 for name in rel:
693 user = ' ' + cycle_color(name) + grey(' ' + rel[name] + ' ')
694 printNicely(user)
695
696
305ce127 697def block():
698 """
699 Block a user
700 """
701 t = Twitter(auth=authen())
702 screen_name = g['stuff'].split()[0]
b8c1f42a
O
703 if screen_name.startswith('@'):
704 t.blocks.create(
5b2c4faf 705 screen_name=screen_name[1:],
706 include_entities=False,
707 skip_status=True)
b8c1f42a 708 printNicely(green('You blocked ' + screen_name + '.'))
305ce127 709 else:
b8c1f42a 710 printNicely(red('A name should begin with a \'@\''))
305ce127 711
712
713def unblock():
714 """
715 Unblock a user
716 """
717 t = Twitter(auth=authen())
718 screen_name = g['stuff'].split()[0]
b8c1f42a
O
719 if screen_name.startswith('@'):
720 t.blocks.destroy(
721 screen_name=screen_name[1:],
722 include_entities=False,
723 skip_status=True)
724 printNicely(green('Unblock ' + screen_name + ' success!'))
305ce127 725 else:
b8c1f42a 726 printNicely(red('A name should begin with a \'@\''))
305ce127 727
728
729def report():
730 """
731 Report a user as a spam account
732 """
733 t = Twitter(auth=authen())
734 screen_name = g['stuff'].split()[0]
b8c1f42a
O
735 if screen_name.startswith('@'):
736 t.users.report_spam(
737 screen_name=screen_name[1:])
738 printNicely(green('You reported ' + screen_name + '.'))
305ce127 739 else:
740 printNicely(red('Sorry I can\'t understand.'))
741
742
813a5d80 743def cal():
744 """
745 Unix's command `cal`
746 """
747 # Format
748 rel = os.popen('cal').read().split('\n')
749 month = rel.pop(0)
750 month = random_rainbow(month)
751 date = rel.pop(0)
752 date = ' '.join([cycle_color(i) for i in date.split(' ')])
6fefb8c9 753 today = str(int(os.popen('date +\'%d\'').read().strip()))
813a5d80 754 # Display
6fa09c14
VNM
755 printNicely(month)
756 printNicely(date)
813a5d80 757 for line in rel:
758 ary = line.split(' ')
d8e901a4 759 ary = map(lambda x: on_grey(x) if x == today else grey(x), ary)
6fa09c14 760 printNicely(' '.join(ary))
813a5d80 761
762
632c6fa5
O
763def theme():
764 """
765 List and change theme
766 """
767 if not g['stuff']:
768 # List themes
769 for theme in g['themes']:
770 line = ' '*2 + magenta('* ' + theme)
771 printNicely(line)
772 else:
773 # Change theme
774 try :
775 new_config = 'rainbowstream/colorset/' + g['stuff'] + '.json'
776 new_config = load_config(new_config)
777 for nc in new_config:
778 c[nc] = new_config[nc]
779 printNicely(green('Theme changed.'))
780 except :
781 printNicely(red('Sorry, config file is broken!'))
782
783
f405a7d0
O
784def help():
785 """
7b674cef 786 Help
f405a7d0 787 """
7e4ccbf3 788 s = ' ' * 2
789 h, w = os.popen('stty size', 'r').read().split()
e3885f55 790
8bc30efd 791 # Start
e3885f55
O
792 usage = '\n'
793 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
7e4ccbf3 794 usage += s + '-' * (int(w) - 4) + '\n'
7e4ccbf3 795 usage += s + 'You are ' + yellow('already') + ' on your personal stream.\n'
5b2c4faf 796 usage += s + 'Any update from Twitter will show up ' + \
797 yellow('immediately') + '.\n'
798 usage += s + 'In addtion, following commands are available right now:\n'
e3885f55 799
1f24a05a 800 # Discover the world
8bc30efd 801 usage += '\n'
802 usage += s + grey(u'\u266A' + ' Discover the world \n')
d03d632b 803 usage += s * 2 + green('trend') + ' will show global trending topics. ' + \
48a25fe8 804 'You can try ' + green('trend US') + ' or ' + \
805 green('trend JP Tokyo') + '.\n'
7e4ccbf3 806 usage += s * 2 + green('home') + ' will show your timeline. ' + \
305ce127 807 green('home 7') + ' will show 7 tweets.\n'
305ce127 808 usage += s * 2 + green('mentions') + ' will show mentions timeline. ' + \
e2b81717 809 green('mentions 7') + ' will show 7 mention tweets.\n'
8bc30efd 810 usage += s * 2 + green('whois @mdo') + ' will show profile of ' + \
811 magenta('@mdo') + '.\n'
812 usage += s * 2 + green('view @mdo') + \
813 ' will show ' + magenta('@mdo') + '\'s home.\n'
814 usage += s * 2 + green('s #AKB48') + ' will search for "' + \
815 yellow('AKB48') + '" and return 5 newest tweet.\n'
816
1f24a05a 817 # Tweet
8bc30efd 818 usage += '\n'
819 usage += s + grey(u'\u266A' + ' Tweets \n')
7e4ccbf3 820 usage += s * 2 + green('t oops ') + \
821 'will tweet "' + yellow('oops') + '" immediately.\n'
822 usage += s * 2 + \
823 green('rt 12 ') + ' will retweet to tweet with ' + \
824 yellow('[id=12]') + '.\n'
1f24a05a 825 usage += s * 2 + \
d8e901a4 826 green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
1f24a05a 827 yellow('[id=12]') + '.\n'
7e4ccbf3 828 usage += s * 2 + green('rep 12 oops') + ' will reply "' + \
829 yellow('oops') + '" to tweet with ' + yellow('[id=12]') + '.\n'
830 usage += s * 2 + \
8bc30efd 831 green('fav 12 ') + ' will favorite the tweet with ' + \
7e4ccbf3 832 yellow('[id=12]') + '.\n'
833 usage += s * 2 + \
834 green('ufav 12 ') + ' will unfavorite tweet with ' + \
835 yellow('[id=12]') + '.\n'
8bc30efd 836 usage += s * 2 + \
837 green('del 12 ') + ' will delete tweet with ' + \
838 yellow('[id=12]') + '.\n'
a99b7b04
O
839 usage += s * 2 + green('show image 12') + ' will show image in tweet with ' + \
840 yellow('[id=12]') + ' in your OS\'s image viewer.\n'
8bc30efd 841
5b2c4faf 842 # Direct message
8bc30efd 843 usage += '\n'
844 usage += s + grey(u'\u266A' + ' Direct messages \n')
305ce127 845 usage += s * 2 + green('inbox') + ' will show inbox messages. ' + \
846 green('inbox 7') + ' will show newest 7 messages.\n'
847 usage += s * 2 + green('sent') + ' will show sent messages. ' + \
848 green('sent 7') + ' will show newest 7 messages.\n'
8bc30efd 849 usage += s * 2 + green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
850 magenta('@dtvd88') + '.\n'
305ce127 851 usage += s * 2 + green('trash 5') + ' will remove message with ' + \
852 yellow('[message_id=5]') + '.\n'
8bc30efd 853
854 # Follower and following
855 usage += '\n'
856 usage += s + grey(u'\u266A' + ' Fiends and followers \n')
857 usage += s * 2 + \
858 green('ls fl') + \
859 ' will list all followers (people who are following you).\n'
860 usage += s * 2 + \
861 green('ls fr') + \
862 ' will list all friends (people who you are following).\n'
f5677fb1 863 usage += s * 2 + green('fl @dtvd88') + ' will follow ' + \
305ce127 864 magenta('@dtvd88') + '.\n'
f5677fb1 865 usage += s * 2 + green('ufl @dtvd88') + ' will unfollow ' + \
305ce127 866 magenta('@dtvd88') + '.\n'
83320499 867 usage += s * 2 + green('mute @dtvd88') + ' will mute ' + \
5b2c4faf 868 magenta('@dtvd88') + '.\n'
83320499 869 usage += s * 2 + green('unmute @dtvd88') + ' will unmute ' + \
5b2c4faf 870 magenta('@dtvd88') + '.\n'
871 usage += s * 2 + green('muting') + ' will list muting users.\n'
305ce127 872 usage += s * 2 + green('block @dtvd88') + ' will block ' + \
873 magenta('@dtvd88') + '.\n'
874 usage += s * 2 + green('unblock @dtvd88') + ' will unblock ' + \
875 magenta('@dtvd88') + '.\n'
876 usage += s * 2 + green('report @dtvd88') + ' will report ' + \
877 magenta('@dtvd88') + ' as a spam account.\n'
8bc30efd 878
8bc30efd 879 # Switch
880 usage += '\n'
881 usage += s + grey(u'\u266A' + ' Switching streams \n')
48a25fe8 882 usage += s * 2 + green('switch public #AKB') + \
883 ' will switch to public stream and follow "' + \
884 yellow('AKB') + '" keyword.\n'
885 usage += s * 2 + green('switch mine') + \
886 ' will switch to your personal stream.\n'
887 usage += s * 2 + green('switch mine -f ') + \
888 ' will prompt to enter the filter.\n'
889 usage += s * 3 + yellow('Only nicks') + \
890 ' filter will decide nicks will be INCLUDE ONLY.\n'
891 usage += s * 3 + yellow('Ignore nicks') + \
892 ' filter will decide nicks will be EXCLUDE.\n'
893 usage += s * 2 + green('switch mine -d') + \
894 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
48a25fe8 895
1f24a05a 896 # Smart shell
897 usage += '\n'
898 usage += s + grey(u'\u266A' + ' Smart shell\n')
d8e901a4 899 usage += s * 2 + green('111111 * 9 / 7') + ' or any math expression ' + \
1f24a05a 900 'will be evaluate by Python interpreter.\n'
d8e901a4 901 usage += s * 2 + 'Even ' + green('cal') + ' will show the calendar' + \
1f24a05a 902 ' for current month.\n'
903
904 # Screening
905 usage += '\n'
906 usage += s + grey(u'\u266A' + ' Screening \n')
632c6fa5
O
907 usage += s * 2 + green('theme') + ' will list available theme.' + \
908 green('theme monokai') + ' will apply '+ yellow('monokai') + \
909 ' theme immediately.\n'
1f24a05a 910 usage += s * 2 + green('h') + ' will show this help again.\n'
911 usage += s * 2 + green('c') + ' will clear the screen.\n'
912 usage += s * 2 + green('q') + ' will quit.\n'
913
8bc30efd 914 # End
915 usage += '\n'
7e4ccbf3 916 usage += s + '-' * (int(w) - 4) + '\n'
8bc30efd 917 usage += s + 'Have fun and hang tight! \n'
f405a7d0 918 printNicely(usage)
f405a7d0
O
919
920
843647ad 921def clear():
f405a7d0 922 """
7b674cef 923 Clear screen
f405a7d0 924 """
843647ad 925 os.system('clear')
f405a7d0
O
926
927
843647ad 928def quit():
b8dda704
O
929 """
930 Exit all
931 """
f5677fb1 932 save_history()
8e633322 933 os.system('rm -rf rainbow.db')
843647ad
O
934 os.kill(g['stream_pid'], signal.SIGKILL)
935 sys.exit()
b8dda704
O
936
937
94a5f62e 938def reset():
f405a7d0 939 """
94a5f62e 940 Reset prefix of line
f405a7d0 941 """
c91f75f2 942 if g['reset']:
e3885f55 943 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
c91f75f2 944 g['reset'] = False
d0a726d6 945 try:
6fa09c14 946 printNicely(eval(g['cmd']))
d0a726d6 947 except:
948 pass
54277114
O
949
950
94a5f62e 951def process(cmd):
54277114 952 """
94a5f62e 953 Process switch
54277114 954 """
94a5f62e 955 return dict(zip(
956 cmdset,
b2b933a9 957 [
42fde775 958 switch,
4592d231 959 trend,
b2b933a9 960 home,
961 view,
305ce127 962 mentions,
b2b933a9 963 tweet,
964 retweet,
1f24a05a 965 allretweet,
7e4ccbf3 966 favorite,
b2b933a9 967 reply,
968 delete,
7e4ccbf3 969 unfavorite,
b2b933a9 970 search,
305ce127 971 message,
f5677fb1 972 show,
0f6e4daf 973 list,
305ce127 974 inbox,
975 sent,
976 trash,
e2b81717 977 whois,
f5677fb1
O
978 follow,
979 unfollow,
5b2c4faf 980 mute,
981 unmute,
982 muting,
305ce127 983 block,
984 unblock,
985 report,
813a5d80 986 cal,
632c6fa5 987 theme,
b2b933a9 988 help,
989 clear,
990 quit
991 ]
94a5f62e 992 )).get(cmd, reset)
993
994
995def listen():
42fde775 996 """
997 Listen to user's input
998 """
d51b4107
O
999 d = dict(zip(
1000 cmdset,
1001 [
affcb149 1002 ['public', 'mine'], # switch
4592d231 1003 [], # trend
7e4ccbf3 1004 [], # home
1005 ['@'], # view
305ce127 1006 [], # mentions
7e4ccbf3 1007 [], # tweet
1008 [], # retweet
1f24a05a 1009 [], # allretweet
f5677fb1 1010 [], # favorite
7e4ccbf3 1011 [], # reply
1012 [], # delete
f5677fb1 1013 [], # unfavorite
7e4ccbf3 1014 ['#'], # search
305ce127 1015 ['@'], # message
f5677fb1 1016 ['image'], # show image
305ce127 1017 ['fl', 'fr'], # list
1018 [], # inbox
1019 [], # sent
1020 [], # trash
e2b81717 1021 ['@'], # whois
affcb149
O
1022 ['@'], # follow
1023 ['@'], # unfollow
5b2c4faf 1024 ['@'], # mute
1025 ['@'], # unmute
1026 ['@'], # muting
305ce127 1027 ['@'], # block
1028 ['@'], # unblock
1029 ['@'], # report
813a5d80 1030 [], # cal
632c6fa5 1031 g['themes'], # theme
7e4ccbf3 1032 [], # help
1033 [], # clear
1034 [], # quit
d51b4107 1035 ]
7e4ccbf3 1036 ))
d51b4107 1037 init_interactive_shell(d)
f5677fb1 1038 read_history()
819569e8 1039 reset()
b2b933a9 1040 while True:
1dd312f5
O
1041 if g['prefix']:
1042 line = raw_input(g['decorated_name'])
1043 else:
1044 line = raw_input()
843647ad
O
1045 try:
1046 cmd = line.split()[0]
1047 except:
1048 cmd = ''
d0a726d6 1049 g['cmd'] = cmd
f405a7d0 1050 # Save cmd to global variable and call process
b8c1f42a
O
1051 try:
1052 g['stuff'] = ' '.join(line.split()[1:])
1053 process(cmd)()
1054 except Exception:
1055 printNicely(red('OMG something is wrong with Twitter right now.'))
1056 # Not redisplay prefix
7e4ccbf3 1057 if cmd in ['switch', 't', 'rt', 'rep']:
1dd312f5
O
1058 g['prefix'] = False
1059 else:
1060 g['prefix'] = True
54277114
O
1061
1062
42fde775 1063def stream(domain, args, name='Rainbow Stream'):
54277114 1064 """
f405a7d0 1065 Track the stream
54277114 1066 """
d51b4107 1067
54277114 1068 # The Logo
42fde775 1069 art_dict = {
632c6fa5
O
1070 c['USER_DOMAIN']: name,
1071 c['PUBLIC_DOMAIN']: args.track_keywords,
1072 c['SITE_DOMAIN']: 'Site Stream',
42fde775 1073 }
1074 ascii_art(art_dict[domain])
d51b4107 1075
91476ec3
O
1076 # These arguments are optional:
1077 stream_args = dict(
1078 timeout=args.timeout,
1079 block=not args.no_block,
1080 heartbeat_timeout=args.heartbeat_timeout)
1081
1082 # Track keyword
1083 query_args = dict()
1084 if args.track_keywords:
1085 query_args['track'] = args.track_keywords
1086
1087 # Get stream
2a6238f5 1088 stream = TwitterStream(
22be990e 1089 auth=authen(),
42fde775 1090 domain=domain,
2a6238f5 1091 **stream_args)
91476ec3 1092
632c6fa5 1093 if domain == c['USER_DOMAIN']:
42fde775 1094 tweet_iter = stream.user(**query_args)
632c6fa5 1095 elif domain == c['SITE_DOMAIN']:
42fde775 1096 tweet_iter = stream.site(**query_args)
1097 else:
1098 if args.track_keywords:
1099 tweet_iter = stream.statuses.filter(**query_args)
1100 else:
1101 tweet_iter = stream.statuses.sample()
1102
1103 # Iterate over the stream.
72c02928
VNM
1104 try:
1105 for tweet in tweet_iter:
1106 if tweet is None:
1107 printNicely("-- None --")
1108 elif tweet is Timeout:
1109 printNicely("-- Timeout --")
1110 elif tweet is HeartbeatTimeout:
1111 printNicely("-- Heartbeat Timeout --")
1112 elif tweet is Hangup:
1113 printNicely("-- Hangup --")
1114 elif tweet.get('text'):
1115 draw(
1116 t=tweet,
1117 iot=args.image_on_term,
1118 keyword=args.track_keywords,
1119 fil=args.filter,
1120 ig=args.ignore,
1121 )
1122 except:
1123 printNicely(magenta("I'm afraid we have problem with twitter'S maximum connection."))
1124 printNicely(magenta("Let's try again later."))
54277114
O
1125
1126
1127def fly():
1128 """
1129 Main function
1130 """
42fde775 1131 # Spawn stream process
1132 args = parse_arguments()
54277114 1133 get_decorated_name()
632c6fa5 1134 p = Process(target=stream, args=(c['USER_DOMAIN'], args, g['original_name']))
42fde775 1135 p.start()
1136
1137 # Start listen process
819569e8 1138 time.sleep(0.5)
c91f75f2 1139 g['reset'] = True
1dd312f5 1140 g['prefix'] = True
f405a7d0 1141 g['stream_pid'] = p.pid
c1fa7c94 1142 g['iot'] = args.image_on_term
0f6e4daf 1143 listen()