print adapt to screen size
[rainbowstream.git] / rainbowstream / rainbow.py
CommitLineData
91476ec3
O
1"""
2Colorful user's timeline stream
3"""
4
5from __future__ import print_function
54277114 6from multiprocessing import Process
91476ec3 7
f405a7d0 8import os, os.path, argparse, sys, time, signal
91476ec3
O
9
10from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
54277114 11from twitter.api import *
91476ec3 12from twitter.oauth import OAuth, read_token_file
8c840a83 13from twitter.oauth_dance import oauth_dance
91476ec3
O
14from twitter.util import printNicely
15from dateutil import parser
91476ec3 16
2a6238f5
O
17from .colors import *
18from .config import *
19
f405a7d0 20g = {}
91476ec3 21
b8dda704 22def draw(t,keyword=None):
91476ec3
O
23 """
24 Draw the rainbow
25 """
26 # Retrieve tweet
27 text = t['text']
28 screen_name = t['user']['screen_name']
29 name = t['user']['name']
30 created_at = t['created_at']
31 date = parser.parse(created_at)
32 time = date.strftime('%Y/%m/%d %H:%M:%S')
33
34 # Format info
54277114 35 user = cycle_color(name) + grey(' ' + '@' + screen_name + ' ')
2a6238f5 36 clock = grey('[' + time + ']')
8c840a83 37 tweet = text.split()
b8dda704 38 # Highlight RT
2a6238f5 39 tweet = map(lambda x: grey(x) if x == 'RT' else x, tweet)
b8dda704 40 # Highlight screen_name
2a6238f5 41 tweet = map(lambda x: cycle_color(x) if x[0] == '@' else x, tweet)
b8dda704 42 # Highlight link
2a6238f5 43 tweet = map(lambda x: cyan(x) if x[0:7] == 'http://' else x, tweet)
b8dda704 44 # Highlight search keyword
7a431249
O
45 if keyword:
46 tweet = map(lambda x: on_yellow(x) if ''.join(c for c in x if c.isalnum()).lower() == keyword.lower() else x, tweet)
8c840a83 47 tweet = ' '.join(tweet)
91476ec3
O
48
49 # Draw rainbow
06773ffe 50 line1 = u"{u:>{uw}}:".format(
2a6238f5
O
51 u=user,
52 uw=len(user) + 2,
91476ec3 53 )
06773ffe 54 line2 = u"{c:>{cw}}".format(
2a6238f5
O
55 c=clock,
56 cw=len(clock) + 2,
06773ffe
O
57 )
58 line3 = ' ' + tweet
59 line4 = '\n'
91476ec3 60
f405a7d0
O
61 printNicely(line1)
62 printNicely(line2)
63 printNicely(line3)
64 printNicely(line4)
91476ec3
O
65
66
67def parse_arguments():
68 """
69 Parse the arguments
70 """
91476ec3 71 parser = argparse.ArgumentParser(description=__doc__ or "")
2a6238f5
O
72 parser.add_argument(
73 '-to',
74 '--timeout',
75 help='Timeout for the stream (seconds).')
76 parser.add_argument(
77 '-ht',
78 '--heartbeat-timeout',
79 help='Set heartbeat timeout.',
80 default=90)
81 parser.add_argument(
82 '-nb',
83 '--no-block',
84 action='store_true',
85 help='Set stream to non-blocking.')
86 parser.add_argument(
87 '-tt',
88 '--track-keywords',
89 help='Search the stream for specific text.')
91476ec3
O
90 return parser.parse_args()
91
92
54277114
O
93def authen():
94 """
95 authenticate with Twitter OAuth
96 """
8c840a83 97 # When using rainbow stream you must authorize.
2a6238f5
O
98 twitter_credential = os.environ.get(
99 'HOME',
100 os.environ.get(
101 'USERPROFILE',
102 '')) + os.sep + '.rainbow_oauth'
8c840a83
O
103 if not os.path.exists(twitter_credential):
104 oauth_dance("Rainbow Stream",
105 CONSUMER_KEY,
106 CONSUMER_SECRET,
107 twitter_credential)
108 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
54277114 109 return OAuth(
2a6238f5
O
110 oauth_token,
111 oauth_token_secret,
112 CONSUMER_KEY,
113 CONSUMER_SECRET)
91476ec3 114
54277114
O
115
116def get_decorated_name():
117 """
118 Beginning of every line
119 """
120 t = Twitter(auth=authen())
121 name = '@' + t.statuses.user_timeline()[-1]['user']['screen_name']
f405a7d0 122 g['decorated_name'] = grey('[') + grey(name) + grey(']: ')
54277114 123
f405a7d0
O
124
125def tweet():
54277114
O
126 """
127 Authen and tweet
128 """
129 t = Twitter(auth=authen())
f405a7d0
O
130 t.statuses.update(status=g['stuff'])
131
132
133def search():
134 """
135 Authen and search
136 """
137 t = Twitter(auth=authen())
138 rel = t.search.tweets(q='#' + g['stuff'])['statuses']
2a911483 139 h, w = os.popen('stty size', 'r').read().split()
140
141 printNicely(grey('*'*int(w)+'\n'))
05105565 142 print('Newest',SEARCH_MAX_RECORD, 'tweet: \n')
f405a7d0 143 for i in xrange(5):
b8dda704 144 draw(t=rel[i],keyword=g['stuff'].strip())
2a911483 145 printNicely(grey('*'*int(w)+'\n'))
f405a7d0
O
146
147
843647ad
O
148def friend():
149 """
150 List of friend (following)
151 """
152 t = Twitter(auth=authen())
153 g['friends'] = t.friends.ids()['ids']
154 for i in g['friends']:
155 screen_name = t.users.lookup(user_id=i)[0]['screen_name']
156 user = cycle_color('@'+screen_name)
157 print(user, end=' ')
158 print('\n');
159
160
161def follower():
162 """
163 List of follower
164 """
165 t = Twitter(auth=authen())
166 g['followers'] = t.followers.ids()['ids']
167 for i in g['followers']:
168 screen_name = t.users.lookup(user_id=i)[0]['screen_name']
169 user = cycle_color('@'+screen_name)
170 print(user, end=' ')
171 print('\n');
172
173
f405a7d0
O
174def help():
175 """
176 Print help
177 """
178 usage = '''
179 Hi boss! I'm ready to serve you right now!
180 ----------------------------------------------------
843647ad
O
181 "tweet" at the beginning will tweet immediately
182 "s" and follow by any word will search and return 5 newest tweet
183 "fr" will list out your following people
184 "fl" will list out your followers
185 "h" will print this help once again
b8dda704 186 "c" will clear the terminal
f405a7d0
O
187 "q" will exit
188 ----------------------------------------------------
843647ad 189 Have fun and hang tight!
f405a7d0
O
190 '''
191 printNicely(usage)
192 sys.stdout.write(g['decorated_name'])
193
194
843647ad 195def clear():
f405a7d0
O
196 """
197 Exit all
198 """
843647ad 199 os.system('clear')
f405a7d0
O
200
201
843647ad 202def quit():
b8dda704
O
203 """
204 Exit all
205 """
843647ad
O
206 os.kill(g['stream_pid'], signal.SIGKILL)
207 sys.exit()
b8dda704
O
208
209
843647ad 210def process(cmd):
f405a7d0
O
211 """
212 Process switch by start of line
213 """
214 return {
843647ad
O
215 'tweet' : tweet,
216 's' : search,
217 'fr' : friend,
218 'fl' : follower,
219 'h' : help,
220 'c' : clear,
221 'q' : quit,
222 }.get(cmd,lambda: sys.stdout.write(g['decorated_name']))
54277114
O
223
224
225def listen(stdin):
226 """
227 Listen to user's input
228 """
229 for line in iter(stdin.readline, ''):
843647ad
O
230 try:
231 cmd = line.split()[0]
232 except:
233 cmd = ''
f405a7d0 234 # Save cmd to global variable and call process
843647ad
O
235 g['stuff'] = ' '.join(line.split()[1:])
236 process(cmd)()
54277114
O
237 stdin.close()
238
239
240def stream():
241 """
f405a7d0 242 Track the stream
54277114
O
243 """
244 args = parse_arguments()
245
246 # The Logo
247 ascii_art()
91476ec3
O
248 # These arguments are optional:
249 stream_args = dict(
250 timeout=args.timeout,
251 block=not args.no_block,
252 heartbeat_timeout=args.heartbeat_timeout)
253
254 # Track keyword
255 query_args = dict()
256 if args.track_keywords:
257 query_args['track'] = args.track_keywords
258
259 # Get stream
2a6238f5 260 stream = TwitterStream(
54277114
O
261 auth = authen(),
262 domain = 'userstream.twitter.com',
2a6238f5 263 **stream_args)
91476ec3
O
264 tweet_iter = stream.user(**query_args)
265
266 # Iterate over the sample stream.
267 for tweet in tweet_iter:
268 if tweet is None:
269 printNicely("-- None --")
270 elif tweet is Timeout:
271 printNicely("-- Timeout --")
272 elif tweet is HeartbeatTimeout:
273 printNicely("-- Heartbeat Timeout --")
274 elif tweet is Hangup:
275 printNicely("-- Hangup --")
276 elif tweet.get('text'):
f405a7d0 277 draw(t=tweet)
54277114
O
278
279
280def fly():
281 """
282 Main function
283 """
284 get_decorated_name()
285 p = Process(target = stream)
286 p.start()
f405a7d0 287 g['stream_pid'] = p.pid
54277114
O
288 listen(sys.stdin)
289