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