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