f31fa23308f284988d5a918b9880c5eefbe4c694
2 Colorful user's timeline stream
4 from multiprocessing
import Process
14 from twitter
.stream
import TwitterStream
, Timeout
, HeartbeatTimeout
, Hangup
15 from twitter
.api
import *
16 from twitter
.oauth
import OAuth
, read_token_file
17 from twitter
.oauth_dance
import oauth_dance
18 from twitter
.util
import printNicely
19 from StringIO
import StringIO
24 from .consumer
import *
25 from .interactive
import *
27 from .c_image
import *
67 def parse_arguments():
71 parser
= argparse
.ArgumentParser(description
=__doc__
or "")
75 help='Timeout for the stream (seconds).')
78 '--heartbeat-timeout',
79 help='Set heartbeat timeout.',
85 help='Set stream to non-blocking.')
89 help='Search the stream for specific text.')
93 help='Filter specific screen_name.')
97 help='Ignore specific screen_name.')
102 help='Display all image on terminal.')
103 return parser
.parse_args()
108 Authenticate with Twitter OAuth
110 # When using rainbow stream you must authorize.
111 twitter_credential
= os
.environ
.get(
115 '')) + os
.sep
+ '.rainbow_oauth'
116 if not os
.path
.exists(twitter_credential
):
117 oauth_dance("Rainbow Stream",
121 oauth_token
, oauth_token_secret
= read_token_file(twitter_credential
)
129 def get_decorated_name():
131 Beginning of every line
133 t
= Twitter(auth
=authen())
134 name
= '@' + t
.account
.verify_credentials()['screen_name']
135 g
['original_name'] = name
[1:]
136 g
['decorated_name'] = grey('[') + grey(name
) + grey(']: ')
138 files
= os
.listdir('rainbowstream/colorset')
139 themes
= [f
.split('.')[0] for f
in files
if f
.split('.')[-1]=='json']
148 target
= g
['stuff'].split()[0]
151 args
= parse_arguments()
153 if g
['stuff'].split()[-1] == '-f':
154 only
= raw_input('Only nicks: ')
155 ignore
= raw_input('Ignore nicks: ')
156 args
.filter = filter(None, only
.split(','))
157 args
.ignore
= filter(None, ignore
.split(','))
158 elif g
['stuff'].split()[-1] == '-d':
159 args
.filter = c
['ONLY_LIST']
160 args
.ignore
= c
['IGNORE_LIST']
162 printNicely(red('Sorry, wrong format.'))
166 if target
== 'public':
167 keyword
= g
['stuff'].split()[1]
168 if keyword
[0] == '#':
169 keyword
= keyword
[1:]
171 os
.kill(g
['stream_pid'], signal
.SIGKILL
)
172 args
.track_keywords
= keyword
180 g
['stream_pid'] = p
.pid
183 elif target
== 'mine':
185 os
.kill(g
['stream_pid'], signal
.SIGKILL
)
194 g
['stream_pid'] = p
.pid
196 printNicely(green('Stream switched.'))
198 printNicely(cyan('Only: ' + str(args
.filter)))
200 printNicely(red('Ignore: ' + str(args
.ignore
)))
203 printNicely(red('Sorry I can\'t understand.'))
210 t
= Twitter(auth
=authen())
211 # Get country and town
213 country
= g
['stuff'].split()[0]
217 town
= g
['stuff'].split()[1]
221 avail
= t
.trends
.available()
224 trends
= t
.trends
.place(_id
=1)[0]['trends']
227 for location
in avail
:
228 # Search for country and Town
230 if location
['countryCode'] == country \
231 and location
['placeType']['name'] == 'Town' \
232 and location
['name'] == town
:
233 trends
= t
.trends
.place(_id
=location
['woeid'])[0]['trends']
235 # Search for country only
237 if location
['countryCode'] == country \
238 and location
['placeType']['name'] == 'Country':
239 trends
= t
.trends
.place(_id
=location
['woeid'])[0]['trends']
247 t
= Twitter(auth
=authen())
248 num
= c
['HOME_TWEET_NUM']
249 if g
['stuff'].isdigit():
250 num
= int(g
['stuff'])
251 for tweet
in reversed(t
.statuses
.home_timeline(count
=num
)):
252 draw(t
=tweet
, iot
=g
['iot'])
260 t
= Twitter(auth
=authen())
261 user
= g
['stuff'].split()[0]
264 num
= int(g
['stuff'].split()[1])
266 num
= c
['HOME_TWEET_NUM']
267 for tweet
in reversed(t
.statuses
.user_timeline(count
=num
, screen_name
=user
[1:])):
268 draw(t
=tweet
, iot
=g
['iot'])
271 printNicely(red('A name should begin with a \'@\''))
278 t
= Twitter(auth
=authen())
279 num
= c
['HOME_TWEET_NUM']
280 if g
['stuff'].isdigit():
281 num
= int(g
['stuff'])
282 for tweet
in reversed(t
.statuses
.mentions_timeline(count
=num
)):
283 draw(t
=tweet
, iot
=g
['iot'])
291 t
= Twitter(auth
=authen())
292 t
.statuses
.update(status
=g
['stuff'])
299 t
= Twitter(auth
=authen())
301 id = int(g
['stuff'].split()[0])
303 printNicely(red('Sorry I can\'t understand.'))
305 tid
= db
.rainbow_to_tweet_query(id)[0].tweet_id
306 t
.statuses
.retweet(id=tid
, include_entities
=False, trim_user
=True)
313 t
= Twitter(auth
=authen())
316 id = int(g
['stuff'].split()[0])
318 printNicely(red('Sorry I can\'t understand.'))
320 tid
= db
.rainbow_to_tweet_query(id)[0].tweet_id
321 # Get display num if exist
323 num
= int(g
['stuff'].split()[1])
325 num
= c
['RETWEETS_SHOW_NUM']
326 # Get result and display
327 rt_ary
= t
.statuses
.retweets(id=tid
, count
=num
)
329 printNicely(magenta('This tweet has no retweet.'))
331 for tweet
in reversed(rt_ary
):
332 draw(t
=tweet
, iot
=g
['iot'])
340 t
= Twitter(auth
=authen())
342 id = int(g
['stuff'].split()[0])
344 printNicely(red('Sorry I can\'t understand.'))
346 tid
= db
.rainbow_to_tweet_query(id)[0].tweet_id
347 t
.favorites
.create(_id
=tid
, include_entities
=False)
348 printNicely(green('Favorited.'))
349 draw(t
.statuses
.show(id=tid
), iot
=g
['iot'])
357 t
= Twitter(auth
=authen())
359 id = int(g
['stuff'].split()[0])
361 printNicely(red('Sorry I can\'t understand.'))
363 tid
= db
.rainbow_to_tweet_query(id)[0].tweet_id
364 user
= t
.statuses
.show(id=tid
)['user']['screen_name']
365 status
= ' '.join(g
['stuff'].split()[1:])
366 status
= '@' + user
+ ' ' + status
.decode('utf-8')
367 t
.statuses
.update(status
=status
, in_reply_to_status_id
=tid
)
374 t
= Twitter(auth
=authen())
376 rid
= int(g
['stuff'].split()[0])
378 printNicely(red('Sorry I can\'t understand.'))
380 tid
= db
.rainbow_to_tweet_query(rid
)[0].tweet_id
381 t
.statuses
.destroy(id=tid
)
382 printNicely(green('Okay it\'s gone.'))
389 t
= Twitter(auth
=authen())
391 id = int(g
['stuff'].split()[0])
393 printNicely(red('Sorry I can\'t understand.'))
395 tid
= db
.rainbow_to_tweet_query(id)[0].tweet_id
396 t
.favorites
.destroy(_id
=tid
)
397 printNicely(green('Okay it\'s unfavorited.'))
398 draw(t
.statuses
.show(id=tid
), iot
=g
['iot'])
406 t
= Twitter(auth
=authen())
407 if g
['stuff'].startswith('#'):
408 rel
= t
.search
.tweets(q
=g
['stuff'])['statuses']
410 printNicely('Newest tweets:')
411 for i
in reversed(xrange(c
['SEARCH_MAX_RECORD'])):
414 keyword
=g
['stuff'].strip()[1:])
417 printNicely(magenta('I\'m afraid there is no result'))
419 printNicely(red('A keyword should be a hashtag (like \'#AKB48\')'))
424 Send a direct message
426 t
= Twitter(auth
=authen())
427 user
= g
['stuff'].split()[0]
428 if user
[0].startswith('@'):
430 content
= g
['stuff'].split()[1]
432 printNicely(red('Sorry I can\'t understand.'))
433 t
.direct_messages
.new(
434 screen_name
=user
[1:],
437 printNicely(green('Message sent.'))
439 printNicely(red('A name should begin with a \'@\''))
446 t
= Twitter(auth
=authen())
448 target
= g
['stuff'].split()[0]
449 if target
!= 'image':
451 id = int(g
['stuff'].split()[1])
452 tid
= db
.rainbow_to_tweet_query(id)[0].tweet_id
453 tweet
= t
.statuses
.show(id=tid
)
454 media
= tweet
['entities']['media']
456 res
= requests
.get(m
['media_url'])
457 img
= Image
.open(StringIO(res
.content
))
460 printNicely(red('Sorry I can\'t show this image.'))
465 List friends for followers
467 t
= Twitter(auth
=authen())
470 name
= g
['stuff'].split()[1]
471 if name
.startswith('@'):
474 printNicely(red('A name should begin with a \'@\''))
475 raise Exception('Invalid name')
477 name
= g
['original_name']
478 # Get list followers or friends
480 target
= g
['stuff'].split()[0]
482 printNicely(red('Omg some syntax is wrong.'))
484 d
= {'fl': 'followers', 'fr': 'friends'}
488 while next_cursor
!= 0:
489 list = getattr(t
, d
[target
]).list(
493 include_entities
=False,
495 for u
in list['users']:
496 rel
[u
['name']] = '@' + u
['screen_name']
497 next_cursor
= list['next_cursor']
499 printNicely('All: ' + str(len(rel
)) + ' people.')
501 user
= ' ' + cycle_color(name
) + grey(' ' + rel
[name
] + ' ')
507 Inbox direct messages
509 t
= Twitter(auth
=authen())
510 num
= c
['MESSAGES_DISPLAY']
512 if g
['stuff'].isdigit():
515 # Max message per page is 20 so we have to loop
517 rel
= rel
+ t
.direct_messages(
520 include_entities
=False,
525 rel
= rel
+ t
.direct_messages(
528 include_entities
=False,
532 printNicely('Inbox: newest ' + str(len(rel
)) + ' messages.')
533 for m
in reversed(rel
):
542 t
= Twitter(auth
=authen())
543 num
= c
['MESSAGES_DISPLAY']
545 if g
['stuff'].isdigit():
546 num
= int(g
['stuff'])
548 # Max message per page is 20 so we have to loop
550 rel
= rel
+ t
.direct_messages
.sent(
553 include_entities
=False,
558 rel
= rel
+ t
.direct_messages
.sent(
561 include_entities
=False,
565 printNicely('Sent: newest ' + str(len(rel
)) + ' messages.')
566 for m
in reversed(rel
):
575 t
= Twitter(auth
=authen())
577 rid
= int(g
['stuff'].split()[0])
579 printNicely(red('Sorry I can\'t understand.'))
580 mid
= db
.rainbow_to_message_query(rid
)[0].message_id
581 t
.direct_messages
.destroy(id=mid
)
582 printNicely(green('Message deleted.'))
587 Show profile of a specific user
589 t
= Twitter(auth
=authen())
590 screen_name
= g
['stuff'].split()[0]
591 if screen_name
.startswith('@'):
594 screen_name
=screen_name
[1:],
595 include_entities
=False)
596 show_profile(user
, g
['iot'])
598 printNicely(red('Omg no user.'))
600 printNicely(red('A name should begin with a \'@\''))
607 t
= Twitter(auth
=authen())
608 screen_name
= g
['stuff'].split()[0]
609 if screen_name
.startswith('@'):
610 t
.friendships
.create(screen_name
=screen_name
[1:], follow
=True)
611 printNicely(green('You are following ' + screen_name
+ ' now!'))
613 printNicely(red('A name should begin with a \'@\''))
620 t
= Twitter(auth
=authen())
621 screen_name
= g
['stuff'].split()[0]
622 if screen_name
.startswith('@'):
623 t
.friendships
.destroy(
624 screen_name
=screen_name
[1:],
625 include_entities
=False)
626 printNicely(green('Unfollow ' + screen_name
+ ' success!'))
628 printNicely(red('A name should begin with a \'@\''))
635 t
= Twitter(auth
=authen())
637 screen_name
= g
['stuff'].split()[0]
639 printNicely(red('A name should be specified. '))
641 if screen_name
.startswith('@'):
642 rel
= t
.mutes
.users
.create(screen_name
=screen_name
[1:])
643 if isinstance(rel
, dict):
644 printNicely(green(screen_name
+ ' is muted.'))
646 printNicely(red(rel
))
648 printNicely(red('A name should begin with a \'@\''))
655 t
= Twitter(auth
=authen())
657 screen_name
= g
['stuff'].split()[0]
659 printNicely(red('A name should be specified. '))
661 if screen_name
.startswith('@'):
662 rel
= t
.mutes
.users
.destroy(screen_name
=screen_name
[1:])
663 if isinstance(rel
, dict):
664 printNicely(green(screen_name
+ ' is unmuted.'))
666 printNicely(red(rel
))
668 printNicely(red('A name should begin with a \'@\''))
675 t
= Twitter(auth
=authen())
680 while next_cursor
!= 0:
681 list = t
.mutes
.users
.list(
682 screen_name
=g
['original_name'],
685 include_entities
=False,
687 for u
in list['users']:
688 rel
[u
['name']] = '@' + u
['screen_name']
689 next_cursor
= list['next_cursor']
691 printNicely('All: ' + str(len(rel
)) + ' people.')
693 user
= ' ' + cycle_color(name
) + grey(' ' + rel
[name
] + ' ')
701 t
= Twitter(auth
=authen())
702 screen_name
= g
['stuff'].split()[0]
703 if screen_name
.startswith('@'):
705 screen_name
=screen_name
[1:],
706 include_entities
=False,
708 printNicely(green('You blocked ' + screen_name
+ '.'))
710 printNicely(red('A name should begin with a \'@\''))
717 t
= Twitter(auth
=authen())
718 screen_name
= g
['stuff'].split()[0]
719 if screen_name
.startswith('@'):
721 screen_name
=screen_name
[1:],
722 include_entities
=False,
724 printNicely(green('Unblock ' + screen_name
+ ' success!'))
726 printNicely(red('A name should begin with a \'@\''))
731 Report a user as a spam account
733 t
= Twitter(auth
=authen())
734 screen_name
= g
['stuff'].split()[0]
735 if screen_name
.startswith('@'):
737 screen_name
=screen_name
[1:])
738 printNicely(green('You reported ' + screen_name
+ '.'))
740 printNicely(red('Sorry I can\'t understand.'))
748 rel
= os
.popen('cal').read().split('\n')
750 month
= random_rainbow(month
)
752 date
= ' '.join([cycle_color(i
) for i
in date
.split(' ')])
753 today
= str(int(os
.popen('date +\'%d\'').read().strip()))
758 ary
= line
.split(' ')
759 ary
= map(lambda x
: on_grey(x
) if x
== today
else grey(x
), ary
)
760 printNicely(' '.join(ary
))
765 List and change theme
769 for theme
in g
['themes']:
770 line
= ' '*2 + magenta('* ' + theme
)
775 new_config
= 'rainbowstream/colorset/' + g
['stuff'] + '.json'
776 new_config
= load_config(new_config
)
777 for nc
in new_config
:
778 c
[nc
] = new_config
[nc
]
779 printNicely(green('Theme changed.'))
781 printNicely(red('Sorry, config file is broken!'))
789 h
, w
= os
.popen('stty size', 'r').read().split()
793 usage
+= s
+ 'Hi boss! I\'m ready to serve you right now!\n'
794 usage
+= s
+ '-' * (int(w
) - 4) + '\n'
795 usage
+= s
+ 'You are ' + yellow('already') + ' on your personal stream.\n'
796 usage
+= s
+ 'Any update from Twitter will show up ' + \
797 yellow('immediately') + '.\n'
798 usage
+= s
+ 'In addtion, following commands are available right now:\n'
802 usage
+= s
+ grey(u
'\u266A' + ' Discover the world \n')
803 usage
+= s
* 2 + green('trend') + ' will show global trending topics. ' + \
804 'You can try ' + green('trend US') + ' or ' + \
805 green('trend JP Tokyo') + '.\n'
806 usage
+= s
* 2 + green('home') + ' will show your timeline. ' + \
807 green('home 7') + ' will show 7 tweets.\n'
808 usage
+= s
* 2 + green('mentions') + ' will show mentions timeline. ' + \
809 green('mentions 7') + ' will show 7 mention tweets.\n'
810 usage
+= s
* 2 + green('whois @mdo') + ' will show profile of ' + \
811 magenta('@mdo') + '.\n'
812 usage
+= s
* 2 + green('view @mdo') + \
813 ' will show ' + magenta('@mdo') + '\'s home.\n'
814 usage
+= s
* 2 + green('s #AKB48') + ' will search for "' + \
815 yellow('AKB48') + '" and return 5 newest tweet.\n'
819 usage
+= s
+ grey(u
'\u266A' + ' Tweets \n')
820 usage
+= s
* 2 + green('t oops ') + \
821 'will tweet "' + yellow('oops') + '" immediately.\n'
823 green('rt 12 ') + ' will retweet to tweet with ' + \
824 yellow('[id=12]') + '.\n'
826 green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
827 yellow('[id=12]') + '.\n'
828 usage
+= s
* 2 + green('rep 12 oops') + ' will reply "' + \
829 yellow('oops') + '" to tweet with ' + yellow('[id=12]') + '.\n'
831 green('fav 12 ') + ' will favorite the tweet with ' + \
832 yellow('[id=12]') + '.\n'
834 green('ufav 12 ') + ' will unfavorite tweet with ' + \
835 yellow('[id=12]') + '.\n'
837 green('del 12 ') + ' will delete tweet with ' + \
838 yellow('[id=12]') + '.\n'
839 usage
+= s
* 2 + green('show image 12') + ' will show image in tweet with ' + \
840 yellow('[id=12]') + ' in your OS\'s image viewer.\n'
844 usage
+= s
+ grey(u
'\u266A' + ' Direct messages \n')
845 usage
+= s
* 2 + green('inbox') + ' will show inbox messages. ' + \
846 green('inbox 7') + ' will show newest 7 messages.\n'
847 usage
+= s
* 2 + green('sent') + ' will show sent messages. ' + \
848 green('sent 7') + ' will show newest 7 messages.\n'
849 usage
+= s
* 2 + green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
850 magenta('@dtvd88') + '.\n'
851 usage
+= s
* 2 + green('trash 5') + ' will remove message with ' + \
852 yellow('[message_id=5]') + '.\n'
854 # Follower and following
856 usage
+= s
+ grey(u
'\u266A' + ' Fiends and followers \n')
859 ' will list all followers (people who are following you).\n'
862 ' will list all friends (people who you are following).\n'
863 usage
+= s
* 2 + green('fl @dtvd88') + ' will follow ' + \
864 magenta('@dtvd88') + '.\n'
865 usage
+= s
* 2 + green('ufl @dtvd88') + ' will unfollow ' + \
866 magenta('@dtvd88') + '.\n'
867 usage
+= s
* 2 + green('mute @dtvd88') + ' will mute ' + \
868 magenta('@dtvd88') + '.\n'
869 usage
+= s
* 2 + green('unmute @dtvd88') + ' will unmute ' + \
870 magenta('@dtvd88') + '.\n'
871 usage
+= s
* 2 + green('muting') + ' will list muting users.\n'
872 usage
+= s
* 2 + green('block @dtvd88') + ' will block ' + \
873 magenta('@dtvd88') + '.\n'
874 usage
+= s
* 2 + green('unblock @dtvd88') + ' will unblock ' + \
875 magenta('@dtvd88') + '.\n'
876 usage
+= s
* 2 + green('report @dtvd88') + ' will report ' + \
877 magenta('@dtvd88') + ' as a spam account.\n'
881 usage
+= s
+ grey(u
'\u266A' + ' Switching streams \n')
882 usage
+= s
* 2 + green('switch public #AKB') + \
883 ' will switch to public stream and follow "' + \
884 yellow('AKB') + '" keyword.\n'
885 usage
+= s
* 2 + green('switch mine') + \
886 ' will switch to your personal stream.\n'
887 usage
+= s
* 2 + green('switch mine -f ') + \
888 ' will prompt to enter the filter.\n'
889 usage
+= s
* 3 + yellow('Only nicks') + \
890 ' filter will decide nicks will be INCLUDE ONLY.\n'
891 usage
+= s
* 3 + yellow('Ignore nicks') + \
892 ' filter will decide nicks will be EXCLUDE.\n'
893 usage
+= s
* 2 + green('switch mine -d') + \
894 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
898 usage
+= s
+ grey(u
'\u266A' + ' Smart shell\n')
899 usage
+= s
* 2 + green('111111 * 9 / 7') + ' or any math expression ' + \
900 'will be evaluate by Python interpreter.\n'
901 usage
+= s
* 2 + 'Even ' + green('cal') + ' will show the calendar' + \
902 ' for current month.\n'
906 usage
+= s
+ grey(u
'\u266A' + ' Screening \n')
907 usage
+= s
* 2 + green('theme') + ' will list available theme.' + \
908 green('theme monokai') + ' will apply '+ yellow('monokai') + \
909 ' theme immediately.\n'
910 usage
+= s
* 2 + green('h') + ' will show this help again.\n'
911 usage
+= s
* 2 + green('c') + ' will clear the screen.\n'
912 usage
+= s
* 2 + green('q') + ' will quit.\n'
916 usage
+= s
+ '-' * (int(w
) - 4) + '\n'
917 usage
+= s
+ 'Have fun and hang tight! \n'
933 os
.system('rm -rf rainbow.db')
934 os
.kill(g
['stream_pid'], signal
.SIGKILL
)
943 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
946 printNicely(eval(g
['cmd']))
997 Listen to user's input
1002 ['public', 'mine'], # switch
1016 ['image'], # show image
1017 ['fl', 'fr'], # list
1031 g
['themes'], # theme
1037 init_interactive_shell(d
)
1042 line
= raw_input(g
['decorated_name'])
1046 cmd
= line
.split()[0]
1050 # Save cmd to global variable and call process
1052 g
['stuff'] = ' '.join(line
.split()[1:])
1055 printNicely(red('OMG something is wrong with Twitter right now.'))
1056 # Not redisplay prefix
1057 if cmd
in ['switch', 't', 'rt', 'rep']:
1063 def stream(domain
, args
, name
='Rainbow Stream'):
1070 c
['USER_DOMAIN']: name
,
1071 c
['PUBLIC_DOMAIN']: args
.track_keywords
,
1072 c
['SITE_DOMAIN']: 'Site Stream',
1074 ascii_art(art_dict
[domain
])
1076 # These arguments are optional:
1078 timeout
=args
.timeout
,
1079 block
=not args
.no_block
,
1080 heartbeat_timeout
=args
.heartbeat_timeout
)
1084 if args
.track_keywords
:
1085 query_args
['track'] = args
.track_keywords
1088 stream
= TwitterStream(
1093 if domain
== c
['USER_DOMAIN']:
1094 tweet_iter
= stream
.user(**query_args
)
1095 elif domain
== c
['SITE_DOMAIN']:
1096 tweet_iter
= stream
.site(**query_args
)
1098 if args
.track_keywords
:
1099 tweet_iter
= stream
.statuses
.filter(**query_args
)
1101 tweet_iter
= stream
.statuses
.sample()
1103 # Iterate over the stream.
1105 for tweet
in tweet_iter
:
1107 printNicely("-- None --")
1108 elif tweet
is Timeout
:
1109 printNicely("-- Timeout --")
1110 elif tweet
is HeartbeatTimeout
:
1111 printNicely("-- Heartbeat Timeout --")
1112 elif tweet
is Hangup
:
1113 printNicely("-- Hangup --")
1114 elif tweet
.get('text'):
1117 iot
=args
.image_on_term
,
1118 keyword
=args
.track_keywords
,
1123 printNicely(magenta("I'm afraid we have problem with twitter'S maximum connection."))
1124 printNicely(magenta("Let's try again later."))
1131 # Spawn stream process
1132 args
= parse_arguments()
1133 get_decorated_name()
1134 p
= Process(target
=stream
, args
=(c
['USER_DOMAIN'], args
, g
['original_name']))
1137 # Start listen process
1141 g
['stream_pid'] = p
.pid
1142 g
['iot'] = args
.image_on_term