fix docs
[rainbowstream.git] / rainbowstream / rainbow.py
1 """
2 Colorful user's timeline stream
3 """
4 from multiprocessing import Process
5
6 import os
7 import os.path
8 import sys
9 import signal
10 import argparse
11 import time
12 import requests
13 import webbrowser
14 import json
15
16 from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
17 from twitter.api import *
18 from twitter.oauth import OAuth, read_token_file
19 from twitter.oauth_dance import oauth_dance
20 from twitter.util import printNicely
21
22 from .draw import *
23 from .colors import *
24 from .config import *
25 from .consumer import *
26 from .interactive import *
27 from .db import *
28 from .c_image import *
29 from .py3patch import *
30
31
32 g = {}
33 db = RainbowDB()
34 cmdset = [
35 'switch',
36 'trend',
37 'home',
38 'view',
39 'mentions',
40 't',
41 'rt',
42 'quote',
43 'allrt',
44 'fav',
45 'rep',
46 'del',
47 'ufav',
48 's',
49 'mes',
50 'show',
51 'open',
52 'ls',
53 'inbox',
54 'sent',
55 'trash',
56 'whois',
57 'fl',
58 'ufl',
59 'mute',
60 'unmute',
61 'muting',
62 'block',
63 'unblock',
64 'report',
65 'list',
66 'cal',
67 'theme',
68 'h',
69 'c',
70 'q'
71 ]
72
73
74 def parse_arguments():
75 """
76 Parse the arguments
77 """
78 parser = argparse.ArgumentParser(description=__doc__ or "")
79 parser.add_argument(
80 '-to',
81 '--timeout',
82 help='Timeout for the stream (seconds).')
83 parser.add_argument(
84 '-ht',
85 '--heartbeat-timeout',
86 help='Set heartbeat timeout.',
87 default=90)
88 parser.add_argument(
89 '-nb',
90 '--no-block',
91 action='store_true',
92 help='Set stream to non-blocking.')
93 parser.add_argument(
94 '-tt',
95 '--track-keywords',
96 help='Search the stream for specific text.')
97 parser.add_argument(
98 '-fil',
99 '--filter',
100 help='Filter specific screen_name.')
101 parser.add_argument(
102 '-ig',
103 '--ignore',
104 help='Ignore specific screen_name.')
105 parser.add_argument(
106 '-iot',
107 '--image-on-term',
108 action='store_true',
109 help='Display all image on terminal.')
110 return parser.parse_args()
111
112
113 def authen():
114 """
115 Authenticate with Twitter OAuth
116 """
117 # When using rainbow stream you must authorize.
118 twitter_credential = os.environ.get(
119 'HOME',
120 os.environ.get(
121 'USERPROFILE',
122 '')) + os.sep + '.rainbow_oauth'
123 if not os.path.exists(twitter_credential):
124 oauth_dance("Rainbow Stream",
125 CONSUMER_KEY,
126 CONSUMER_SECRET,
127 twitter_credential)
128 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
129 return OAuth(
130 oauth_token,
131 oauth_token_secret,
132 CONSUMER_KEY,
133 CONSUMER_SECRET)
134
135
136 def get_decorated_name():
137 """
138 Beginning of every line
139 """
140 t = Twitter(auth=authen())
141 name = '@' + t.account.verify_credentials()['screen_name']
142 g['original_name'] = name[1:]
143 g['decorated_name'] = color_func(c['DECORATED_NAME'])('[' + name + ']: ')
144
145 files = os.listdir(os.path.dirname(__file__) + '/colorset')
146 themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json']
147 g['themes'] = themes
148 db.theme_store(c['THEME'])
149
150
151 def switch():
152 """
153 Switch stream
154 """
155 try:
156 target = g['stuff'].split()[0]
157
158 # Filter and ignore
159 args = parse_arguments()
160 try:
161 if g['stuff'].split()[-1] == '-f':
162 only = raw_input('Only nicks: ')
163 ignore = raw_input('Ignore nicks: ')
164 args.filter = filter(None, only.split(','))
165 args.ignore = filter(None, ignore.split(','))
166 elif g['stuff'].split()[-1] == '-d':
167 args.filter = c['ONLY_LIST']
168 args.ignore = c['IGNORE_LIST']
169 except:
170 printNicely(red('Sorry, wrong format.'))
171 return
172
173 # Public stream
174 if target == 'public':
175 keyword = g['stuff'].split()[1]
176 if keyword[0] == '#':
177 keyword = keyword[1:]
178 # Kill old process
179 os.kill(g['stream_pid'], signal.SIGKILL)
180 args.track_keywords = keyword
181 # Start new process
182 p = Process(
183 target=stream,
184 args=(
185 c['PUBLIC_DOMAIN'],
186 args))
187 p.start()
188 g['stream_pid'] = p.pid
189
190 # Personal stream
191 elif target == 'mine':
192 # Kill old process
193 os.kill(g['stream_pid'], signal.SIGKILL)
194 # Start new process
195 p = Process(
196 target=stream,
197 args=(
198 c['USER_DOMAIN'],
199 args,
200 g['original_name']))
201 p.start()
202 g['stream_pid'] = p.pid
203 printNicely('')
204 if args.filter:
205 printNicely(cyan('Only: ' + str(args.filter)))
206 if args.ignore:
207 printNicely(red('Ignore: ' + str(args.ignore)))
208 printNicely('')
209 except:
210 printNicely(red('Sorry I can\'t understand.'))
211
212
213 def trend():
214 """
215 Trend
216 """
217 t = Twitter(auth=authen())
218 # Get country and town
219 try:
220 country = g['stuff'].split()[0]
221 except:
222 country = ''
223 try:
224 town = g['stuff'].split()[1]
225 except:
226 town = ''
227
228 avail = t.trends.available()
229 # World wide
230 if not country:
231 trends = t.trends.place(_id=1)[0]['trends']
232 print_trends(trends)
233 else:
234 for location in avail:
235 # Search for country and Town
236 if town:
237 if location['countryCode'] == country \
238 and location['placeType']['name'] == 'Town' \
239 and location['name'] == town:
240 trends = t.trends.place(_id=location['woeid'])[0]['trends']
241 print_trends(trends)
242 # Search for country only
243 else:
244 if location['countryCode'] == country \
245 and location['placeType']['name'] == 'Country':
246 trends = t.trends.place(_id=location['woeid'])[0]['trends']
247 print_trends(trends)
248
249
250 def home():
251 """
252 Home
253 """
254 t = Twitter(auth=authen())
255 num = c['HOME_TWEET_NUM']
256 if g['stuff'].isdigit():
257 num = int(g['stuff'])
258 for tweet in reversed(t.statuses.home_timeline(count=num)):
259 draw(t=tweet, iot=g['iot'])
260 printNicely('')
261
262
263 def view():
264 """
265 Friend view
266 """
267 t = Twitter(auth=authen())
268 user = g['stuff'].split()[0]
269 if user[0] == '@':
270 try:
271 num = int(g['stuff'].split()[1])
272 except:
273 num = c['HOME_TWEET_NUM']
274 for tweet in reversed(t.statuses.user_timeline(count=num, screen_name=user[1:])):
275 draw(t=tweet, iot=g['iot'])
276 printNicely('')
277 else:
278 printNicely(red('A name should begin with a \'@\''))
279
280
281 def mentions():
282 """
283 Mentions timeline
284 """
285 t = Twitter(auth=authen())
286 num = c['HOME_TWEET_NUM']
287 if g['stuff'].isdigit():
288 num = int(g['stuff'])
289 for tweet in reversed(t.statuses.mentions_timeline(count=num)):
290 draw(t=tweet, iot=g['iot'])
291 printNicely('')
292
293
294 def tweet():
295 """
296 Tweet
297 """
298 t = Twitter(auth=authen())
299 t.statuses.update(status=g['stuff'])
300
301
302 def retweet():
303 """
304 ReTweet
305 """
306 t = Twitter(auth=authen())
307 try:
308 id = int(g['stuff'].split()[0])
309 except:
310 printNicely(red('Sorry I can\'t understand.'))
311 return
312 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
313 t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
314
315
316 def quote():
317 """
318 Quote a tweet
319 """
320 t = Twitter(auth=authen())
321 try:
322 id = int(g['stuff'].split()[0])
323 except:
324 printNicely(red('Sorry I can\'t understand.'))
325 return
326 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
327 tweet = t.statuses.show(id=tid)
328 screen_name = tweet['user']['screen_name']
329 text = tweet['text']
330 quote = '\"@' + screen_name + ': ' + text + '\"'
331 quote = quote.encode('utf8')
332 notice = light_magenta('Compose mode ')
333 notice += light_yellow('(Enter nothing will cancel the quote)')
334 notice += light_magenta(':')
335 printNicely(notice)
336 extra = raw_input(quote)
337 if extra:
338 t.statuses.update(status=quote + extra)
339 else:
340 printNicely(light_magenta('No text added.'))
341
342
343 def allretweet():
344 """
345 List all retweet
346 """
347 t = Twitter(auth=authen())
348 # Get rainbow id
349 try:
350 id = int(g['stuff'].split()[0])
351 except:
352 printNicely(red('Sorry I can\'t understand.'))
353 return
354 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
355 # Get display num if exist
356 try:
357 num = int(g['stuff'].split()[1])
358 except:
359 num = c['RETWEETS_SHOW_NUM']
360 # Get result and display
361 rt_ary = t.statuses.retweets(id=tid, count=num)
362 if not rt_ary:
363 printNicely(magenta('This tweet has no retweet.'))
364 return
365 for tweet in reversed(rt_ary):
366 draw(t=tweet, iot=g['iot'])
367 printNicely('')
368
369
370 def favorite():
371 """
372 Favorite
373 """
374 t = Twitter(auth=authen())
375 try:
376 id = int(g['stuff'].split()[0])
377 except:
378 printNicely(red('Sorry I can\'t understand.'))
379 return
380 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
381 t.favorites.create(_id=tid, include_entities=False)
382 printNicely(green('Favorited.'))
383 draw(t.statuses.show(id=tid), iot=g['iot'])
384 printNicely('')
385
386
387 def reply():
388 """
389 Reply
390 """
391 t = Twitter(auth=authen())
392 try:
393 id = int(g['stuff'].split()[0])
394 except:
395 printNicely(red('Sorry I can\'t understand.'))
396 return
397 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
398 user = t.statuses.show(id=tid)['user']['screen_name']
399 status = ' '.join(g['stuff'].split()[1:])
400 status = '@' + user + ' ' + status.decode('utf-8')
401 t.statuses.update(status=status, in_reply_to_status_id=tid)
402
403
404 def delete():
405 """
406 Delete
407 """
408 t = Twitter(auth=authen())
409 try:
410 rid = int(g['stuff'].split()[0])
411 except:
412 printNicely(red('Sorry I can\'t understand.'))
413 return
414 tid = db.rainbow_to_tweet_query(rid)[0].tweet_id
415 t.statuses.destroy(id=tid)
416 printNicely(green('Okay it\'s gone.'))
417
418
419 def unfavorite():
420 """
421 Unfavorite
422 """
423 t = Twitter(auth=authen())
424 try:
425 id = int(g['stuff'].split()[0])
426 except:
427 printNicely(red('Sorry I can\'t understand.'))
428 return
429 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
430 t.favorites.destroy(_id=tid)
431 printNicely(green('Okay it\'s unfavorited.'))
432 draw(t.statuses.show(id=tid), iot=g['iot'])
433 printNicely('')
434
435
436 def search():
437 """
438 Search
439 """
440 t = Twitter(auth=authen())
441 g['stuff'] = g['stuff'].strip()
442 rel = t.search.tweets(q=g['stuff'])['statuses']
443 if rel:
444 printNicely('Newest tweets:')
445 for i in reversed(xrange(c['SEARCH_MAX_RECORD'])):
446 draw(t=rel[i],
447 iot=g['iot'],
448 keyword=g['stuff'])
449 printNicely('')
450 else:
451 printNicely(magenta('I\'m afraid there is no result'))
452
453
454 def message():
455 """
456 Send a direct message
457 """
458 t = Twitter(auth=authen())
459 user = g['stuff'].split()[0]
460 if user[0].startswith('@'):
461 try:
462 content = g['stuff'].split()[1]
463 except:
464 printNicely(red('Sorry I can\'t understand.'))
465 t.direct_messages.new(
466 screen_name=user[1:],
467 text=content
468 )
469 printNicely(green('Message sent.'))
470 else:
471 printNicely(red('A name should begin with a \'@\''))
472
473
474 def show():
475 """
476 Show image
477 """
478 t = Twitter(auth=authen())
479 try:
480 target = g['stuff'].split()[0]
481 if target != 'image':
482 return
483 id = int(g['stuff'].split()[1])
484 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
485 tweet = t.statuses.show(id=tid)
486 media = tweet['entities']['media']
487 for m in media:
488 res = requests.get(m['media_url'])
489 img = Image.open(BytesIO(res.content))
490 img.show()
491 except:
492 printNicely(red('Sorry I can\'t show this image.'))
493
494
495 def urlopen():
496 """
497 Open url
498 """
499 t = Twitter(auth=authen())
500 try:
501 if not g['stuff'].isdigit():
502 return
503 tid = db.rainbow_to_tweet_query(g['stuff'])[0].tweet_id
504 tweet = t.statuses.show(id=tid)
505 link_ary = [
506 u for u in tweet['text'].split() if u.startswith('http://')]
507 if not link_ary:
508 printNicely(light_magenta('No url here @.@!'))
509 return
510 for link in link_ary:
511 webbrowser.open(link)
512 except:
513 printNicely(red('Sorry I can\'t open url in this tweet.'))
514
515
516 def ls():
517 """
518 List friends for followers
519 """
520 t = Twitter(auth=authen())
521 # Get name
522 try:
523 name = g['stuff'].split()[1]
524 if name.startswith('@'):
525 name = name[1:]
526 else:
527 printNicely(red('A name should begin with a \'@\''))
528 raise Exception('Invalid name')
529 except:
530 name = g['original_name']
531 # Get list followers or friends
532 try:
533 target = g['stuff'].split()[0]
534 except:
535 printNicely(red('Omg some syntax is wrong.'))
536 # Init cursor
537 d = {'fl': 'followers', 'fr': 'friends'}
538 next_cursor = -1
539 rel = {}
540 # Cursor loop
541 while next_cursor != 0:
542 list = getattr(t, d[target]).list(
543 screen_name=name,
544 cursor=next_cursor,
545 skip_status=True,
546 include_entities=False,
547 )
548 for u in list['users']:
549 rel[u['name']] = '@' + u['screen_name']
550 next_cursor = list['next_cursor']
551 # Print out result
552 printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.')
553 for name in rel:
554 user = ' ' + cycle_color(name)
555 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
556 printNicely(user)
557
558
559 def inbox():
560 """
561 Inbox direct messages
562 """
563 t = Twitter(auth=authen())
564 num = c['MESSAGES_DISPLAY']
565 rel = []
566 if g['stuff'].isdigit():
567 num = g['stuff']
568 cur_page = 1
569 # Max message per page is 20 so we have to loop
570 while num > 20:
571 rel = rel + t.direct_messages(
572 count=20,
573 page=cur_page,
574 include_entities=False,
575 skip_status=False
576 )
577 num -= 20
578 cur_page += 1
579 rel = rel + t.direct_messages(
580 count=num,
581 page=cur_page,
582 include_entities=False,
583 skip_status=False
584 )
585 # Display
586 printNicely('Inbox: newest ' + str(len(rel)) + ' messages.')
587 for m in reversed(rel):
588 print_message(m)
589 printNicely('')
590
591
592 def sent():
593 """
594 Sent direct messages
595 """
596 t = Twitter(auth=authen())
597 num = c['MESSAGES_DISPLAY']
598 rel = []
599 if g['stuff'].isdigit():
600 num = int(g['stuff'])
601 cur_page = 1
602 # Max message per page is 20 so we have to loop
603 while num > 20:
604 rel = rel + t.direct_messages.sent(
605 count=20,
606 page=cur_page,
607 include_entities=False,
608 skip_status=False
609 )
610 num -= 20
611 cur_page += 1
612 rel = rel + t.direct_messages.sent(
613 count=num,
614 page=cur_page,
615 include_entities=False,
616 skip_status=False
617 )
618 # Display
619 printNicely('Sent: newest ' + str(len(rel)) + ' messages.')
620 for m in reversed(rel):
621 print_message(m)
622 printNicely('')
623
624
625 def trash():
626 """
627 Remove message
628 """
629 t = Twitter(auth=authen())
630 try:
631 rid = int(g['stuff'].split()[0])
632 except:
633 printNicely(red('Sorry I can\'t understand.'))
634 mid = db.rainbow_to_message_query(rid)[0].message_id
635 t.direct_messages.destroy(id=mid)
636 printNicely(green('Message deleted.'))
637
638
639 def whois():
640 """
641 Show profile of a specific user
642 """
643 t = Twitter(auth=authen())
644 screen_name = g['stuff'].split()[0]
645 if screen_name.startswith('@'):
646 try:
647 user = t.users.show(
648 screen_name=screen_name[1:],
649 include_entities=False)
650 show_profile(user, g['iot'])
651 except:
652 printNicely(red('Omg no user.'))
653 else:
654 printNicely(red('A name should begin with a \'@\''))
655
656
657 def follow():
658 """
659 Follow a user
660 """
661 t = Twitter(auth=authen())
662 screen_name = g['stuff'].split()[0]
663 if screen_name.startswith('@'):
664 t.friendships.create(screen_name=screen_name[1:], follow=True)
665 printNicely(green('You are following ' + screen_name + ' now!'))
666 else:
667 printNicely(red('A name should begin with a \'@\''))
668
669
670 def unfollow():
671 """
672 Unfollow a user
673 """
674 t = Twitter(auth=authen())
675 screen_name = g['stuff'].split()[0]
676 if screen_name.startswith('@'):
677 t.friendships.destroy(
678 screen_name=screen_name[1:],
679 include_entities=False)
680 printNicely(green('Unfollow ' + screen_name + ' success!'))
681 else:
682 printNicely(red('A name should begin with a \'@\''))
683
684
685 def mute():
686 """
687 Mute a user
688 """
689 t = Twitter(auth=authen())
690 try:
691 screen_name = g['stuff'].split()[0]
692 except:
693 printNicely(red('A name should be specified. '))
694 return
695 if screen_name.startswith('@'):
696 rel = t.mutes.users.create(screen_name=screen_name[1:])
697 if isinstance(rel, dict):
698 printNicely(green(screen_name + ' is muted.'))
699 else:
700 printNicely(red(rel))
701 else:
702 printNicely(red('A name should begin with a \'@\''))
703
704
705 def unmute():
706 """
707 Unmute a user
708 """
709 t = Twitter(auth=authen())
710 try:
711 screen_name = g['stuff'].split()[0]
712 except:
713 printNicely(red('A name should be specified. '))
714 return
715 if screen_name.startswith('@'):
716 rel = t.mutes.users.destroy(screen_name=screen_name[1:])
717 if isinstance(rel, dict):
718 printNicely(green(screen_name + ' is unmuted.'))
719 else:
720 printNicely(red(rel))
721 else:
722 printNicely(red('A name should begin with a \'@\''))
723
724
725 def muting():
726 """
727 List muting user
728 """
729 t = Twitter(auth=authen())
730 # Init cursor
731 next_cursor = -1
732 rel = {}
733 # Cursor loop
734 while next_cursor != 0:
735 list = t.mutes.users.list(
736 screen_name=g['original_name'],
737 cursor=next_cursor,
738 skip_status=True,
739 include_entities=False,
740 )
741 for u in list['users']:
742 rel[u['name']] = '@' + u['screen_name']
743 next_cursor = list['next_cursor']
744 # Print out result
745 printNicely('All: ' + str(len(rel)) + ' people.')
746 for name in rel:
747 user = ' ' + cycle_color(name)
748 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
749 printNicely(user)
750
751
752 def block():
753 """
754 Block a user
755 """
756 t = Twitter(auth=authen())
757 screen_name = g['stuff'].split()[0]
758 if screen_name.startswith('@'):
759 t.blocks.create(
760 screen_name=screen_name[1:],
761 include_entities=False,
762 skip_status=True)
763 printNicely(green('You blocked ' + screen_name + '.'))
764 else:
765 printNicely(red('A name should begin with a \'@\''))
766
767
768 def unblock():
769 """
770 Unblock a user
771 """
772 t = Twitter(auth=authen())
773 screen_name = g['stuff'].split()[0]
774 if screen_name.startswith('@'):
775 t.blocks.destroy(
776 screen_name=screen_name[1:],
777 include_entities=False,
778 skip_status=True)
779 printNicely(green('Unblock ' + screen_name + ' success!'))
780 else:
781 printNicely(red('A name should begin with a \'@\''))
782
783
784 def report():
785 """
786 Report a user as a spam account
787 """
788 t = Twitter(auth=authen())
789 screen_name = g['stuff'].split()[0]
790 if screen_name.startswith('@'):
791 t.users.report_spam(
792 screen_name=screen_name[1:])
793 printNicely(green('You reported ' + screen_name + '.'))
794 else:
795 printNicely(red('Sorry I can\'t understand.'))
796
797
798 def get_slug():
799 """
800 Get Slug Decorator
801 """
802 # Get list name
803 list_name = raw_input(light_magenta('Give me the list\'s name: '))
804 # Get list name and owner
805 try:
806 owner, slug = list_name.split('/')
807 if slug.startswith('@'):
808 slug = slug[1:]
809 return owner, slug
810 except:
811 printNicely(light_magenta('List name should follow "@owner/list_name" format.'))
812 raise Exception('Wrong list name')
813
814
815 def show_lists(t):
816 """
817 List list
818 """
819 rel = t.lists.list(screen_name=g['original_name'])
820 if rel:
821 print_list(rel)
822 else:
823 printNicely(light_magenta('You belong to no lists :)'))
824
825
826 def list_home(t):
827 """
828 List home
829 """
830 owner, slug = get_slug()
831 res = t.lists.statuses(
832 slug=slug,
833 owner_screen_name=owner,
834 count=c['LIST_MAX'],
835 include_entities=False)
836 for tweet in res:
837 draw(t=tweet)
838 printNicely('')
839
840
841 def list_members(t):
842 """
843 List members
844 """
845 owner, slug = get_slug()
846 # Get members
847 rel = {}
848 next_cursor = -1
849 while next_cursor != 0:
850 m = t.lists.members(
851 slug=slug,
852 owner_screen_name=owner,
853 cursor=next_cursor,
854 include_entities=False)
855 for u in m['users']:
856 rel[u['name']] = '@' + u['screen_name']
857 next_cursor = m['next_cursor']
858 printNicely('All: ' + str(len(rel)) + ' members.')
859 for name in rel:
860 user = ' ' + cycle_color(name)
861 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
862 printNicely(user)
863
864
865 def list_subscribers(t):
866 """
867 List subscribers
868 """
869 owner, slug = get_slug()
870 # Get subscribers
871 rel = {}
872 next_cursor = -1
873 while next_cursor != 0:
874 m = t.lists.subscribers(
875 slug=slug,
876 owner_screen_name=owner,
877 cursor=next_cursor,
878 include_entities=False)
879 for u in m['users']:
880 rel[u['name']] = '@' + u['screen_name']
881 next_cursor = m['next_cursor']
882 printNicely('All: ' + str(len(rel)) + ' subscribers.')
883 for name in rel:
884 user = ' ' + cycle_color(name)
885 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
886 printNicely(user)
887
888
889 def list_add(t):
890 """
891 Add specific user to a list
892 """
893 owner, slug = get_slug()
894 # Add
895 user_name = raw_input(light_magenta('Give me name of the newbie: '))
896 if user_name.startswith('@'):
897 user_name = user_name[1:]
898 try:
899 t.lists.members.create(
900 slug=slug,
901 owner_screen_name=owner,
902 screen_name=user_name)
903 printNicely(light_green('Added.'))
904 except:
905 printNicely(light_magenta('I\'m sorry we can not add him/her.'))
906
907
908 def list_remove(t):
909 """
910 Remove specific user from a list
911 """
912 owner, slug = get_slug()
913 # Remove
914 user_name = raw_input(light_magenta('Give me name of the unlucky one: '))
915 if user_name.startswith('@'):
916 user_name = user_name[1:]
917 try:
918 t.lists.members.destroy(
919 slug=slug,
920 owner_screen_name=owner,
921 screen_name=user_name)
922 printNicely(light_green('Gone.'))
923 except:
924 printNicely(light_magenta('I\'m sorry we can not remove him/her.'))
925
926
927 def list_subscribe(t):
928 """
929 Subscribe to a list
930 """
931 owner, slug = get_slug()
932 # Subscribe
933 try:
934 t.lists.subscribers.create(
935 slug=slug,
936 owner_screen_name=owner)
937 printNicely(light_green('Done.'))
938 except:
939 printNicely(
940 light_magenta('I\'m sorry you can not subscribe to this list.'))
941
942
943 def list_unsubscribe(t):
944 """
945 Unsubscribe a list
946 """
947 owner, slug = get_slug()
948 # Subscribe
949 try:
950 t.lists.subscribers.destroy(
951 slug=slug,
952 owner_screen_name=owner)
953 printNicely(light_green('Done.'))
954 except:
955 printNicely(
956 light_magenta('I\'m sorry you can not unsubscribe to this list.'))
957
958
959 def list_own(t):
960 """
961 List own
962 """
963 rel = []
964 next_cursor = -1
965 while next_cursor != 0:
966 res = t.lists.ownerships(
967 screen_name=g['original_name'],
968 cursor=next_cursor)
969 rel += res['lists']
970 next_cursor = res['next_cursor']
971 if rel:
972 print_list(rel)
973 else:
974 printNicely(light_magenta('You own no lists :)'))
975
976
977 def list_new(t):
978 """
979 Create a new list
980 """
981 name = raw_input(light_magenta('New list\'s name: '))
982 mode = raw_input(light_magenta('New list\'s mode (public/private): '))
983 description = raw_input(light_magenta('New list\'s description: '))
984 try:
985 t.lists.create(
986 name=name,
987 mode=mode,
988 description=description)
989 printNicely(light_green(name + ' list is created.'))
990 except:
991 printNicely(red('Oops something is wrong with Twitter :('))
992
993
994 def list_update(t):
995 """
996 Update a list
997 """
998 slug = raw_input(light_magenta('Your list that you want to update: '))
999 name = raw_input(light_magenta('Update name (leave blank to unchange): '))
1000 mode = raw_input(light_magenta('Update mode (public/private): '))
1001 description = raw_input(light_magenta('Update description: '))
1002 try:
1003 if name:
1004 t.lists.update(
1005 slug='-'.join(slug.split()),
1006 owner_screen_name=g['original_name'],
1007 name=name,
1008 mode=mode,
1009 description=description)
1010 else:
1011 t.lists.update(
1012 slug=slug,
1013 owner_screen_name=g['original_name'],
1014 mode=mode,
1015 description=description)
1016 printNicely(light_green(slug + ' list is updated.'))
1017 except:
1018 printNicely(red('Oops something is wrong with Twitter :('))
1019
1020
1021 def list_delete(t):
1022 """
1023 Delete a list
1024 """
1025 slug = raw_input(light_magenta('Your list that you want to update: '))
1026 try:
1027 t.lists.destroy(
1028 slug='-'.join(slug.split()),
1029 owner_screen_name=g['original_name'])
1030 printNicely(light_green(slug + ' list is deleted.'))
1031 except:
1032 printNicely(red('Oops something is wrong with Twitter :('))
1033
1034
1035 def list():
1036 """
1037 Twitter's list
1038 """
1039 t = Twitter(auth=authen())
1040 # List all lists or base on action
1041 try:
1042 g['list_action'] = g['stuff'].split()[0]
1043 except:
1044 show_lists(t)
1045 return
1046 # Sub-function
1047 action_ary = {
1048 'home': list_home,
1049 'all_mem': list_members,
1050 'all_sub': list_subscribers,
1051 'add': list_add,
1052 'rm': list_remove,
1053 'sub': list_subscribe,
1054 'unsub': list_unsubscribe,
1055 'own': list_own,
1056 'new': list_new,
1057 'update': list_update,
1058 'del': list_delete,
1059 }
1060 try:
1061 return action_ary[g['list_action']](t)
1062 except:
1063 printNicely(red('Please try again.'))
1064
1065
1066 def cal():
1067 """
1068 Unix's command `cal`
1069 """
1070 # Format
1071 rel = os.popen('cal').read().split('\n')
1072 month = rel.pop(0)
1073 date = rel.pop(0)
1074 show_calendar(month, date, rel)
1075
1076
1077 def theme():
1078 """
1079 List and change theme
1080 """
1081 if not g['stuff']:
1082 # List themes
1083 for theme in g['themes']:
1084 line = light_magenta(theme)
1085 if c['THEME'] == theme:
1086 line = ' ' * 2 + light_yellow('* ') + line
1087 else:
1088 line = ' ' * 4 + line
1089 printNicely(line)
1090 elif g['stuff'] == 'current_as_default':
1091 # Set as default
1092 def fixup(adict, k, v):
1093 for key in adict.keys():
1094 if key == k:
1095 adict[key] = v
1096 elif type(adict[key]) is dict:
1097 fixup(adict[key], k, v)
1098 # Modify
1099 path = os.environ.get(
1100 'HOME',
1101 os.environ.get(
1102 'USERPROFILE',
1103 '')) + os.sep + '.rainbow_config.json'
1104 data = load_config(rainbow_config)
1105 fixup(data, 'THEME', c['THEME'])
1106 # Save
1107 with open(path, 'w') as out:
1108 json.dump(data, out, indent = 4)
1109 os.system('chmod 777 ' + path)
1110 printNicely(light_green('Okay it will be applied from next time :)'))
1111 else:
1112 # Change theme
1113 try:
1114 # Load new config
1115 if g['stuff'] != 'custom':
1116 new_config = os.path.dirname(
1117 __file__) + '/colorset/' + g['stuff'] + '.json'
1118 else:
1119 new_config = os.environ.get(
1120 'HOME', os.environ.get(
1121 'USERPROFILE',
1122 '')) + os.sep + '.rainbow_config.json'
1123 new_config = load_config(new_config)
1124 if new_config:
1125 for nc in new_config:
1126 c[nc] = new_config[nc]
1127 # Update db and reset colors
1128 db.theme_update(g['stuff'])
1129 c['THEME'] = g['stuff']
1130 start_cycle()
1131 g['decorated_name'] = color_func(
1132 c['DECORATED_NAME'])(
1133 '[@' + g['original_name'] + ']: ')
1134 printNicely(green('Theme changed.'))
1135 except:
1136 printNicely(red('No such theme exists.'))
1137
1138
1139 def help_discover():
1140 """
1141 Discover the world
1142 """
1143 s = ' ' * 2
1144 # Discover the world
1145 usage = '\n'
1146 usage += s + grey(u'\u266A' + ' Discover the world \n')
1147 usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \
1148 'You can try ' + light_green('trend US') + ' or ' + \
1149 light_green('trend JP Tokyo') + '.\n'
1150 usage += s * 2 + light_green('home') + ' will show your timeline. ' + \
1151 light_green('home 7') + ' will show 7 tweets.\n'
1152 usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \
1153 light_green('mentions 7') + ' will show 7 mention tweets.\n'
1154 usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \
1155 magenta('@mdo') + '.\n'
1156 usage += s * 2 + light_green('view @mdo') + \
1157 ' will show ' + magenta('@mdo') + '\'s home.\n'
1158 usage += s * 2 + light_green('s AKB48') + ' will search for "' + \
1159 light_yellow('AKB48') + '" and return 5 newest tweet. ' + \
1160 'Search can be performed with or without hashtag.\n'
1161 printNicely(usage)
1162
1163
1164 def help_tweets():
1165 """
1166 Tweets
1167 """
1168 s = ' ' * 2
1169 # Tweet
1170 usage = '\n'
1171 usage += s + grey(u'\u266A' + ' Tweets \n')
1172 usage += s * 2 + light_green('t oops ') + \
1173 'will tweet "' + light_yellow('oops') + '" immediately.\n'
1174 usage += s * 2 + \
1175 light_green('rt 12 ') + ' will retweet to tweet with ' + \
1176 light_yellow('[id=12]') + '.\n'
1177 usage += s * 2 + \
1178 light_green('quote 12 ') + ' will quote the tweet with ' + \
1179 light_yellow('[id=12]') + '. If no extra text is added, ' + \
1180 'the quote will be canceled.\n'
1181 usage += s * 2 + \
1182 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
1183 light_yellow('[id=12]') + '.\n'
1184 usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \
1185 light_yellow('oops') + '" to tweet with ' + \
1186 light_yellow('[id=12]') + '.\n'
1187 usage += s * 2 + \
1188 light_green('fav 12 ') + ' will favorite the tweet with ' + \
1189 light_yellow('[id=12]') + '.\n'
1190 usage += s * 2 + \
1191 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
1192 light_yellow('[id=12]') + '.\n'
1193 usage += s * 2 + \
1194 light_green('del 12 ') + ' will delete tweet with ' + \
1195 light_yellow('[id=12]') + '.\n'
1196 usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \
1197 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
1198 usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \
1199 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
1200 printNicely(usage)
1201
1202
1203 def help_messages():
1204 """
1205 Messages
1206 """
1207 s = ' ' * 2
1208 # Direct message
1209 usage = '\n'
1210 usage += s + grey(u'\u266A' + ' Direct messages \n')
1211 usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \
1212 light_green('inbox 7') + ' will show newest 7 messages.\n'
1213 usage += s * 2 + light_green('sent') + ' will show sent messages. ' + \
1214 light_green('sent 7') + ' will show newest 7 messages.\n'
1215 usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
1216 magenta('@dtvd88') + '.\n'
1217 usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \
1218 light_yellow('[message_id=5]') + '.\n'
1219 printNicely(usage)
1220
1221
1222 def help_friends_and_followers():
1223 """
1224 Friends and Followers
1225 """
1226 s = ' ' * 2
1227 # Follower and following
1228 usage = '\n'
1229 usage += s + grey(u'\u266A' + ' Friends and followers \n')
1230 usage += s * 2 + \
1231 light_green('ls fl') + \
1232 ' will list all followers (people who are following you).\n'
1233 usage += s * 2 + \
1234 light_green('ls fr') + \
1235 ' will list all friends (people who you are following).\n'
1236 usage += s * 2 + light_green('fl @dtvd88') + ' will follow ' + \
1237 magenta('@dtvd88') + '.\n'
1238 usage += s * 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
1239 magenta('@dtvd88') + '.\n'
1240 usage += s * 2 + light_green('mute @dtvd88') + ' will mute ' + \
1241 magenta('@dtvd88') + '.\n'
1242 usage += s * 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
1243 magenta('@dtvd88') + '.\n'
1244 usage += s * 2 + light_green('muting') + ' will list muting users.\n'
1245 usage += s * 2 + light_green('block @dtvd88') + ' will block ' + \
1246 magenta('@dtvd88') + '.\n'
1247 usage += s * 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
1248 magenta('@dtvd88') + '.\n'
1249 usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \
1250 magenta('@dtvd88') + ' as a spam account.\n'
1251 printNicely(usage)
1252
1253
1254 def help_list():
1255 """
1256 Lists
1257 """
1258 s = ' ' * 2
1259 # Twitter list
1260 usage = '\n'
1261 usage += s + grey(u'\u266A' + ' Twitter list\n')
1262 usage += s * 2 + light_green('list') + \
1263 ' will show all lists you are belong to.\n'
1264 usage += s * 2 + light_green('list home') + \
1265 ' will show timeline of list. You will be asked for list\'s name.\n'
1266 usage += s * 2 + light_green('list all_mem') + \
1267 ' will show list\'s all members.\n'
1268 usage += s * 2 + light_green('list all_sub') + \
1269 ' will show list\'s all subscribers.\n'
1270 usage += s * 2 + light_green('list add') + \
1271 ' will add specific person to a list owned by you.' + \
1272 ' You will be asked for list\'s name and person\'s name.\n'
1273 usage += s * 2 + light_green('list rm') + \
1274 ' will remove specific person from a list owned by you.' + \
1275 ' You will be asked for list\'s name and person\'s name.\n'
1276 usage += s * 2 + light_green('list sub') + \
1277 ' will subscribe you to a specific list.\n'
1278 usage += s * 2 + light_green('list unsub') + \
1279 ' will unsubscribe you from a specific list.\n'
1280 usage += s * 2 + light_green('list own') + \
1281 ' will show all list owned by you.\n'
1282 usage += s * 2 + light_green('list new') + \
1283 ' will create a new list.\n'
1284 usage += s * 2 + light_green('list update') + \
1285 ' will update a list owned by you.\n'
1286 usage += s * 2 + light_green('list del') + \
1287 ' will delete a list owned by you.\n'
1288 printNicely(usage)
1289
1290
1291 def help_stream():
1292 """
1293 Stream switch
1294 """
1295 s = ' ' * 2
1296 # Switch
1297 usage = '\n'
1298 usage += s + grey(u'\u266A' + ' Switching streams \n')
1299 usage += s * 2 + light_green('switch public #AKB') + \
1300 ' will switch to public stream and follow "' + \
1301 light_yellow('AKB') + '" keyword.\n'
1302 usage += s * 2 + light_green('switch mine') + \
1303 ' will switch to your personal stream.\n'
1304 usage += s * 2 + light_green('switch mine -f ') + \
1305 ' will prompt to enter the filter.\n'
1306 usage += s * 3 + light_yellow('Only nicks') + \
1307 ' filter will decide nicks will be INCLUDE ONLY.\n'
1308 usage += s * 3 + light_yellow('Ignore nicks') + \
1309 ' filter will decide nicks will be EXCLUDE.\n'
1310 usage += s * 2 + light_green('switch mine -d') + \
1311 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
1312 printNicely(usage)
1313
1314
1315 def help():
1316 """
1317 Help
1318 """
1319 s = ' ' * 2
1320 h, w = os.popen('stty size', 'r').read().split()
1321
1322 # Start
1323 usage = '\n'
1324 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
1325 usage += s + '-' * (int(w) - 4) + '\n'
1326 usage += s + 'You are ' + \
1327 light_yellow('already') + ' on your personal stream.\n'
1328 usage += s + 'Any update from Twitter will show up ' + \
1329 light_yellow('immediately') + '.\n'
1330 usage += s + 'In addtion, following commands are available right now:\n'
1331
1332 # Twitter help section
1333 usage += '\n'
1334 usage += s + grey(u'\u266A' + ' Twitter help\n')
1335 usage += s * 2 + light_green('h discover') + \
1336 ' will show help for discover commands.\n'
1337 usage += s * 2 + light_green('h tweets') + \
1338 ' will show help for tweets commands.\n'
1339 usage += s * 2 + light_green('h messages') + \
1340 ' will show help for messages commands.\n'
1341 usage += s * 2 + light_green('h friends_and_followers') + \
1342 ' will show help for friends and followers commands.\n'
1343 usage += s * 2 + light_green('h list') + \
1344 ' will show help for list commands.\n'
1345 usage += s * 2 + light_green('h stream') + \
1346 ' will show help for stream commands.\n'
1347
1348 # Smart shell
1349 usage += '\n'
1350 usage += s + grey(u'\u266A' + ' Smart shell\n')
1351 usage += s * 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
1352 'will be evaluate by Python interpreter.\n'
1353 usage += s * 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
1354 ' for current month.\n'
1355
1356 # Screening
1357 usage += '\n'
1358 usage += s + grey(u'\u266A' + ' Screening \n')
1359 usage += s * 2 + light_green('theme') + ' will list available theme.' + \
1360 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
1361 ' theme immediately.\n'
1362 usage += s * 2 + light_green('h') + ' will show this help again.\n'
1363 usage += s * 2 + light_green('c') + ' will clear the screen.\n'
1364 usage += s * 2 + light_green('q') + ' will quit.\n'
1365
1366 # End
1367 usage += '\n'
1368 usage += s + '-' * (int(w) - 4) + '\n'
1369 usage += s + 'Have fun and hang tight! \n'
1370
1371 # Show help
1372 d = {
1373 'discover': help_discover,
1374 'tweets': help_tweets,
1375 'messages': help_messages,
1376 'friends_and_followers': help_friends_and_followers,
1377 'list': help_list,
1378 'stream': help_stream,
1379 }
1380 if g['stuff']:
1381 d[g['stuff'].strip()]()
1382 else:
1383 printNicely(usage)
1384
1385
1386 def clear():
1387 """
1388 Clear screen
1389 """
1390 os.system('clear')
1391
1392
1393 def quit():
1394 """
1395 Exit all
1396 """
1397 save_history()
1398 os.system('rm -rf rainbow.db')
1399 os.kill(g['stream_pid'], signal.SIGKILL)
1400 sys.exit()
1401
1402
1403 def reset():
1404 """
1405 Reset prefix of line
1406 """
1407 if g['reset']:
1408 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
1409 g['reset'] = False
1410 try:
1411 printNicely(str(eval(g['cmd'])))
1412 except Exception:
1413 pass
1414
1415
1416 def process(cmd):
1417 """
1418 Process switch
1419 """
1420 return dict(zip(
1421 cmdset,
1422 [
1423 switch,
1424 trend,
1425 home,
1426 view,
1427 mentions,
1428 tweet,
1429 retweet,
1430 quote,
1431 allretweet,
1432 favorite,
1433 reply,
1434 delete,
1435 unfavorite,
1436 search,
1437 message,
1438 show,
1439 urlopen,
1440 ls,
1441 inbox,
1442 sent,
1443 trash,
1444 whois,
1445 follow,
1446 unfollow,
1447 mute,
1448 unmute,
1449 muting,
1450 block,
1451 unblock,
1452 report,
1453 list,
1454 cal,
1455 theme,
1456 help,
1457 clear,
1458 quit
1459 ]
1460 )).get(cmd, reset)
1461
1462
1463 def listen():
1464 """
1465 Listen to user's input
1466 """
1467 d = dict(zip(
1468 cmdset,
1469 [
1470 ['public', 'mine'], # switch
1471 [], # trend
1472 [], # home
1473 ['@'], # view
1474 [], # mentions
1475 [], # tweet
1476 [], # retweet
1477 [], # quote
1478 [], # allretweet
1479 [], # favorite
1480 [], # reply
1481 [], # delete
1482 [], # unfavorite
1483 ['#'], # search
1484 ['@'], # message
1485 ['image'], # show image
1486 [''], # open url
1487 ['fl', 'fr'], # list
1488 [], # inbox
1489 [], # sent
1490 [], # trash
1491 ['@'], # whois
1492 ['@'], # follow
1493 ['@'], # unfollow
1494 ['@'], # mute
1495 ['@'], # unmute
1496 ['@'], # muting
1497 ['@'], # block
1498 ['@'], # unblock
1499 ['@'], # report
1500 [
1501 'home',
1502 'all_mem',
1503 'all_sub',
1504 'add',
1505 'rm',
1506 'sub',
1507 'unsub',
1508 'own',
1509 'new',
1510 'update',
1511 'del'
1512 ], # list
1513 [], # cal
1514 g['themes'] + ['current_as_default'], # theme
1515 [
1516 'discover',
1517 'tweets',
1518 'messages',
1519 'friends_and_followers',
1520 'list',
1521 'stream'
1522 ], # help
1523 [], # clear
1524 [], # quit
1525 ]
1526 ))
1527 init_interactive_shell(d)
1528 read_history()
1529 reset()
1530 while True:
1531 if g['prefix']:
1532 line = raw_input(g['decorated_name'])
1533 else:
1534 line = raw_input()
1535 try:
1536 cmd = line.split()[0]
1537 except:
1538 cmd = ''
1539 g['cmd'] = cmd
1540 # Save cmd to global variable and call process
1541 try:
1542 g['stuff'] = ' '.join(line.split()[1:])
1543 process(cmd)()
1544 except Exception:
1545 printNicely(red('OMG something is wrong with Twitter right now.'))
1546 # Not redisplay prefix
1547 if cmd in ['switch', 't', 'rt', 'rep']:
1548 g['prefix'] = False
1549 else:
1550 g['prefix'] = True
1551
1552
1553 def stream(domain, args, name='Rainbow Stream'):
1554 """
1555 Track the stream
1556 """
1557
1558 # The Logo
1559 art_dict = {
1560 c['USER_DOMAIN']: name,
1561 c['PUBLIC_DOMAIN']: args.track_keywords,
1562 c['SITE_DOMAIN']: name,
1563 }
1564 if c['ASCII_ART']:
1565 ascii_art(art_dict[domain])
1566
1567 # These arguments are optional:
1568 stream_args = dict(
1569 timeout=args.timeout,
1570 block=not args.no_block,
1571 heartbeat_timeout=args.heartbeat_timeout)
1572
1573 # Track keyword
1574 query_args = dict()
1575 if args.track_keywords:
1576 query_args['track'] = args.track_keywords
1577
1578 # Get stream
1579 stream = TwitterStream(
1580 auth=authen(),
1581 domain=domain,
1582 **stream_args)
1583
1584 try:
1585 if domain == c['USER_DOMAIN']:
1586 tweet_iter = stream.user(**query_args)
1587 elif domain == c['SITE_DOMAIN']:
1588 tweet_iter = stream.site(**query_args)
1589 else:
1590 if args.track_keywords:
1591 tweet_iter = stream.statuses.filter(**query_args)
1592 else:
1593 tweet_iter = stream.statuses.sample()
1594
1595 # Iterate over the stream.
1596 for tweet in tweet_iter:
1597 if tweet is None:
1598 printNicely("-- None --")
1599 elif tweet is Timeout:
1600 printNicely("-- Timeout --")
1601 elif tweet is HeartbeatTimeout:
1602 printNicely("-- Heartbeat Timeout --")
1603 elif tweet is Hangup:
1604 printNicely("-- Hangup --")
1605 elif tweet.get('text'):
1606 draw(
1607 t=tweet,
1608 iot=args.image_on_term,
1609 keyword=args.track_keywords,
1610 fil=args.filter,
1611 ig=args.ignore,
1612 )
1613 except TwitterHTTPError:
1614 printNicely('')
1615 printNicely(
1616 magenta("We have maximum connection problem with twitter'stream API right now :("))
1617
1618
1619 def fly():
1620 """
1621 Main function
1622 """
1623 # Spawn stream process
1624 args = parse_arguments()
1625 try:
1626 get_decorated_name()
1627
1628 except TwitterHTTPError:
1629 printNicely('')
1630 printNicely(
1631 magenta("Something wrong with Twitter Oauth right now :("))
1632 printNicely(
1633 magenta("Please delete ~/.rainbow_oauth and try again."))
1634 save_history()
1635 os.system('rm -rf rainbow.db')
1636 sys.exit()
1637
1638 p = Process(
1639 target=stream,
1640 args=(
1641 c['USER_DOMAIN'],
1642 args,
1643 g['original_name']))
1644 p.start()
1645
1646 # Start listen process
1647 time.sleep(0.5)
1648 g['reset'] = True
1649 g['prefix'] = True
1650 g['stream_pid'] = p.pid
1651 g['iot'] = args.image_on_term
1652 listen()