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