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