fallback humanize function for arrow now supported locale
[rainbowstream.git] / rainbowstream / draw.py
CommitLineData
e9f5200b 1import random
bcb5518e 2import textwrap
e9f5200b 3import itertools
7500d90b 4import requests
8b3456f9 5import locale
6import arrow
59262e95 7import re
67c663f8 8import os
7500d90b 9
2da50cc4 10from twitter.util import printNicely
e9f5200b
VNM
11from functools import wraps
12from pyfiglet import figlet_format
7500d90b 13from dateutil import parser
2da50cc4 14from .c_image import *
7500d90b
VNM
15from .colors import *
16from .config import *
c3bab4ef 17from .py3patch import *
841260fe 18from .emoji import *
c3bab4ef 19
99b52f5f
O
20# Draw global variables
21dg = {}
1fdd6a5c 22
422dd385 23
e9f5200b
VNM
24def init_cycle():
25 """
26 Init the cycle
27 """
28 colors_shuffle = [globals()[i.encode('utf8')]
fa6e062d
O
29 if not str(i).isdigit()
30 else term_color(int(i))
422dd385 31 for i in c['CYCLE_COLOR']]
5f22104f 32 return itertools.cycle(colors_shuffle)
1fdd6a5c 33
e9f5200b 34
59262e95 35def start_cycle():
2359c276
VNM
36 """
37 Notify from rainbow
38 """
99b52f5f
O
39 dg['cyc'] = init_cycle()
40 dg['cache'] = {}
e5455a30 41 dg['humanize_unsupported'] = False
2359c276
VNM
42
43
e9f5200b
VNM
44def order_rainbow(s):
45 """
46 Print a string with ordered color with each character
47 """
5f22104f 48 colors_shuffle = [globals()[i.encode('utf8')]
fa6e062d
O
49 if not str(i).isdigit()
50 else term_color(int(i))
422dd385 51 for i in c['CYCLE_COLOR']]
5f22104f 52 colored = [colors_shuffle[i % 7](s[i]) for i in xrange(len(s))]
c3bab4ef 53 return ''.join(colored)
e9f5200b
VNM
54
55
56def random_rainbow(s):
57 """
58 Print a string with random color with each character
59 """
5f22104f 60 colors_shuffle = [globals()[i.encode('utf8')]
fa6e062d
O
61 if not str(i).isdigit()
62 else term_color(int(i))
422dd385 63 for i in c['CYCLE_COLOR']]
5f22104f 64 colored = [random.choice(colors_shuffle)(i) for i in s]
c3bab4ef 65 return ''.join(colored)
e9f5200b
VNM
66
67
68def Memoize(func):
69 """
70 Memoize decorator
71 """
e9f5200b
VNM
72 @wraps(func)
73 def wrapper(*args):
99b52f5f
O
74 if args not in dg['cache']:
75 dg['cache'][args] = func(*args)
76 return dg['cache'][args]
e9f5200b
VNM
77 return wrapper
78
79
80@Memoize
81def cycle_color(s):
82 """
83 Cycle the colors_shuffle
84 """
99b52f5f 85 return next(dg['cyc'])(s)
e9f5200b
VNM
86
87
88def ascii_art(text):
89 """
90 Draw the Ascii Art
91 """
92 fi = figlet_format(text, font='doom')
93 print('\n'.join(
99b52f5f 94 [next(dg['cyc'])(i) for i in fi.split('\n')]
e9f5200b
VNM
95 ))
96
97
92685d21 98def check_config():
ceec8593 99 """
100 Check if config is changed
101 """
102 changed = False
103 data = get_all_config()
104 for key in c:
105 if key in data:
106 if data[key] != c[key]:
107 changed = True
108 if changed:
109 reload_config()
110
111
112def validate_theme(theme):
113 """
114 Validate a theme exists or not
115 """
116 # Theme changed check
117 files = os.listdir(os.path.dirname(__file__) + '/colorset')
118 themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json']
119 return theme in themes
92685d21 120
121
99b52f5f 122def reload_theme(value, prev):
4cf86720
VNM
123 """
124 Check current theme and update if necessary
125 """
99b52f5f 126 if value != prev:
1f2f6159 127 config = os.path.dirname(
99b52f5f 128 __file__) + '/colorset/' + value + '.json'
4cf86720
VNM
129 # Load new config
130 data = load_config(config)
a5301bc0
VNM
131 if data:
132 for d in data:
133 c[d] = data[d]
99b52f5f 134 # Restart color cycle and update config
ceec8593 135 start_cycle()
99b52f5f
O
136 set_config('THEME', value)
137 return value
138 return prev
7500d90b 139
fe08f905
VNM
140
141def color_func(func_name):
142 """
143 Call color function base on name
144 """
fa6e062d
O
145 if str(func_name).isdigit():
146 return term_color(int(func_name))
c3bab4ef 147 return globals()[func_name]
fe08f905
VNM
148
149
e5455a30
O
150def fallback_humanize(date, fallback_format=None, use_fallback=False):
151 """
152 Format date with arrow and a fallback format
153 """
154 # Convert to local timezone
155 date = arrow.get(date).to('local')
156 # Set default fallback format
157 if not fallback_format:
158 fallback_format = '%Y/%m/%d %H:%M:%S'
159 # Determine using fallback format or not by a variable
160 if use_fallback:
161 return date.datetime.strftime(fallback_format)
162 try:
163 # Use Arrow's humanize function
164 lang, encode = locale.getdefaultlocale()
165 clock = date.humanize(locale=lang)
166 except:
167 # Notice at the 1st time only
168 if not dg['humanize_unsupported']:
169 dg['humanize_unsupported'] = True
170 printNicely(
171 light_magenta('Humanized date display method does not support your $LC_ALL.'))
172 # Fallback when LC_ALL is not supported
173 clock = date.datetime.strftime(fallback_format)
174 return clock
175
176
99cd1fba 177def draw(t, keyword=None, humanize=True, noti=False, fil=[], ig=[]):
7500d90b
VNM
178 """
179 Draw the rainbow
180 """
99b52f5f 181 # Check config
92685d21 182 check_config()
c37c04a9 183
7500d90b
VNM
184 # Retrieve tweet
185 tid = t['id']
606def7e 186 text = t['text']
7500d90b
VNM
187 screen_name = t['user']['screen_name']
188 name = t['user']['name']
189 created_at = t['created_at']
190 favorited = t['favorited']
318cdd67
O
191 retweet_count = t['retweet_count']
192 favorite_count = t['favorite_count']
7500d90b 193 date = parser.parse(created_at)
e5455a30
O
194 try:
195 clock_format = c['FORMAT']['TWEET']['CLOCK_FORMAT']
196 except:
197 clock_format = '%Y/%m/%d %H:%M:%S'
198 clock = fallback_humanize(date, clock_format, not humanize)
7500d90b 199
606def7e
BR
200 # Pull extended retweet text
201 try:
18df6e7f
O
202 text = 'RT @' + t['retweeted_status']['user']['screen_name'] + ': ' +\
203 t['retweeted_status']['text']
38a6dc30
O
204 # Display as a notification
205 target = t['retweeted_status']['user']['screen_name']
206 if all([target == c['original_name'], not noti]):
207 # Add to evens for 'notification' command
208 t['event'] = 'retweet'
209 c['events'].append(t)
210 notify_retweet(t)
211 return
606def7e
BR
212 except:
213 pass
214
18df6e7f 215 # Unescape HTML character
606def7e
BR
216 text = unescape(text)
217
7500d90b
VNM
218 # Get expanded url
219 try:
220 expanded_url = []
221 url = []
222 urls = t['entities']['urls']
223 for u in urls:
224 expanded_url.append(u['expanded_url'])
225 url.append(u['url'])
226 except:
227 expanded_url = None
228 url = None
229
230 # Get media
231 try:
232 media_url = []
233 media = t['entities']['media']
234 for m in media:
235 media_url.append(m['media_url'])
236 except:
237 media_url = None
238
239 # Filter and ignore
37cf396a 240 mytweet = screen_name == c['original_name']
7500d90b 241 screen_name = '@' + screen_name
e3927852
O
242 fil = list(set((fil or []) + c['ONLY_LIST']))
243 ig = list(set((ig or []) + c['IGNORE_LIST']))
7500d90b
VNM
244 if fil and screen_name not in fil:
245 return
246 if ig and screen_name in ig:
247 return
248
249 # Get rainbow id
99b52f5f
O
250 if tid not in c['tweet_dict']:
251 c['tweet_dict'].append(tid)
252 rid = len(c['tweet_dict']) - 1
253 else:
254 rid = c['tweet_dict'].index(tid)
7500d90b
VNM
255
256 # Format info
8c7ae594 257 name = cycle_color(name)
571ea706
O
258 if mytweet:
259 nick = color_func(c['TWEET']['mynick'])(screen_name)
260 else:
261 nick = color_func(c['TWEET']['nick'])(screen_name)
0d9977c7
O
262 clock = clock
263 id = str(rid)
8c7ae594 264 fav = ''
7500d90b 265 if favorited:
8c7ae594
O
266 fav = color_func(c['TWEET']['favorited'])(u'\u2605')
267
7500d90b
VNM
268 tweet = text.split()
269 # Replace url
270 if expanded_url:
13e6b275 271 for index in xrange(len(expanded_url)):
c3bab4ef 272 tweet = lmap(
8141aca6 273 lambda x: expanded_url[index]
274 if x == url[index]
275 else x,
7500d90b
VNM
276 tweet)
277 # Highlight RT
c3bab4ef 278 tweet = lmap(
8141aca6 279 lambda x: color_func(c['TWEET']['rt'])(x)
280 if x == 'RT'
281 else x,
c075e6dc 282 tweet)
7500d90b 283 # Highlight screen_name
c3bab4ef 284 tweet = lmap(lambda x: cycle_color(x) if x[0] == '@' else x, tweet)
7500d90b 285 # Highlight link
c3bab4ef 286 tweet = lmap(
8141aca6 287 lambda x: color_func(c['TWEET']['link'])(x)
37cf396a 288 if x.startswith('http')
8141aca6 289 else x,
c075e6dc 290 tweet)
4c025026 291 # Highlight hashtag
292 tweet = lmap(
8141aca6 293 lambda x: color_func(c['TWEET']['hashtag'])(x)
294 if x.startswith('#')
295 else x,
4c025026 296 tweet)
37cf396a
O
297 # Highlight my tweet
298 if mytweet:
299 tweet = [color_func(c['TWEET']['mytweet'])(x)
300 for x in tweet
301 if not any([
302 x == 'RT',
303 x.startswith('http'),
304 x.startswith('#')])
305 ]
59262e95 306 # Highlight keyword
7500d90b 307 tweet = ' '.join(tweet)
59262e95 308 if keyword:
a8c5fce4 309 roj = re.search(keyword, tweet, re.IGNORECASE)
59262e95
O
310 if roj:
311 occur = roj.group()
312 ary = tweet.split(occur)
b13c6a0d 313 delimiter = color_func(c['TWEET']['keyword'])(occur)
314 tweet = delimiter.join(ary)
7500d90b 315
8c7ae594 316 # Load config formater
318cdd67 317 formater = ''
8c7ae594
O
318 try:
319 formater = c['FORMAT']['TWEET']['DISPLAY']
7c437a0f
O
320 formater = name.join(formater.split('#name'))
321 formater = nick.join(formater.split('#nick'))
322 formater = fav.join(formater.split('#fav'))
323 formater = tweet.join(formater.split('#tweet'))
0d9977c7 324 # Change clock word
03c0d30b 325 word = [wo for wo in formater.split() if '#clock' in wo][0]
8141aca6 326 delimiter = color_func(c['TWEET']['clock'])(
327 clock.join(word.split('#clock')))
0d9977c7
O
328 formater = delimiter.join(formater.split(word))
329 # Change id word
03c0d30b 330 word = [wo for wo in formater.split() if '#id' in wo][0]
0d9977c7
O
331 delimiter = color_func(c['TWEET']['id'])(id.join(word.split('#id')))
332 formater = delimiter.join(formater.split(word))
318cdd67 333 # Change retweet count word
03c0d30b 334 word = [wo for wo in formater.split() if '#rt_count' in wo][0]
318cdd67
O
335 delimiter = color_func(c['TWEET']['retweet_count'])(
336 str(retweet_count).join(word.split('#rt_count')))
337 formater = delimiter.join(formater.split(word))
338 # Change favorites count word
03c0d30b 339 word = [wo for wo in formater.split() if '#fa_count' in wo][0]
318cdd67
O
340 delimiter = color_func(c['TWEET']['favorite_count'])(
341 str(favorite_count).join(word.split('#fa_count')))
342 formater = delimiter.join(formater.split(word))
841260fe 343 formater = emojize(formater)
8c7ae594 344 except:
318cdd67 345 pass
7500d90b 346
99cd1fba
O
347 # Add spaces in begining of line if this is inside a notification
348 if noti:
349 formater = '\n '.join(formater.split('\n'))
38a6dc30
O
350 # Reformat
351 if formater.startswith('\n'):
352 formater = formater[1:]
99cd1fba 353
8c7ae594
O
354 # Draw
355 printNicely(formater)
7500d90b
VNM
356
357 # Display Image
fe9bb33b 358 if c['IMAGE_ON_TERM'] and media_url:
7500d90b 359 for mu in media_url:
17bc529d 360 try:
361 response = requests.get(mu)
77f1d210 362 image_to_display(BytesIO(response.content))
363 except Exception:
17bc529d 364 printNicely(red('Sorry, image link is broken'))
7500d90b
VNM
365
366
67c663f8
O
367def print_threads(d):
368 """
369 Print threads of messages
370 """
371 id = 1
372 rel = {}
373 for partner in d:
374 messages = d[partner]
375 count = len(messages)
376 screen_name = '@' + partner[0]
377 name = partner[1]
378 screen_name = color_func(c['MESSAGE']['partner'])(screen_name)
379 name = cycle_color(name)
03c0d30b 380 thread_id = color_func(c['MESSAGE']['id'])('thread_id:' + str(id))
381 line = ' ' * 2 + name + ' ' + screen_name + \
67c663f8
O
382 ' (' + str(count) + ' message) ' + thread_id
383 printNicely(line)
384 rel[id] = partner
385 id += 1
386 dg['thread'] = d
387 return rel
388
389
390def print_thread(partner, me_nick, me_name):
391 """
392 Print a thread of messages
393 """
394 # Sort messages by time
395 messages = dg['thread'][partner]
03c0d30b 396 messages.sort(key=lambda x: parser.parse(x['created_at']))
397 # Use legacy display on non-ascii text message
bcb5518e 398 ms = [m['text'] for m in messages]
399 ums = [m for m in ms if not all(ord(c) < 128 for c in m)]
400 if ums:
03c0d30b 401 for m in messages:
402 print_message(m)
403 printNicely('')
404 return
405 # Print the first line
406 dg['frame_margin'] = margin = 2
407 partner_nick = partner[0]
408 partner_name = partner[1]
409 left_size = len(partner_nick) + len(partner_name) + 2
410 right_size = len(me_nick) + len(me_name) + 2
411 partner_nick = color_func(c['MESSAGE']['partner'])('@' + partner_nick)
412 partner_name = cycle_color(partner_name)
67c663f8
O
413 me_screen_name = color_func(c['MESSAGE']['me'])('@' + me_nick)
414 me_name = cycle_color(me_name)
03c0d30b 415 left = ' ' * margin + partner_name + ' ' + partner_nick
67c663f8
O
416 right = me_name + ' ' + me_screen_name + ' ' * margin
417 h, w = os.popen('stty size', 'r').read().split()
418 w = int(w)
03c0d30b 419 line = '{}{}{}'.format(
420 left, ' ' * (w - left_size - right_size - 2 * margin), right)
67c663f8
O
421 printNicely('')
422 printNicely(line)
423 printNicely('')
67c663f8
O
424 # Print messages
425 for m in messages:
426 if m['sender_screen_name'] == me_nick:
427 print_right_message(m)
428 elif m['recipient_screen_name'] == me_nick:
429 print_left_message(m)
430
431
432def print_right_message(m):
433 """
434 Print a message on the right of screen
435 """
436 h, w = os.popen('stty size', 'r').read().split()
437 w = int(w)
03c0d30b 438 frame_width = w // 3 - dg['frame_margin']
37cf396a 439 frame_width = max(c['THREAD_MIN_WIDTH'], frame_width)
03c0d30b 440 step = frame_width - 2 * dg['frame_margin']
bcb5518e 441 slicing = textwrap.wrap(m['text'], step)
03c0d30b 442 spaces = w - frame_width - dg['frame_margin']
67c663f8 443 dotline = ' ' * spaces + '-' * frame_width
03c0d30b 444 dotline = color_func(c['MESSAGE']['me_frame'])(dotline)
223d2e05 445 # Draw the frame
67c663f8
O
446 printNicely(dotline)
447 for line in slicing:
448 fill = step - len(line)
449 screen_line = ' ' * spaces + '| ' + line + ' ' * fill + ' '
450 if slicing[-1] == line:
451 screen_line = screen_line + ' >'
452 else:
453 screen_line = screen_line + '|'
03c0d30b 454 screen_line = color_func(c['MESSAGE']['me_frame'])(screen_line)
67c663f8
O
455 printNicely(screen_line)
456 printNicely(dotline)
03c0d30b 457 # Format clock
223d2e05
O
458 date = parser.parse(m['created_at'])
459 date = arrow.get(date).to('local').datetime
460 clock_format = '%Y/%m/%d %H:%M:%S'
461 try:
462 clock_format = c['FORMAT']['MESSAGE']['CLOCK_FORMAT']
463 except:
464 pass
465 clock = date.strftime(clock_format)
03c0d30b 466 # Format id
223d2e05
O
467 if m['id'] not in c['message_dict']:
468 c['message_dict'].append(m['id'])
469 rid = len(c['message_dict']) - 1
470 else:
471 rid = c['message_dict'].index(m['id'])
03c0d30b 472 id = str(rid)
473 # Print meta
474 formater = ''
475 try:
476 virtual_meta = formater = c['THREAD_META_RIGHT']
477 virtual_meta = clock.join(virtual_meta.split('#clock'))
478 virtual_meta = id.join(virtual_meta.split('#id'))
479 # Change clock word
480 word = [wo for wo in formater.split() if '#clock' in wo][0]
481 delimiter = color_func(c['MESSAGE']['clock'])(
482 clock.join(word.split('#clock')))
483 formater = delimiter.join(formater.split(word))
484 # Change id word
485 word = [wo for wo in formater.split() if '#id' in wo][0]
486 delimiter = color_func(c['MESSAGE']['id'])(id.join(word.split('#id')))
487 formater = delimiter.join(formater.split(word))
841260fe 488 formater = emojize(formater)
03c0d30b 489 except Exception:
490 printNicely(red('Wrong format in config.'))
491 return
492 meta = formater
493 line = ' ' * (w - len(virtual_meta) - dg['frame_margin']) + meta
223d2e05 494 printNicely(line)
67c663f8
O
495
496
497def print_left_message(m):
498 """
499 Print a message on the left of screen
500 """
501 h, w = os.popen('stty size', 'r').read().split()
502 w = int(w)
03c0d30b 503 frame_width = w // 3 - dg['frame_margin']
37cf396a 504 frame_width = max(c['THREAD_MIN_WIDTH'], frame_width)
03c0d30b 505 step = frame_width - 2 * dg['frame_margin']
bcb5518e 506 slicing = textwrap.wrap(m['text'], step)
03c0d30b 507 spaces = dg['frame_margin']
67c663f8 508 dotline = ' ' * spaces + '-' * frame_width
03c0d30b 509 dotline = color_func(c['MESSAGE']['partner_frame'])(dotline)
223d2e05 510 # Draw the frame
67c663f8
O
511 printNicely(dotline)
512 for line in slicing:
513 fill = step - len(line)
514 screen_line = ' ' + line + ' ' * fill + ' |'
515 if slicing[-1] == line:
03c0d30b 516 screen_line = ' ' * (spaces - 1) + '< ' + screen_line
67c663f8
O
517 else:
518 screen_line = ' ' * spaces + '|' + screen_line
03c0d30b 519 screen_line = color_func(c['MESSAGE']['partner_frame'])(screen_line)
67c663f8
O
520 printNicely(screen_line)
521 printNicely(dotline)
03c0d30b 522 # Format clock
223d2e05
O
523 date = parser.parse(m['created_at'])
524 date = arrow.get(date).to('local').datetime
525 clock_format = '%Y/%m/%d %H:%M:%S'
526 try:
527 clock_format = c['FORMAT']['MESSAGE']['CLOCK_FORMAT']
528 except:
529 pass
530 clock = date.strftime(clock_format)
03c0d30b 531 # Format id
223d2e05
O
532 if m['id'] not in c['message_dict']:
533 c['message_dict'].append(m['id'])
534 rid = len(c['message_dict']) - 1
535 else:
536 rid = c['message_dict'].index(m['id'])
03c0d30b 537 id = str(rid)
538 # Print meta
539 formater = ''
540 try:
541 virtual_meta = formater = c['THREAD_META_LEFT']
542 virtual_meta = clock.join(virtual_meta.split('#clock'))
543 virtual_meta = id.join(virtual_meta.split('#id'))
544 # Change clock word
545 word = [wo for wo in formater.split() if '#clock' in wo][0]
546 delimiter = color_func(c['MESSAGE']['clock'])(
547 clock.join(word.split('#clock')))
548 formater = delimiter.join(formater.split(word))
549 # Change id word
550 word = [wo for wo in formater.split() if '#id' in wo][0]
551 delimiter = color_func(c['MESSAGE']['id'])(id.join(word.split('#id')))
552 formater = delimiter.join(formater.split(word))
841260fe 553 formater = emojize(formater)
03c0d30b 554 except Exception:
555 printNicely(red('Wrong format in config.'))
556 return
557 meta = formater
558 line = ' ' * dg['frame_margin'] + meta
223d2e05 559 printNicely(line)
67c663f8
O
560
561
4dc385b5 562def print_message(m):
7500d90b
VNM
563 """
564 Print direct message
565 """
c37c04a9 566 # Retrieve message
7500d90b
VNM
567 sender_screen_name = '@' + m['sender_screen_name']
568 sender_name = m['sender']['name']
b2cde062 569 text = unescape(m['text'])
7500d90b
VNM
570 recipient_screen_name = '@' + m['recipient_screen_name']
571 recipient_name = m['recipient']['name']
572 mid = m['id']
573 date = parser.parse(m['created_at'])
8b3456f9 574 date = arrow.get(date).to('local').datetime
8c7ae594
O
575 clock_format = '%Y/%m/%d %H:%M:%S'
576 try:
577 clock_format = c['FORMAT']['MESSAGE']['CLOCK_FORMAT']
578 except:
579 pass
580 clock = date.strftime(clock_format)
7500d90b
VNM
581
582 # Get rainbow id
99b52f5f
O
583 if mid not in c['message_dict']:
584 c['message_dict'].append(mid)
585 rid = len(c['message_dict']) - 1
586 else:
587 rid = c['message_dict'].index(mid)
7500d90b 588
6fa09c14 589 # Draw
8c7ae594
O
590 sender_name = cycle_color(sender_name)
591 sender_nick = color_func(c['MESSAGE']['sender'])(sender_screen_name)
592 recipient_name = cycle_color(recipient_name)
0d9977c7
O
593 recipient_nick = color_func(
594 c['MESSAGE']['recipient'])(recipient_screen_name)
8c7ae594 595 to = color_func(c['MESSAGE']['to'])('>>>')
0d9977c7
O
596 clock = clock
597 id = str(rid)
8c7ae594 598
c3bab4ef 599 text = ''.join(lmap(lambda x: x + ' ' if x == '\n' else x, text))
7500d90b 600
8c7ae594
O
601 # Load config formater
602 try:
603 formater = c['FORMAT']['MESSAGE']['DISPLAY']
0d9977c7
O
604 formater = sender_name.join(formater.split("#sender_name"))
605 formater = sender_nick.join(formater.split("#sender_nick"))
606 formater = to.join(formater.split("#to"))
607 formater = recipient_name.join(formater.split("#recipient_name"))
608 formater = recipient_nick.join(formater.split("#recipient_nick"))
609 formater = text.join(formater.split("#message"))
610 # Change clock word
03c0d30b 611 word = [wo for wo in formater.split() if '#clock' in wo][0]
8141aca6 612 delimiter = color_func(c['MESSAGE']['clock'])(
613 clock.join(word.split('#clock')))
0d9977c7
O
614 formater = delimiter.join(formater.split(word))
615 # Change id word
03c0d30b 616 word = [wo for wo in formater.split() if '#id' in wo][0]
0d9977c7
O
617 delimiter = color_func(c['MESSAGE']['id'])(id.join(word.split('#id')))
618 formater = delimiter.join(formater.split(word))
841260fe 619 formater = emojize(formater)
8c7ae594
O
620 except:
621 printNicely(red('Wrong format in config.'))
622 return
623
624 # Draw
625 printNicely(formater)
7500d90b
VNM
626
627
38a6dc30
O
628def notify_retweet(t):
629 """
630 Notify a retweet
631 """
632 source = t['user']
633 created_at = t['created_at']
634 # Format
635 source_user = cycle_color(source['name']) + \
636 color_func(c['NOTIFICATION']['source_nick'])(
637 ' @' + source['screen_name'])
638 notify = color_func(c['NOTIFICATION']['notify'])(
639 'retweeted your tweet')
640 date = parser.parse(created_at)
e5455a30 641 clock = fallback_humanize(date)
38a6dc30
O
642 clock = color_func(c['NOTIFICATION']['clock'])(clock)
643 meta = c['NOTIFY_FORMAT']
644 meta = source_user.join(meta.split('#source_user'))
645 meta = notify.join(meta.split('#notify'))
646 meta = clock.join(meta.split('#clock'))
104619ce 647 meta = emojize(meta)
38a6dc30
O
648 # Output
649 printNicely('')
650 printNicely(meta)
651 draw(t=t['retweeted_status'], noti=True)
652
653
99cd1fba
O
654def notify_favorite(e):
655 """
656 Notify a favorite event
657 """
658 # Retrieve info
659 target = e['target']
660 if target['screen_name'] != c['original_name']:
661 return
662 source = e['source']
663 target_object = e['target_object']
664 created_at = e['created_at']
665 # Format
666 source_user = cycle_color(source['name']) + \
667 color_func(c['NOTIFICATION']['source_nick'])(
668 ' @' + source['screen_name'])
38a6dc30
O
669 notify = color_func(c['NOTIFICATION']['notify'])(
670 'favorited your tweet')
99cd1fba 671 date = parser.parse(created_at)
e5455a30 672 clock = fallback_humanize(date)
99cd1fba 673 clock = color_func(c['NOTIFICATION']['clock'])(clock)
38a6dc30
O
674 meta = c['NOTIFY_FORMAT']
675 meta = source_user.join(meta.split('#source_user'))
676 meta = notify.join(meta.split('#notify'))
677 meta = clock.join(meta.split('#clock'))
104619ce 678 meta = emojize(meta)
99cd1fba
O
679 # Output
680 printNicely('')
681 printNicely(meta)
682 draw(t=target_object, noti=True)
683
684
685def notify_unfavorite(e):
686 """
687 Notify a unfavorite event
688 """
689 # Retrieve info
690 target = e['target']
691 if target['screen_name'] != c['original_name']:
692 return
693 source = e['source']
694 target_object = e['target_object']
695 created_at = e['created_at']
696 # Format
697 source_user = cycle_color(source['name']) + \
698 color_func(c['NOTIFICATION']['source_nick'])(
699 ' @' + source['screen_name'])
700 notify = color_func(c['NOTIFICATION']['notify'])(
38a6dc30 701 'unfavorited your tweet')
99cd1fba 702 date = parser.parse(created_at)
e5455a30 703 clock = fallback_humanize(date)
99cd1fba 704 clock = color_func(c['NOTIFICATION']['clock'])(clock)
38a6dc30
O
705 meta = c['NOTIFY_FORMAT']
706 meta = source_user.join(meta.split('#source_user'))
707 meta = notify.join(meta.split('#notify'))
708 meta = clock.join(meta.split('#clock'))
104619ce 709 meta = emojize(meta)
99cd1fba
O
710 # Output
711 printNicely('')
712 printNicely(meta)
713 draw(t=target_object, noti=True)
714
715
716def notify_follow(e):
717 """
718 Notify a follow event
719 """
720 # Retrieve info
721 target = e['target']
722 if target['screen_name'] != c['original_name']:
723 return
724 source = e['source']
725 created_at = e['created_at']
726 # Format
727 source_user = cycle_color(source['name']) + \
728 color_func(c['NOTIFICATION']['source_nick'])(
729 ' @' + source['screen_name'])
38a6dc30
O
730 notify = color_func(c['NOTIFICATION']['notify'])(
731 'followed you')
99cd1fba 732 date = parser.parse(created_at)
e5455a30 733 clock = fallback_humanize(date)
99cd1fba 734 clock = color_func(c['NOTIFICATION']['clock'])(clock)
38a6dc30
O
735 meta = c['NOTIFY_FORMAT']
736 meta = source_user.join(meta.split('#source_user'))
737 meta = notify.join(meta.split('#notify'))
738 meta = clock.join(meta.split('#clock'))
104619ce 739 meta = emojize(meta)
99cd1fba
O
740 # Output
741 printNicely('')
742 printNicely(meta)
743
744
745def notify_list_member_added(e):
746 """
747 Notify a list_member_added event
748 """
749 # Retrieve info
750 target = e['target']
751 if target['screen_name'] != c['original_name']:
752 return
753 source = e['source']
754 target_object = [e['target_object']] # list of Twitter list
755 created_at = e['created_at']
756 # Format
757 source_user = cycle_color(source['name']) + \
758 color_func(c['NOTIFICATION']['source_nick'])(
759 ' @' + source['screen_name'])
38a6dc30
O
760 notify = color_func(c['NOTIFICATION']['notify'])(
761 'added you to a list')
99cd1fba 762 date = parser.parse(created_at)
e5455a30 763 clock = fallback_humanize(date)
99cd1fba 764 clock = color_func(c['NOTIFICATION']['clock'])(clock)
38a6dc30
O
765 meta = c['NOTIFY_FORMAT']
766 meta = source_user.join(meta.split('#source_user'))
767 meta = notify.join(meta.split('#notify'))
768 meta = clock.join(meta.split('#clock'))
104619ce 769 meta = emojize(meta)
99cd1fba
O
770 # Output
771 printNicely('')
772 printNicely(meta)
773 print_list(target_object, noti=True)
774
775
776def notify_list_member_removed(e):
777 """
778 Notify a list_member_removed event
779 """
780 # Retrieve info
781 target = e['target']
782 if target['screen_name'] != c['original_name']:
783 return
784 source = e['source']
785 target_object = [e['target_object']] # list of Twitter list
786 created_at = e['created_at']
787 # Format
788 source_user = cycle_color(source['name']) + \
789 color_func(c['NOTIFICATION']['source_nick'])(
790 ' @' + source['screen_name'])
791 notify = color_func(c['NOTIFICATION']['notify'])(
38a6dc30 792 'removed you from a list')
99cd1fba 793 date = parser.parse(created_at)
e5455a30 794 clock = fallback_humanize(date)
99cd1fba 795 clock = color_func(c['NOTIFICATION']['clock'])(clock)
38a6dc30
O
796 meta = c['NOTIFY_FORMAT']
797 meta = source_user.join(meta.split('#source_user'))
798 meta = notify.join(meta.split('#notify'))
799 meta = clock.join(meta.split('#clock'))
104619ce 800 meta = emojize(meta)
99cd1fba
O
801 # Output
802 printNicely('')
803 printNicely(meta)
804 print_list(target_object, noti=True)
805
806
807def notify_list_user_subscribed(e):
808 """
809 Notify a list_user_subscribed event
810 """
811 # Retrieve info
812 target = e['target']
813 if target['screen_name'] != c['original_name']:
814 return
815 source = e['source']
816 target_object = [e['target_object']] # list of Twitter list
817 created_at = e['created_at']
818 # Format
819 source_user = cycle_color(source['name']) + \
820 color_func(c['NOTIFICATION']['source_nick'])(
821 ' @' + source['screen_name'])
822 notify = color_func(c['NOTIFICATION']['notify'])(
38a6dc30 823 'subscribed to your list')
99cd1fba 824 date = parser.parse(created_at)
e5455a30 825 clock = fallback_humanize(date)
99cd1fba 826 clock = color_func(c['NOTIFICATION']['clock'])(clock)
38a6dc30
O
827 meta = c['NOTIFY_FORMAT']
828 meta = source_user.join(meta.split('#source_user'))
829 meta = notify.join(meta.split('#notify'))
830 meta = clock.join(meta.split('#clock'))
104619ce 831 meta = emojize(meta)
99cd1fba
O
832 # Output
833 printNicely('')
834 printNicely(meta)
835 print_list(target_object, noti=True)
836
837
838def notify_list_user_unsubscribed(e):
839 """
840 Notify a list_user_unsubscribed event
841 """
842 # Retrieve info
843 target = e['target']
844 if target['screen_name'] != c['original_name']:
845 return
846 source = e['source']
847 target_object = [e['target_object']] # list of Twitter list
848 created_at = e['created_at']
849 # Format
850 source_user = cycle_color(source['name']) + \
851 color_func(c['NOTIFICATION']['source_nick'])(
852 ' @' + source['screen_name'])
853 notify = color_func(c['NOTIFICATION']['notify'])(
38a6dc30 854 'unsubscribed from your list')
99cd1fba 855 date = parser.parse(created_at)
e5455a30 856 clock = fallback_humanize(date)
99cd1fba 857 clock = color_func(c['NOTIFICATION']['clock'])(clock)
38a6dc30
O
858 meta = c['NOTIFY_FORMAT']
859 meta = source_user.join(meta.split('#source_user'))
860 meta = notify.join(meta.split('#notify'))
861 meta = clock.join(meta.split('#clock'))
104619ce 862 meta = emojize(meta)
99cd1fba
O
863 # Output
864 printNicely('')
865 printNicely(meta)
866 print_list(target_object, noti=True)
867
868
869def print_event(e):
870 """
871 Notify an event
872 """
873 event_dict = {
38a6dc30 874 'retweet': notify_retweet,
99cd1fba
O
875 'favorite': notify_favorite,
876 'unfavorite': notify_unfavorite,
877 'follow': notify_follow,
878 'list_member_added': notify_list_member_added,
879 'list_member_removed': notify_list_member_removed,
880 'list_user_subscribed': notify_list_user_subscribed,
881 'list_user_unsubscribed': notify_list_user_unsubscribed,
882 }
69340648 883 event_dict.get(e['event'], lambda *args: None)(e)
99cd1fba
O
884
885
fe9bb33b 886def show_profile(u):
7500d90b
VNM
887 """
888 Show a profile
889 """
890 # Retrieve info
891 name = u['name']
892 screen_name = u['screen_name']
893 description = u['description']
894 profile_image_url = u['profile_image_url']
895 location = u['location']
896 url = u['url']
897 created_at = u['created_at']
898 statuses_count = u['statuses_count']
899 friends_count = u['friends_count']
900 followers_count = u['followers_count']
6fa09c14 901
7500d90b 902 # Create content
c075e6dc
O
903 statuses_count = color_func(
904 c['PROFILE']['statuses_count'])(
905 str(statuses_count) +
906 ' tweets')
907 friends_count = color_func(
908 c['PROFILE']['friends_count'])(
909 str(friends_count) +
910 ' following')
911 followers_count = color_func(
912 c['PROFILE']['followers_count'])(
913 str(followers_count) +
914 ' followers')
7500d90b 915 count = statuses_count + ' ' + friends_count + ' ' + followers_count
c075e6dc
O
916 user = cycle_color(
917 name) + color_func(c['PROFILE']['nick'])(' @' + screen_name + ' : ') + count
918 profile_image_raw_url = 'Profile photo: ' + \
919 color_func(c['PROFILE']['profile_image_url'])(profile_image_url)
7500d90b 920 description = ''.join(
c3bab4ef 921 lmap(lambda x: x + ' ' * 4 if x == '\n' else x, description))
632c6fa5
O
922 description = color_func(c['PROFILE']['description'])(description)
923 location = 'Location : ' + color_func(c['PROFILE']['location'])(location)
924 url = 'URL : ' + (color_func(c['PROFILE']['url'])(url) if url else '')
7500d90b 925 date = parser.parse(created_at)
e5455a30 926 clock = fallback_humanize(date)
632c6fa5 927 clock = 'Join at ' + color_func(c['PROFILE']['clock'])(clock)
6fa09c14 928
7500d90b
VNM
929 # Format
930 line1 = u"{u:>{uw}}".format(
931 u=user,
932 uw=len(user) + 2,
933 )
934 line2 = u"{p:>{pw}}".format(
935 p=profile_image_raw_url,
936 pw=len(profile_image_raw_url) + 4,
937 )
938 line3 = u"{d:>{dw}}".format(
939 d=description,
940 dw=len(description) + 4,
941 )
942 line4 = u"{l:>{lw}}".format(
943 l=location,
944 lw=len(location) + 4,
945 )
946 line5 = u"{u:>{uw}}".format(
947 u=url,
948 uw=len(url) + 4,
949 )
950 line6 = u"{c:>{cw}}".format(
951 c=clock,
952 cw=len(clock) + 4,
953 )
6fa09c14 954
7500d90b
VNM
955 # Display
956 printNicely('')
957 printNicely(line1)
fe9bb33b 958 if c['IMAGE_ON_TERM']:
17bc529d 959 try:
960 response = requests.get(profile_image_url)
c37c04a9 961 image_to_display(BytesIO(response.content))
17bc529d 962 except:
963 pass
7500d90b
VNM
964 else:
965 printNicely(line2)
966 for line in [line3, line4, line5, line6]:
967 printNicely(line)
968 printNicely('')
969
970
971def print_trends(trends):
972 """
973 Display topics
974 """
632c6fa5 975 for topic in trends[:c['TREND_MAX']]:
7500d90b
VNM
976 name = topic['name']
977 url = topic['url']
8394e34b 978 line = cycle_color(name) + ': ' + color_func(c['TREND']['url'])(url)
7500d90b
VNM
979 printNicely(line)
980 printNicely('')
2d341029
O
981
982
99cd1fba 983def print_list(group, noti=False):
2d341029
O
984 """
985 Display a list
986 """
99b52f5f 987 for grp in group:
2d341029 988 # Format
99b52f5f 989 name = grp['full_name']
2d341029 990 name = color_func(c['GROUP']['name'])(name + ' : ')
99b52f5f 991 member = str(grp['member_count'])
422dd385 992 member = color_func(c['GROUP']['member'])(member + ' member')
99b52f5f 993 subscriber = str(grp['subscriber_count'])
422dd385
O
994 subscriber = color_func(
995 c['GROUP']['subscriber'])(
996 subscriber +
997 ' subscriber')
99b52f5f 998 description = grp['description'].strip()
2d341029 999 description = color_func(c['GROUP']['description'])(description)
99b52f5f 1000 mode = grp['mode']
422dd385 1001 mode = color_func(c['GROUP']['mode'])('Type: ' + mode)
99b52f5f 1002 created_at = grp['created_at']
2d341029 1003 date = parser.parse(created_at)
e5455a30 1004 clock = fallback_humanize(date)
2d341029
O
1005 clock = 'Created at ' + color_func(c['GROUP']['clock'])(clock)
1006
99cd1fba
O
1007 prefix = ' ' * 2
1008 # Add spaces in begining of line if this is inside a notification
1009 if noti:
1010 prefix = ' ' * 2 + prefix
2d341029 1011 # Create lines
99cd1fba
O
1012 line1 = prefix + name + member + ' ' + subscriber
1013 line2 = prefix + ' ' * 2 + description
1014 line3 = prefix + ' ' * 2 + mode
1015 line4 = prefix + ' ' * 2 + clock
2d341029
O
1016
1017 # Display
1018 printNicely('')
1019 printNicely(line1)
1020 printNicely(line2)
1021 printNicely(line3)
1022 printNicely(line4)
1023
38a6dc30
O
1024 if not noti:
1025 printNicely('')
59262e95
O
1026
1027
8141aca6 1028def show_calendar(month, date, rel):
1029 """
1030 Show the calendar in rainbow mode
1031 """
1032 month = random_rainbow(month)
1033 date = ' '.join([cycle_color(i) for i in date.split(' ')])
1034 today = str(int(os.popen('date +\'%d\'').read().strip()))
1035 # Display
1036 printNicely(month)
1037 printNicely(date)
1038 for line in rel:
1039 ary = line.split(' ')
1040 ary = lmap(
1041 lambda x: color_func(c['CAL']['today'])(x)
1042 if x == today
1043 else color_func(c['CAL']['days'])(x),
1044 ary)
1045 printNicely(' '.join(ary))
1046
1047
b7c9c570 1048def format_quote(tweet):
1049 """
1050 Quoting format
1051 """
1052 # Retrieve info
1053 screen_name = '@' + tweet['user']['screen_name']
1054 text = tweet['text']
1055 # Validate quote format
1056 if '#owner' not in c['QUOTE_FORMAT']:
1057 printNicely(light_magenta('Quote should contains #owner'))
1058 return False
1059 if '#comment' not in c['QUOTE_FORMAT']:
1060 printNicely(light_magenta('Quote format should have #comment'))
1061 return False
1062 # Build formater
1063 formater = ''
1064 try:
1065 formater = c['QUOTE_FORMAT']
1066 formater = screen_name.join(formater.split('#owner'))
1067 formater = text.join(formater.split('#tweet'))
1068 formater = u2str(formater)
104619ce 1069 formater = emojize(formater)
b7c9c570 1070 except:
1071 pass
1072 # Highlight like a tweet
4dc385b5
O
1073 notice = formater.split()
1074 notice = lmap(
b7c9c570 1075 lambda x: light_green(x)
1076 if x == '#comment'
1077 else x,
4dc385b5
O
1078 notice)
1079 notice = lmap(
b7c9c570 1080 lambda x: color_func(c['TWEET']['rt'])(x)
1081 if x == 'RT'
1082 else x,
4dc385b5
O
1083 notice)
1084 notice = lmap(lambda x: cycle_color(x) if x[0] == '@' else x, notice)
1085 notice = lmap(
b7c9c570 1086 lambda x: color_func(c['TWEET']['link'])(x)
1087 if x[0:4] == 'http'
1088 else x,
4dc385b5
O
1089 notice)
1090 notice = lmap(
b7c9c570 1091 lambda x: color_func(c['TWEET']['hashtag'])(x)
1092 if x.startswith('#')
1093 else x,
4dc385b5
O
1094 notice)
1095 notice = ' '.join(notice)
b7c9c570 1096 # Notice
4dc385b5 1097 notice = light_magenta('Quoting: "') + notice + light_magenta('"')
b7c9c570 1098 printNicely(notice)
1099 return formater
1100
1101
59262e95 1102# Start the color cycle
b2cde062 1103start_cycle()