1b241c3fb6315541fe6c72e894b73bf133fd1701
[rainbowstream.git] / rainbowstream / draw.py
1 import random
2 import itertools
3 import requests
4 import datetime
5 import time
6
7 from twitter.util import printNicely
8 from functools import wraps
9 from pyfiglet import figlet_format
10 from functools import reduce
11 from StringIO import StringIO
12 from dateutil import parser
13 from .c_image import *
14 from .colors import *
15 from .config import *
16 from .db import *
17
18 db = RainbowDB()
19 g = {}
20
21 def init_cycle():
22 """
23 Init the cycle
24 """
25 colors_shuffle = [globals()[i.encode('utf8')]
26 if not i.startswith('term_')
27 else term_color(int(i[5:]))
28 for i in c['CYCLE_COLOR']]
29 return itertools.cycle(colors_shuffle)
30 g['cyc'] = init_cycle()
31 g['cache'] = {}
32
33
34 def reset_cycle():
35 """
36 Notify from rainbow
37 """
38 g['cyc'] = init_cycle()
39 g['cache'] = {}
40
41
42 def order_rainbow(s):
43 """
44 Print a string with ordered color with each character
45 """
46 colors_shuffle = [globals()[i.encode('utf8')]
47 if not i.startswith('term_')
48 else term_color(int(i[5:]))
49 for i in c['CYCLE_COLOR']]
50 colored = [colors_shuffle[i % 7](s[i]) for i in xrange(len(s))]
51 return reduce(lambda x, y: x + y, colored)
52
53
54 def random_rainbow(s):
55 """
56 Print a string with random color with each character
57 """
58 colors_shuffle = [globals()[i.encode('utf8')]
59 if not i.startswith('term_')
60 else term_color(int(i[5:]))
61 for i in c['CYCLE_COLOR']]
62 colored = [random.choice(colors_shuffle)(i) for i in s]
63 return reduce(lambda x, y: x + y, colored)
64
65
66 def Memoize(func):
67 """
68 Memoize decorator
69 """
70 @wraps(func)
71 def wrapper(*args):
72 if args not in g['cache']:
73 g['cache'][args] = func(*args)
74 return g['cache'][args]
75 return wrapper
76
77
78 @Memoize
79 def cycle_color(s):
80 """
81 Cycle the colors_shuffle
82 """
83 return next(g['cyc'])(s)
84
85
86 def ascii_art(text):
87 """
88 Draw the Ascii Art
89 """
90 fi = figlet_format(text, font='doom')
91 print('\n'.join(
92 [next(g['cyc'])(i) for i in fi.split('\n')]
93 ))
94
95
96 def show_calendar(month, date, rel):
97 """
98 Show the calendar in rainbow mode
99 """
100 month = random_rainbow(month)
101 date = ' '.join([cycle_color(i) for i in date.split(' ')])
102 today = str(int(os.popen('date +\'%d\'').read().strip()))
103 # Display
104 printNicely(month)
105 printNicely(date)
106 for line in rel:
107 ary = line.split(' ')
108 ary = map(lambda x: color_func(c['CAL']['today'])(x)
109 if x == today
110 else color_func(c['CAL']['days'])(x)
111 , ary)
112 printNicely(' '.join(ary))
113
114
115 def check_theme():
116 """
117 Check current theme and update if necessary
118 """
119 exists = db.theme_query()
120 themes = [t.theme_name for t in exists]
121 if c['theme'] != themes[0]:
122 c['theme'] = themes[0]
123 # Determine path
124 if c['theme'] == 'custom':
125 config = os.environ.get(
126 'HOME',
127 os.environ.get('USERPROFILE',
128 '')) + os.sep + '.rainbow_config.json'
129 else:
130 config = os.path.dirname(__file__) + '/colorset/'+c['theme']+'.json'
131 # Load new config
132 data = load_config(config)
133 if data:
134 for d in data:
135 c[d] = data[d]
136 # Re-init color cycle
137 g['cyc'] = init_cycle()
138
139
140 def color_func(func_name):
141 """
142 Call color function base on name
143 """
144 pure = func_name.encode('utf8')
145 if pure.startswith('term_') and pure[5:].isdigit():
146 return term_color(int(pure[5:]))
147 return globals()[pure]
148
149
150 def draw(t, iot=False, keyword=None, fil=[], ig=[]):
151 """
152 Draw the rainbow
153 """
154
155 check_theme()
156 # Retrieve tweet
157 tid = t['id']
158 text = t['text']
159 screen_name = t['user']['screen_name']
160 name = t['user']['name']
161 created_at = t['created_at']
162 favorited = t['favorited']
163 date = parser.parse(created_at)
164 date = date - datetime.timedelta(seconds=time.timezone)
165 clock = date.strftime('%Y/%m/%d %H:%M:%S')
166
167 # Get expanded url
168 try:
169 expanded_url = []
170 url = []
171 urls = t['entities']['urls']
172 for u in urls:
173 expanded_url.append(u['expanded_url'])
174 url.append(u['url'])
175 except:
176 expanded_url = None
177 url = None
178
179 # Get media
180 try:
181 media_url = []
182 media = t['entities']['media']
183 for m in media:
184 media_url.append(m['media_url'])
185 except:
186 media_url = None
187
188 # Filter and ignore
189 screen_name = '@' + screen_name
190 if fil and screen_name not in fil:
191 return
192 if ig and screen_name in ig:
193 return
194
195 # Get rainbow id
196 res = db.tweet_to_rainbow_query(tid)
197 if not res:
198 db.tweet_store(tid)
199 res = db.tweet_to_rainbow_query(tid)
200 rid = res[0].rainbow_id
201
202 # Format info
203 user = cycle_color(
204 name) + color_func(c['TWEET']['nick'])(' ' + screen_name + ' ')
205 meta = color_func(c['TWEET']['clock'])(
206 '[' + clock + '] ') + color_func(c['TWEET']['id'])('[id=' + str(rid) + '] ')
207 if favorited:
208 meta = meta + color_func(c['TWEET']['favorited'])(u'\u2605')
209 tweet = text.split()
210 # Replace url
211 if expanded_url:
212 for index in range(len(expanded_url)):
213 tweet = map(
214 lambda x: expanded_url[index] if x == url[index] else x,
215 tweet)
216 # Highlight RT
217 tweet = map(
218 lambda x: color_func(
219 c['TWEET']['rt'])(x) if x == 'RT' else x,
220 tweet)
221 # Highlight screen_name
222 tweet = map(lambda x: cycle_color(x) if x[0] == '@' else x, tweet)
223 # Highlight link
224 tweet = map(
225 lambda x: color_func(
226 c['TWEET']['link'])(x) if x[
227 0:4] == 'http' else x,
228 tweet)
229 # Highlight search keyword
230 if keyword:
231 tweet = map(
232 lambda x: color_func(c['TWEET']['keyword'])(x) if
233 ''.join(c for c in x if c.isalnum()).lower() == keyword.lower()
234 else x,
235 tweet
236 )
237 # Recreate tweet
238 tweet = ' '.join(tweet)
239
240 # Draw rainbow
241 line1 = u"{u:>{uw}}:".format(
242 u=user,
243 uw=len(user) + 2,
244 )
245 line2 = u"{c:>{cw}}".format(
246 c=meta,
247 cw=len(meta) + 2,
248 )
249 line3 = ' ' + tweet
250
251 printNicely('')
252 printNicely(line1)
253 printNicely(line2)
254 printNicely(line3)
255
256 # Display Image
257 if iot and media_url:
258 for mu in media_url:
259 try:
260 response = requests.get(mu)
261 image_to_display(StringIO(response.content))
262 except:
263 printNicely(red('Sorry, image link is broken'))
264
265
266 def print_message(m):
267 """
268 Print direct message
269 """
270 sender_screen_name = '@' + m['sender_screen_name']
271 sender_name = m['sender']['name']
272 text = m['text']
273 recipient_screen_name = '@' + m['recipient_screen_name']
274 recipient_name = m['recipient']['name']
275 mid = m['id']
276 date = parser.parse(m['created_at'])
277 date = date - datetime.timedelta(seconds=time.timezone)
278 clock = date.strftime('%Y/%m/%d %H:%M:%S')
279
280 # Get rainbow id
281 res = db.message_to_rainbow_query(mid)
282 if not res:
283 db.message_store(mid)
284 res = db.message_to_rainbow_query(mid)
285 rid = res[0].rainbow_id
286
287 # Draw
288 sender = cycle_color(
289 sender_name) + color_func(c['MESSAGE']['sender'])(' ' + sender_screen_name + ' ')
290 recipient = cycle_color(recipient_name) + color_func(
291 c['MESSAGE']['recipient'])(
292 ' ' + recipient_screen_name + ' ')
293 user = sender + color_func(c['MESSAGE']['to'])(' >>> ') + recipient
294 meta = color_func(
295 c['MESSAGE']['clock'])(
296 '[' + clock + ']') + color_func(
297 c['MESSAGE']['id'])(
298 ' [message_id=' + str(rid) + '] ')
299 text = ''.join(map(lambda x: x + ' ' if x == '\n' else x, text))
300
301 line1 = u"{u:>{uw}}:".format(
302 u=user,
303 uw=len(user) + 2,
304 )
305 line2 = u"{c:>{cw}}".format(
306 c=meta,
307 cw=len(meta) + 2,
308 )
309
310 line3 = ' ' + text
311
312 printNicely('')
313 printNicely(line1)
314 printNicely(line2)
315 printNicely(line3)
316
317
318 def show_profile(u, iot=False):
319 """
320 Show a profile
321 """
322 # Retrieve info
323 name = u['name']
324 screen_name = u['screen_name']
325 description = u['description']
326 profile_image_url = u['profile_image_url']
327 location = u['location']
328 url = u['url']
329 created_at = u['created_at']
330 statuses_count = u['statuses_count']
331 friends_count = u['friends_count']
332 followers_count = u['followers_count']
333
334 # Create content
335 statuses_count = color_func(
336 c['PROFILE']['statuses_count'])(
337 str(statuses_count) +
338 ' tweets')
339 friends_count = color_func(
340 c['PROFILE']['friends_count'])(
341 str(friends_count) +
342 ' following')
343 followers_count = color_func(
344 c['PROFILE']['followers_count'])(
345 str(followers_count) +
346 ' followers')
347 count = statuses_count + ' ' + friends_count + ' ' + followers_count
348 user = cycle_color(
349 name) + color_func(c['PROFILE']['nick'])(' @' + screen_name + ' : ') + count
350 profile_image_raw_url = 'Profile photo: ' + \
351 color_func(c['PROFILE']['profile_image_url'])(profile_image_url)
352 description = ''.join(
353 map(lambda x: x + ' ' * 4 if x == '\n' else x, description))
354 description = color_func(c['PROFILE']['description'])(description)
355 location = 'Location : ' + color_func(c['PROFILE']['location'])(location)
356 url = 'URL : ' + (color_func(c['PROFILE']['url'])(url) if url else '')
357 date = parser.parse(created_at)
358 date = date - datetime.timedelta(seconds=time.timezone)
359 clock = date.strftime('%Y/%m/%d %H:%M:%S')
360 clock = 'Join at ' + color_func(c['PROFILE']['clock'])(clock)
361
362 # Format
363 line1 = u"{u:>{uw}}".format(
364 u=user,
365 uw=len(user) + 2,
366 )
367 line2 = u"{p:>{pw}}".format(
368 p=profile_image_raw_url,
369 pw=len(profile_image_raw_url) + 4,
370 )
371 line3 = u"{d:>{dw}}".format(
372 d=description,
373 dw=len(description) + 4,
374 )
375 line4 = u"{l:>{lw}}".format(
376 l=location,
377 lw=len(location) + 4,
378 )
379 line5 = u"{u:>{uw}}".format(
380 u=url,
381 uw=len(url) + 4,
382 )
383 line6 = u"{c:>{cw}}".format(
384 c=clock,
385 cw=len(clock) + 4,
386 )
387
388 # Display
389 printNicely('')
390 printNicely(line1)
391 if iot:
392 try:
393 response = requests.get(profile_image_url)
394 image_to_display(StringIO(response.content), 2, 20)
395 except:
396 pass
397 else:
398 printNicely(line2)
399 for line in [line3, line4, line5, line6]:
400 printNicely(line)
401 printNicely('')
402
403
404 def print_trends(trends):
405 """
406 Display topics
407 """
408 for topic in trends[:c['TREND_MAX']]:
409 name = topic['name']
410 url = topic['url']
411 line = cycle_color(name) + ': ' + color_func(c['TREND']['url'])(url)
412 printNicely(line)
413 printNicely('')
414
415
416 def print_list(group):
417 """
418 Display a list
419 """
420 for g in group:
421 # Format
422 name = g['name']
423 name = color_func(c['GROUP']['name'])(name + ' : ')
424 member = str(g['member_count'])
425 member = color_func(c['GROUP']['member'])(member+' member')
426 subscriber = str(g['subscriber_count'])
427 subscriber = color_func(c['GROUP']['subscriber'])(subscriber+' subscriber')
428 description = g['description'].strip()
429 description = color_func(c['GROUP']['description'])(description)
430 mode = g['mode']
431 mode = color_func(c['GROUP']['mode'])('Type: '+mode)
432 created_at = g['created_at']
433 date = parser.parse(created_at)
434 date = date - datetime.timedelta(seconds=time.timezone)
435 clock = date.strftime('%Y/%m/%d %H:%M:%S')
436 clock = 'Created at ' + color_func(c['GROUP']['clock'])(clock)
437
438 # Save to db
439 db.list_store(g['id'],g['name'])
440
441 # Create lines
442 line1 = ' '*2 + name + member + ' ' + subscriber
443 line2 = ' '*4 + description
444 line3 = ' '*4 + mode
445 line4 = ' '*4 + clock
446
447 # Display
448 printNicely('')
449 printNicely(line1)
450 printNicely(line2)
451 printNicely(line3)
452 printNicely(line4)
453
454 printNicely('')
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491