add linebreak after favorite
[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
147bb4a2 131 tweet = map(lambda x: cyan(x) if x[0:4] == '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'])
bb6d4e4e 540 printNicely('')
7e4ccbf3 541 except:
542 printNicely(red('Omg some syntax is wrong.'))
543
544
7b674cef 545def reply():
829cc2d8 546 """
7b674cef 547 Reply
829cc2d8
O
548 """
549 t = Twitter(auth=authen())
7b674cef 550 try:
551 id = int(g['stuff'].split()[0])
305ce127 552 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
18cab06a 553 user = t.statuses.show(id=tid)['user']['screen_name']
7b674cef 554 status = ' '.join(g['stuff'].split()[1:])
555 status = '@' + user + ' ' + status.decode('utf-8')
18cab06a 556 t.statuses.update(status=status, in_reply_to_status_id=tid)
7b674cef 557 except:
c91f75f2 558 printNicely(red('Sorry I can\'t understand.'))
7b674cef 559
560
561def delete():
562 """
563 Delete
564 """
565 t = Twitter(auth=authen())
566 try:
305ce127 567 rid = int(g['stuff'].split()[0])
568 tid = db.rainbow_to_tweet_query(rid)[0].tweet_id
18cab06a 569 t.statuses.destroy(id=tid)
c91f75f2 570 printNicely(green('Okay it\'s gone.'))
7b674cef 571 except:
305ce127 572 printNicely(red('Sorry I can\'t understand.'))
829cc2d8
O
573
574
7e4ccbf3 575def unfavorite():
576 """
577 Unfavorite
578 """
579 t = Twitter(auth=authen())
580 try:
581 id = int(g['stuff'].split()[0])
305ce127 582 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
7e4ccbf3 583 t.favorites.destroy(_id=tid)
584 printNicely(green('Okay it\'s unfavorited.'))
c1fa7c94 585 draw(t.statuses.show(id=tid), iot=g['iot'])
bb6d4e4e 586 printNicely('')
7e4ccbf3 587 except:
588 printNicely(red('Sorry I can\'t unfavorite this tweet for you.'))
589
590
f405a7d0
O
591def search():
592 """
7b674cef 593 Search
f405a7d0
O
594 """
595 t = Twitter(auth=authen())
94a5f62e 596 try:
597 if g['stuff'][0] == '#':
598 rel = t.search.tweets(q=g['stuff'])['statuses']
c91f75f2 599 if len(rel):
600 printNicely('Newest tweets:')
601 for i in reversed(xrange(SEARCH_MAX_RECORD)):
88af38d8 602 draw(t=rel[i],
0f6e4daf 603 iot=g['iot'],
604 keyword=g['stuff'].strip()[1:])
c91f75f2 605 printNicely('')
606 else:
607 printNicely(magenta('I\'m afraid there is no result'))
94a5f62e 608 else:
c91f75f2 609 printNicely(red('A keyword should be a hashtag (like \'#AKB48\')'))
94a5f62e 610 except:
c91f75f2 611 printNicely(red('Sorry I can\'t understand.'))
b2b933a9 612
f405a7d0 613
305ce127 614def message():
615 """
616 Send a direct message
617 """
618 t = Twitter(auth=authen())
619 user = g['stuff'].split()[0]
620 if user[0] == '@':
621 try:
622 content = g['stuff'].split()[1]
623 t.direct_messages.new(
624 screen_name=user[1:],
625 text=content
48a25fe8 626 )
305ce127 627 printNicely(green('Message sent.'))
628 except:
629 printNicely(red('Sorry I can\'t understand.'))
630 else:
631 printNicely(red('A name should begin with a \'@\''))
632
633
f5677fb1 634def show():
843647ad 635 """
f5677fb1 636 Show image
843647ad
O
637 """
638 t = Twitter(auth=authen())
f5677fb1
O
639 try:
640 target = g['stuff'].split()[0]
641 if target != 'image':
642 return
643 id = int(g['stuff'].split()[1])
305ce127 644 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
f5677fb1
O
645 tweet = t.statuses.show(id=tid)
646 media = tweet['entities']['media']
647 for m in media:
648 res = requests.get(m['media_url'])
649 img = Image.open(StringIO(res.content))
650 img.show()
651 except:
652 printNicely(red('Sorry I can\'t show this image.'))
843647ad
O
653
654
0f6e4daf 655def list():
656 """
657 List friends for followers
658 """
659 t = Twitter(auth=authen())
e2b81717
O
660 # Get name
661 try:
662 name = g['stuff'].split()[1]
663 if name[0] == '@':
664 name = name[1:]
665 else:
666 printNicely(red('A name should begin with a \'@\''))
667 raise Exception('Invalid name')
668 except:
669 name = g['original_name']
670 # Get list followers or friends
0f6e4daf 671 try:
672 target = g['stuff'].split()[0]
673 d = {'fl': 'followers', 'fr': 'friends'}
674 next_cursor = -1
675 rel = {}
676 # Cursor loop
677 while next_cursor != 0:
305ce127 678 list = getattr(t, d[target]).list(
e2b81717 679 screen_name=name,
305ce127 680 cursor=next_cursor,
681 skip_status=True,
682 include_entities=False,
48a25fe8 683 )
0f6e4daf 684 for u in list['users']:
685 rel[u['name']] = '@' + u['screen_name']
686 next_cursor = list['next_cursor']
687 # Print out result
688 printNicely('All: ' + str(len(rel)) + ' people.')
689 for name in rel:
690 user = ' ' + cycle_color(name) + grey(' ' + rel[name] + ' ')
691 printNicely(user)
692 except:
693 printNicely(red('Omg some syntax is wrong.'))
694
695
305ce127 696def inbox():
697 """
698 Inbox direct messages
699 """
700 t = Twitter(auth=authen())
701 num = MESSAGES_DISPLAY
702 rel = []
703 if g['stuff'].isdigit():
704 num = g['stuff']
705 cur_page = 1
706 # Max message per page is 20 so we have to loop
707 while num > 20:
708 rel = rel + t.direct_messages(
709 count=20,
710 page=cur_page,
711 include_entities=False,
712 skip_status=False
48a25fe8 713 )
305ce127 714 num -= 20
715 cur_page += 1
716 rel = rel + t.direct_messages(
717 count=num,
718 page=cur_page,
719 include_entities=False,
720 skip_status=False
48a25fe8 721 )
e2b81717 722 # Display
305ce127 723 printNicely('Inbox: newest ' + str(len(rel)) + ' messages.')
724 for m in reversed(rel):
725 print_message(m)
726 printNicely('')
727
e2b81717 728
305ce127 729def sent():
730 """
731 Sent direct messages
732 """
733 t = Twitter(auth=authen())
734 num = MESSAGES_DISPLAY
735 rel = []
736 if g['stuff'].isdigit():
737 num = int(g['stuff'])
738 cur_page = 1
739 # Max message per page is 20 so we have to loop
740 while num > 20:
741 rel = rel + t.direct_messages.sent(
742 count=20,
743 page=cur_page,
744 include_entities=False,
745 skip_status=False
48a25fe8 746 )
305ce127 747 num -= 20
748 cur_page += 1
749 rel = rel + t.direct_messages.sent(
750 count=num,
751 page=cur_page,
752 include_entities=False,
753 skip_status=False
48a25fe8 754 )
e2b81717 755 # Display
305ce127 756 printNicely('Sent: newest ' + str(len(rel)) + ' messages.')
757 for m in reversed(rel):
758 print_message(m)
759 printNicely('')
e2b81717 760
305ce127 761
762def trash():
763 """
764 Remove message
765 """
766 t = Twitter(auth=authen())
767 try:
768 rid = int(g['stuff'].split()[0])
769 mid = db.rainbow_to_message_query(rid)[0].message_id
770 t.direct_messages.destroy(id=mid)
771 printNicely(green('Message deleted.'))
772 except:
773 printNicely(red('Sorry I can\'t understand.'))
774
775
e2b81717
O
776def whois():
777 """
778 Show profile of a specific user
779 """
780 t = Twitter(auth=authen())
781 screen_name = g['stuff'].split()[0]
782 if screen_name[0] == '@':
783 try:
784 user = t.users.show(
785 screen_name=screen_name[1:],
786 include_entities=False)
787 show_profile(user)
788 except:
789 printNicely(red('Omg no user.'))
790 else:
791 printNicely(red('Sorry I can\'t understand.'))
792
793
f5677fb1 794def follow():
843647ad 795 """
f5677fb1 796 Follow a user
843647ad
O
797 """
798 t = Twitter(auth=authen())
f5677fb1
O
799 screen_name = g['stuff'].split()[0]
800 if screen_name[0] == '@':
0f6e4daf 801 try:
802 t.friendships.create(screen_name=screen_name[1:], follow=True)
f5677fb1
O
803 printNicely(green('You are following ' + screen_name + ' now!'))
804 except:
805 printNicely(red('Sorry can not follow at this time.'))
806 else:
807 printNicely(red('Sorry I can\'t understand.'))
808
809
810def unfollow():
811 """
812 Unfollow a user
813 """
814 t = Twitter(auth=authen())
815 screen_name = g['stuff'].split()[0]
816 if screen_name[0] == '@':
0f6e4daf 817 try:
818 t.friendships.destroy(
305ce127 819 screen_name=screen_name[1:],
0f6e4daf 820 include_entities=False)
f5677fb1
O
821 printNicely(green('Unfollow ' + screen_name + ' success!'))
822 except:
823 printNicely(red('Sorry can not unfollow at this time.'))
824 else:
825 printNicely(red('Sorry I can\'t understand.'))
843647ad
O
826
827
305ce127 828def block():
829 """
830 Block a user
831 """
832 t = Twitter(auth=authen())
833 screen_name = g['stuff'].split()[0]
834 if screen_name[0] == '@':
835 try:
836 t.blocks.create(
e2b81717 837 screen_name=screen_name[1:],
305ce127 838 include_entities=False,
839 skip_status=True)
840 printNicely(green('You blocked ' + screen_name + '.'))
841 except:
842 printNicely(red('Sorry something went wrong.'))
843 else:
844 printNicely(red('Sorry I can\'t understand.'))
845
846
847def unblock():
848 """
849 Unblock a user
850 """
851 t = Twitter(auth=authen())
852 screen_name = g['stuff'].split()[0]
853 if screen_name[0] == '@':
854 try:
855 t.blocks.destroy(
856 screen_name=screen_name[1:],
857 include_entities=False,
858 skip_status=True)
859 printNicely(green('Unblock ' + screen_name + ' success!'))
860 except:
861 printNicely(red('Sorry something went wrong.'))
862 else:
863 printNicely(red('Sorry I can\'t understand.'))
864
865
866def report():
867 """
868 Report a user as a spam account
869 """
870 t = Twitter(auth=authen())
871 screen_name = g['stuff'].split()[0]
872 if screen_name[0] == '@':
873 try:
874 t.users.report_spam(
e2b81717 875 screen_name=screen_name[1:])
305ce127 876 printNicely(green('You reported ' + screen_name + '.'))
877 except:
878 printNicely(red('Sorry something went wrong.'))
879 else:
880 printNicely(red('Sorry I can\'t understand.'))
881
882
f405a7d0
O
883def help():
884 """
7b674cef 885 Help
f405a7d0 886 """
7e4ccbf3 887 s = ' ' * 2
888 h, w = os.popen('stty size', 'r').read().split()
e3885f55
O
889
890 usage = '\n'
891 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
7e4ccbf3 892 usage += s + '-' * (int(w) - 4) + '\n'
7e4ccbf3 893 usage += s + 'You are ' + yellow('already') + ' on your personal stream.\n'
e3885f55 894
d03d632b 895 usage += s * 2 + green('trend') + ' will show global trending topics. ' + \
48a25fe8 896 'You can try ' + green('trend US') + ' or ' + \
897 green('trend JP Tokyo') + '.\n'
7e4ccbf3 898 usage += s * 2 + green('home') + ' will show your timeline. ' + \
305ce127 899 green('home 7') + ' will show 7 tweets.\n'
7e4ccbf3 900 usage += s * 2 + green('view @mdo') + \
305ce127 901 ' will show ' + magenta('@mdo') + '\'s home.\n'
902 usage += s * 2 + green('mentions') + ' will show mentions timeline. ' + \
e2b81717 903 green('mentions 7') + ' will show 7 mention tweets.\n'
7e4ccbf3 904 usage += s * 2 + green('t oops ') + \
905 'will tweet "' + yellow('oops') + '" immediately.\n'
906 usage += s * 2 + \
907 green('rt 12 ') + ' will retweet to tweet with ' + \
908 yellow('[id=12]') + '.\n'
909 usage += s * 2 + \
910 green('fav 12 ') + ' will favorite the tweet with ' + \
911 yellow('[id=12]') + '.\n'
912 usage += s * 2 + green('rep 12 oops') + ' will reply "' + \
913 yellow('oops') + '" to tweet with ' + yellow('[id=12]') + '.\n'
914 usage += s * 2 + \
915 green('del 12 ') + ' will delete tweet with ' + \
916 yellow('[id=12]') + '.\n'
917 usage += s * 2 + \
918 green('ufav 12 ') + ' will unfavorite tweet with ' + \
919 yellow('[id=12]') + '.\n'
920 usage += s * 2 + green('s #AKB48') + ' will search for "' + \
921 yellow('AKB48') + '" and return 5 newest tweet.\n'
305ce127 922 usage += s * 2 + green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
923 magenta('@dtvd88') + '.\n'
a99b7b04
O
924 usage += s * 2 + green('show image 12') + ' will show image in tweet with ' + \
925 yellow('[id=12]') + ' in your OS\'s image viewer.\n'
0f6e4daf 926 usage += s * 2 + \
927 green('ls fl') + \
b5f92888 928 ' will list all followers (people who are following you).\n'
0f6e4daf 929 usage += s * 2 + \
930 green('ls fr') + \
931 ' will list all friends (people who you are following).\n'
305ce127 932 usage += s * 2 + green('inbox') + ' will show inbox messages. ' + \
933 green('inbox 7') + ' will show newest 7 messages.\n'
934 usage += s * 2 + green('sent') + ' will show sent messages. ' + \
935 green('sent 7') + ' will show newest 7 messages.\n'
936 usage += s * 2 + green('trash 5') + ' will remove message with ' + \
937 yellow('[message_id=5]') + '.\n'
e2b81717
O
938 usage += s * 2 + green('whois @dtvd88') + ' will show profile of ' + \
939 magenta('@dtvd88') + '.\n'
f5677fb1 940 usage += s * 2 + green('fl @dtvd88') + ' will follow ' + \
305ce127 941 magenta('@dtvd88') + '.\n'
f5677fb1 942 usage += s * 2 + green('ufl @dtvd88') + ' will unfollow ' + \
305ce127 943 magenta('@dtvd88') + '.\n'
944 usage += s * 2 + green('block @dtvd88') + ' will block ' + \
945 magenta('@dtvd88') + '.\n'
946 usage += s * 2 + green('unblock @dtvd88') + ' will unblock ' + \
947 magenta('@dtvd88') + '.\n'
948 usage += s * 2 + green('report @dtvd88') + ' will report ' + \
949 magenta('@dtvd88') + ' as a spam account.\n'
7e4ccbf3 950 usage += s * 2 + green('h') + ' will show this help again.\n'
951 usage += s * 2 + green('c') + ' will clear the screen.\n'
952 usage += s * 2 + green('q') + ' will quit.\n'
953
48a25fe8 954 usage += s + 'For switching streams: \n'
955 usage += s * 2 + green('switch public #AKB') + \
956 ' will switch to public stream and follow "' + \
957 yellow('AKB') + '" keyword.\n'
958 usage += s * 2 + green('switch mine') + \
959 ' will switch to your personal stream.\n'
960 usage += s * 2 + green('switch mine -f ') + \
961 ' will prompt to enter the filter.\n'
962 usage += s * 3 + yellow('Only nicks') + \
963 ' filter will decide nicks will be INCLUDE ONLY.\n'
964 usage += s * 3 + yellow('Ignore nicks') + \
965 ' filter will decide nicks will be EXCLUDE.\n'
966 usage += s * 2 + green('switch mine -d') + \
967 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
968 usage += s * 3 + '(see ' + grey('rainbowstream/config.py') + ').\n'
969
7e4ccbf3 970 usage += s + '-' * (int(w) - 4) + '\n'
e3885f55 971 usage += s + 'Have fun and hang tight!\n'
f405a7d0 972 printNicely(usage)
f405a7d0
O
973
974
843647ad 975def clear():
f405a7d0 976 """
7b674cef 977 Clear screen
f405a7d0 978 """
843647ad 979 os.system('clear')
f405a7d0
O
980
981
843647ad 982def quit():
b8dda704
O
983 """
984 Exit all
985 """
f5677fb1 986 save_history()
8e633322 987 os.system('rm -rf rainbow.db')
843647ad
O
988 os.kill(g['stream_pid'], signal.SIGKILL)
989 sys.exit()
b8dda704
O
990
991
94a5f62e 992def reset():
f405a7d0 993 """
94a5f62e 994 Reset prefix of line
f405a7d0 995 """
c91f75f2 996 if g['reset']:
e3885f55 997 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
c91f75f2 998 g['reset'] = False
54277114
O
999
1000
94a5f62e 1001def process(cmd):
54277114 1002 """
94a5f62e 1003 Process switch
54277114 1004 """
94a5f62e 1005 return dict(zip(
1006 cmdset,
b2b933a9 1007 [
42fde775 1008 switch,
4592d231 1009 trend,
b2b933a9 1010 home,
1011 view,
305ce127 1012 mentions,
b2b933a9 1013 tweet,
1014 retweet,
7e4ccbf3 1015 favorite,
b2b933a9 1016 reply,
1017 delete,
7e4ccbf3 1018 unfavorite,
b2b933a9 1019 search,
305ce127 1020 message,
f5677fb1 1021 show,
0f6e4daf 1022 list,
305ce127 1023 inbox,
1024 sent,
1025 trash,
e2b81717 1026 whois,
f5677fb1
O
1027 follow,
1028 unfollow,
305ce127 1029 block,
1030 unblock,
1031 report,
b2b933a9 1032 help,
1033 clear,
1034 quit
1035 ]
94a5f62e 1036 )).get(cmd, reset)
1037
1038
1039def listen():
42fde775 1040 """
1041 Listen to user's input
1042 """
d51b4107
O
1043 d = dict(zip(
1044 cmdset,
1045 [
affcb149 1046 ['public', 'mine'], # switch
4592d231 1047 [], # trend
7e4ccbf3 1048 [], # home
1049 ['@'], # view
305ce127 1050 [], # mentions
7e4ccbf3 1051 [], # tweet
1052 [], # retweet
f5677fb1 1053 [], # favorite
7e4ccbf3 1054 [], # reply
1055 [], # delete
f5677fb1 1056 [], # unfavorite
7e4ccbf3 1057 ['#'], # search
305ce127 1058 ['@'], # message
f5677fb1 1059 ['image'], # show image
305ce127 1060 ['fl', 'fr'], # list
1061 [], # inbox
1062 [], # sent
1063 [], # trash
e2b81717 1064 ['@'], # whois
affcb149
O
1065 ['@'], # follow
1066 ['@'], # unfollow
305ce127 1067 ['@'], # block
1068 ['@'], # unblock
1069 ['@'], # report
7e4ccbf3 1070 [], # help
1071 [], # clear
1072 [], # quit
d51b4107 1073 ]
7e4ccbf3 1074 ))
d51b4107 1075 init_interactive_shell(d)
f5677fb1 1076 read_history()
819569e8 1077 reset()
b2b933a9 1078 while True:
1dd312f5
O
1079 if g['prefix']:
1080 line = raw_input(g['decorated_name'])
1081 else:
1082 line = raw_input()
843647ad
O
1083 try:
1084 cmd = line.split()[0]
1085 except:
1086 cmd = ''
f405a7d0 1087 # Save cmd to global variable and call process
843647ad
O
1088 g['stuff'] = ' '.join(line.split()[1:])
1089 process(cmd)()
7e4ccbf3 1090 if cmd in ['switch', 't', 'rt', 'rep']:
1dd312f5
O
1091 g['prefix'] = False
1092 else:
1093 g['prefix'] = True
54277114
O
1094
1095
42fde775 1096def stream(domain, args, name='Rainbow Stream'):
54277114 1097 """
f405a7d0 1098 Track the stream
54277114 1099 """
d51b4107 1100
54277114 1101 # The Logo
42fde775 1102 art_dict = {
1103 USER_DOMAIN: name,
1104 PUBLIC_DOMAIN: args.track_keywords,
1105 SITE_DOMAIN: 'Site Stream',
1106 }
1107 ascii_art(art_dict[domain])
d51b4107 1108
91476ec3
O
1109 # These arguments are optional:
1110 stream_args = dict(
1111 timeout=args.timeout,
1112 block=not args.no_block,
1113 heartbeat_timeout=args.heartbeat_timeout)
1114
1115 # Track keyword
1116 query_args = dict()
1117 if args.track_keywords:
1118 query_args['track'] = args.track_keywords
1119
1120 # Get stream
2a6238f5 1121 stream = TwitterStream(
22be990e 1122 auth=authen(),
42fde775 1123 domain=domain,
2a6238f5 1124 **stream_args)
91476ec3 1125
42fde775 1126 if domain == USER_DOMAIN:
1127 tweet_iter = stream.user(**query_args)
1128 elif domain == SITE_DOMAIN:
1129 tweet_iter = stream.site(**query_args)
1130 else:
1131 if args.track_keywords:
1132 tweet_iter = stream.statuses.filter(**query_args)
1133 else:
1134 tweet_iter = stream.statuses.sample()
1135
1136 # Iterate over the stream.
91476ec3
O
1137 for tweet in tweet_iter:
1138 if tweet is None:
1139 printNicely("-- None --")
1140 elif tweet is Timeout:
1141 printNicely("-- Timeout --")
1142 elif tweet is HeartbeatTimeout:
1143 printNicely("-- Heartbeat Timeout --")
1144 elif tweet is Hangup:
1145 printNicely("-- Hangup --")
1146 elif tweet.get('text'):
7e4ccbf3 1147 draw(
1148 t=tweet,
c1fa7c94 1149 iot=args.image_on_term,
7e4ccbf3 1150 keyword=args.track_keywords,
1151 fil=args.filter,
88af38d8 1152 ig=args.ignore,
0f6e4daf 1153 )
54277114
O
1154
1155
1156def fly():
1157 """
1158 Main function
1159 """
42fde775 1160 # Spawn stream process
1161 args = parse_arguments()
54277114 1162 get_decorated_name()
42fde775 1163 p = Process(target=stream, args=(USER_DOMAIN, args, g['original_name']))
1164 p.start()
1165
1166 # Start listen process
819569e8 1167 time.sleep(0.5)
c91f75f2 1168 g['reset'] = True
1dd312f5 1169 g['prefix'] = True
f405a7d0 1170 g['stream_pid'] = p.pid
c1fa7c94 1171 g['iot'] = args.image_on_term
0f6e4daf 1172 listen()