b43cd9f90bdc99082886e082ccae5ef450564e8f
[rainbowstream.git] / rainbowstream / draw.py
1 import random
2 import textwrap
3 import itertools
4 import requests
5 import locale
6 import arrow
7 import re
8 import os
9
10 from twitter.util import printNicely
11 from functools import wraps
12 from pyfiglet import figlet_format
13 from dateutil import parser
14 from .c_image import *
15 from .colors import *
16 from .config import *
17 from .py3patch import *
18 from .emoji import *
19
20 # Draw global variables
21 dg = {}
22
23
24 def init_cycle():
25 """
26 Init the cycle
27 """
28 colors_shuffle = [globals()[i.encode('utf8')]
29 if not str(i).isdigit()
30 else term_color(int(i))
31 for i in c['CYCLE_COLOR']]
32 return itertools.cycle(colors_shuffle)
33
34
35 def start_cycle():
36 """
37 Notify from rainbow
38 """
39 dg['cyc'] = init_cycle()
40 dg['cache'] = {}
41
42
43 def order_rainbow(s):
44 """
45 Print a string with ordered color with each character
46 """
47 colors_shuffle = [globals()[i.encode('utf8')]
48 if not str(i).isdigit()
49 else term_color(int(i))
50 for i in c['CYCLE_COLOR']]
51 colored = [colors_shuffle[i % 7](s[i]) for i in xrange(len(s))]
52 return ''.join(colored)
53
54
55 def random_rainbow(s):
56 """
57 Print a string with random color with each character
58 """
59 colors_shuffle = [globals()[i.encode('utf8')]
60 if not str(i).isdigit()
61 else term_color(int(i))
62 for i in c['CYCLE_COLOR']]
63 colored = [random.choice(colors_shuffle)(i) for i in s]
64 return ''.join(colored)
65
66
67 def Memoize(func):
68 """
69 Memoize decorator
70 """
71 @wraps(func)
72 def wrapper(*args):
73 if args not in dg['cache']:
74 dg['cache'][args] = func(*args)
75 return dg['cache'][args]
76 return wrapper
77
78
79 @Memoize
80 def cycle_color(s):
81 """
82 Cycle the colors_shuffle
83 """
84 return next(dg['cyc'])(s)
85
86
87 def ascii_art(text):
88 """
89 Draw the Ascii Art
90 """
91 fi = figlet_format(text, font='doom')
92 print('\n'.join(
93 [next(dg['cyc'])(i) for i in fi.split('\n')]
94 ))
95
96
97 def check_config():
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
111 def 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
119
120
121 def reload_theme(value, prev):
122 """
123 Check current theme and update if necessary
124 """
125 if value != prev:
126 config = os.path.dirname(
127 __file__) + '/colorset/' + value + '.json'
128 # Load new config
129 data = load_config(config)
130 if data:
131 for d in data:
132 c[d] = data[d]
133 # Restart color cycle and update config
134 start_cycle()
135 set_config('THEME', value)
136 return value
137 return prev
138
139
140 def color_func(func_name):
141 """
142 Call color function base on name
143 """
144 if str(func_name).isdigit():
145 return term_color(int(func_name))
146 return globals()[func_name]
147
148
149 def draw(t, keyword=None, humanize=True, noti=False, fil=[], ig=[]):
150 """
151 Draw the rainbow
152 """
153 # Check config
154 check_config()
155
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 retweet_count = t['retweet_count']
164 favorite_count = t['favorite_count']
165 date = parser.parse(created_at)
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)
176
177 # Pull extended retweet text
178 try:
179 text = 'RT @' + t['retweeted_status']['user']['screen_name'] + ': ' +\
180 t['retweeted_status']['text']
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
189 except:
190 pass
191
192 # Unescape HTML character
193 text = unescape(text)
194
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
217 mytweet = screen_name == c['original_name']
218 screen_name = '@' + screen_name
219 fil = list(set((fil or []) + c['ONLY_LIST']))
220 ig = list(set((ig or []) + c['IGNORE_LIST']))
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
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)
232
233 # Format info
234 name = cycle_color(name)
235 if mytweet:
236 nick = color_func(c['TWEET']['mynick'])(screen_name)
237 else:
238 nick = color_func(c['TWEET']['nick'])(screen_name)
239 clock = clock
240 id = str(rid)
241 fav = ''
242 if favorited:
243 fav = color_func(c['TWEET']['favorited'])(u'\u2605')
244
245 tweet = text.split()
246 # Replace url
247 if expanded_url:
248 for index in xrange(len(expanded_url)):
249 tweet = lmap(
250 lambda x: expanded_url[index]
251 if x == url[index]
252 else x,
253 tweet)
254 # Highlight RT
255 tweet = lmap(
256 lambda x: color_func(c['TWEET']['rt'])(x)
257 if x == 'RT'
258 else x,
259 tweet)
260 # Highlight screen_name
261 tweet = lmap(lambda x: cycle_color(x) if x[0] == '@' else x, tweet)
262 # Highlight link
263 tweet = lmap(
264 lambda x: color_func(c['TWEET']['link'])(x)
265 if x.startswith('http')
266 else x,
267 tweet)
268 # Highlight hashtag
269 tweet = lmap(
270 lambda x: color_func(c['TWEET']['hashtag'])(x)
271 if x.startswith('#')
272 else x,
273 tweet)
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 ]
283 # Highlight keyword
284 tweet = ' '.join(tweet)
285 if keyword:
286 roj = re.search(keyword, tweet, re.IGNORECASE)
287 if roj:
288 occur = roj.group()
289 ary = tweet.split(occur)
290 delimiter = color_func(c['TWEET']['keyword'])(occur)
291 tweet = delimiter.join(ary)
292
293 # Load config formater
294 formater = ''
295 try:
296 formater = c['FORMAT']['TWEET']['DISPLAY']
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'))
301 # Change clock word
302 word = [wo for wo in formater.split() if '#clock' in wo][0]
303 delimiter = color_func(c['TWEET']['clock'])(
304 clock.join(word.split('#clock')))
305 formater = delimiter.join(formater.split(word))
306 # Change id word
307 word = [wo for wo in formater.split() if '#id' in wo][0]
308 delimiter = color_func(c['TWEET']['id'])(id.join(word.split('#id')))
309 formater = delimiter.join(formater.split(word))
310 # Change retweet count word
311 word = [wo for wo in formater.split() if '#rt_count' in wo][0]
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
316 word = [wo for wo in formater.split() if '#fa_count' in wo][0]
317 delimiter = color_func(c['TWEET']['favorite_count'])(
318 str(favorite_count).join(word.split('#fa_count')))
319 formater = delimiter.join(formater.split(word))
320 formater = emojize(formater)
321 except:
322 pass
323
324 # Add spaces in begining of line if this is inside a notification
325 if noti:
326 formater = '\n '.join(formater.split('\n'))
327 # Reformat
328 if formater.startswith('\n'):
329 formater = formater[1:]
330
331 # Draw
332 printNicely(formater)
333
334 # Display Image
335 if c['IMAGE_ON_TERM'] and media_url:
336 for mu in media_url:
337 try:
338 response = requests.get(mu)
339 image_to_display(BytesIO(response.content))
340 except Exception:
341 printNicely(red('Sorry, image link is broken'))
342
343
344 def 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)
357 thread_id = color_func(c['MESSAGE']['id'])('thread_id:' + str(id))
358 line = ' ' * 2 + name + ' ' + screen_name + \
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
367 def 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]
373 messages.sort(key=lambda x: parser.parse(x['created_at']))
374 # Use legacy display on non-ascii text message
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:
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)
390 me_screen_name = color_func(c['MESSAGE']['me'])('@' + me_nick)
391 me_name = cycle_color(me_name)
392 left = ' ' * margin + partner_name + ' ' + partner_nick
393 right = me_name + ' ' + me_screen_name + ' ' * margin
394 h, w = os.popen('stty size', 'r').read().split()
395 w = int(w)
396 line = '{}{}{}'.format(
397 left, ' ' * (w - left_size - right_size - 2 * margin), right)
398 printNicely('')
399 printNicely(line)
400 printNicely('')
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
409 def 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)
415 frame_width = w // 3 - dg['frame_margin']
416 frame_width = max(c['THREAD_MIN_WIDTH'], frame_width)
417 step = frame_width - 2 * dg['frame_margin']
418 slicing = textwrap.wrap(m['text'], step)
419 spaces = w - frame_width - dg['frame_margin']
420 dotline = ' ' * spaces + '-' * frame_width
421 dotline = color_func(c['MESSAGE']['me_frame'])(dotline)
422 # Draw the frame
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 + '|'
431 screen_line = color_func(c['MESSAGE']['me_frame'])(screen_line)
432 printNicely(screen_line)
433 printNicely(dotline)
434 # Format clock
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)
443 # Format id
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'])
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))
465 formater = emojize(formater)
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
471 printNicely(line)
472
473
474 def 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)
480 frame_width = w // 3 - dg['frame_margin']
481 frame_width = max(c['THREAD_MIN_WIDTH'], frame_width)
482 step = frame_width - 2 * dg['frame_margin']
483 slicing = textwrap.wrap(m['text'], step)
484 spaces = dg['frame_margin']
485 dotline = ' ' * spaces + '-' * frame_width
486 dotline = color_func(c['MESSAGE']['partner_frame'])(dotline)
487 # Draw the frame
488 printNicely(dotline)
489 for line in slicing:
490 fill = step - len(line)
491 screen_line = ' ' + line + ' ' * fill + ' |'
492 if slicing[-1] == line:
493 screen_line = ' ' * (spaces - 1) + '< ' + screen_line
494 else:
495 screen_line = ' ' * spaces + '|' + screen_line
496 screen_line = color_func(c['MESSAGE']['partner_frame'])(screen_line)
497 printNicely(screen_line)
498 printNicely(dotline)
499 # Format clock
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)
508 # Format id
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'])
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))
530 formater = emojize(formater)
531 except Exception:
532 printNicely(red('Wrong format in config.'))
533 return
534 meta = formater
535 line = ' ' * dg['frame_margin'] + meta
536 printNicely(line)
537
538
539 def print_message(m):
540 """
541 Print direct message
542 """
543 # Retrieve message
544 sender_screen_name = '@' + m['sender_screen_name']
545 sender_name = m['sender']['name']
546 text = unescape(m['text'])
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'])
551 date = arrow.get(date).to('local').datetime
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)
558
559 # Get rainbow id
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)
565
566 # Draw
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)
570 recipient_nick = color_func(
571 c['MESSAGE']['recipient'])(recipient_screen_name)
572 to = color_func(c['MESSAGE']['to'])('>>>')
573 clock = clock
574 id = str(rid)
575
576 text = ''.join(lmap(lambda x: x + ' ' if x == '\n' else x, text))
577
578 # Load config formater
579 try:
580 formater = c['FORMAT']['MESSAGE']['DISPLAY']
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
588 word = [wo for wo in formater.split() if '#clock' in wo][0]
589 delimiter = color_func(c['MESSAGE']['clock'])(
590 clock.join(word.split('#clock')))
591 formater = delimiter.join(formater.split(word))
592 # Change id word
593 word = [wo for wo in formater.split() if '#id' in wo][0]
594 delimiter = color_func(c['MESSAGE']['id'])(id.join(word.split('#id')))
595 formater = delimiter.join(formater.split(word))
596 formater = emojize(formater)
597 except:
598 printNicely(red('Wrong format in config.'))
599 return
600
601 # Draw
602 printNicely(formater)
603
604
605 def 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'))
626 meta = emojize(meta)
627 # Output
628 printNicely('')
629 printNicely(meta)
630 draw(t=t['retweeted_status'], noti=True)
631
632
633 def 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'])
648 notify = color_func(c['NOTIFICATION']['notify'])(
649 'favorited your tweet')
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)
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'))
659 meta = emojize(meta)
660 # Output
661 printNicely('')
662 printNicely(meta)
663 draw(t=target_object, noti=True)
664
665
666 def 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'])(
682 'unfavorited your tweet')
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)
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'))
692 meta = emojize(meta)
693 # Output
694 printNicely('')
695 printNicely(meta)
696 draw(t=target_object, noti=True)
697
698
699 def 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'])
713 notify = color_func(c['NOTIFICATION']['notify'])(
714 'followed you')
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)
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'))
724 meta = emojize(meta)
725 # Output
726 printNicely('')
727 printNicely(meta)
728
729
730 def 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'])
745 notify = color_func(c['NOTIFICATION']['notify'])(
746 'added you to a list')
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)
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'))
756 meta = emojize(meta)
757 # Output
758 printNicely('')
759 printNicely(meta)
760 print_list(target_object, noti=True)
761
762
763 def 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'])(
779 'removed you from a list')
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)
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'))
789 meta = emojize(meta)
790 # Output
791 printNicely('')
792 printNicely(meta)
793 print_list(target_object, noti=True)
794
795
796 def 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'])(
812 'subscribed to your list')
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)
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'))
822 meta = emojize(meta)
823 # Output
824 printNicely('')
825 printNicely(meta)
826 print_list(target_object, noti=True)
827
828
829 def 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'])(
845 'unsubscribed from your list')
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)
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'))
855 meta = emojize(meta)
856 # Output
857 printNicely('')
858 printNicely(meta)
859 print_list(target_object, noti=True)
860
861
862 def print_event(e):
863 """
864 Notify an event
865 """
866 event_dict = {
867 'retweet': notify_retweet,
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 }
876 event_dict.get(e['event'], lambda *args: None)(e)
877
878
879 def show_profile(u):
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']
894
895 # Create content
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')
908 count = statuses_count + ' ' + friends_count + ' ' + followers_count
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)
913 description = ''.join(
914 lmap(lambda x: x + ' ' * 4 if x == '\n' else x, description))
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 '')
918 date = parser.parse(created_at)
919 lang, encode = locale.getdefaultlocale()
920 clock = arrow.get(date).to('local').humanize(locale=lang)
921 clock = 'Join at ' + color_func(c['PROFILE']['clock'])(clock)
922
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 )
948
949 # Display
950 printNicely('')
951 printNicely(line1)
952 if c['IMAGE_ON_TERM']:
953 try:
954 response = requests.get(profile_image_url)
955 image_to_display(BytesIO(response.content))
956 except:
957 pass
958 else:
959 printNicely(line2)
960 for line in [line3, line4, line5, line6]:
961 printNicely(line)
962 printNicely('')
963
964
965 def print_trends(trends):
966 """
967 Display topics
968 """
969 for topic in trends[:c['TREND_MAX']]:
970 name = topic['name']
971 url = topic['url']
972 line = cycle_color(name) + ': ' + color_func(c['TREND']['url'])(url)
973 printNicely(line)
974 printNicely('')
975
976
977 def print_list(group, noti=False):
978 """
979 Display a list
980 """
981 for grp in group:
982 # Format
983 name = grp['full_name']
984 name = color_func(c['GROUP']['name'])(name + ' : ')
985 member = str(grp['member_count'])
986 member = color_func(c['GROUP']['member'])(member + ' member')
987 subscriber = str(grp['subscriber_count'])
988 subscriber = color_func(
989 c['GROUP']['subscriber'])(
990 subscriber +
991 ' subscriber')
992 description = grp['description'].strip()
993 description = color_func(c['GROUP']['description'])(description)
994 mode = grp['mode']
995 mode = color_func(c['GROUP']['mode'])('Type: ' + mode)
996 created_at = grp['created_at']
997 date = parser.parse(created_at)
998 lang, encode = locale.getdefaultlocale()
999 clock = arrow.get(date).to('local').humanize(locale=lang)
1000 clock = 'Created at ' + color_func(c['GROUP']['clock'])(clock)
1001
1002 prefix = ' ' * 2
1003 # Add spaces in begining of line if this is inside a notification
1004 if noti:
1005 prefix = ' ' * 2 + prefix
1006 # Create lines
1007 line1 = prefix + name + member + ' ' + subscriber
1008 line2 = prefix + ' ' * 2 + description
1009 line3 = prefix + ' ' * 2 + mode
1010 line4 = prefix + ' ' * 2 + clock
1011
1012 # Display
1013 printNicely('')
1014 printNicely(line1)
1015 printNicely(line2)
1016 printNicely(line3)
1017 printNicely(line4)
1018
1019 if not noti:
1020 printNicely('')
1021
1022
1023 def 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
1043 def 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)
1064 formater = emojize(formater)
1065 except:
1066 pass
1067 # Highlight like a tweet
1068 notice = formater.split()
1069 notice = lmap(
1070 lambda x: light_green(x)
1071 if x == '#comment'
1072 else x,
1073 notice)
1074 notice = lmap(
1075 lambda x: color_func(c['TWEET']['rt'])(x)
1076 if x == 'RT'
1077 else x,
1078 notice)
1079 notice = lmap(lambda x: cycle_color(x) if x[0] == '@' else x, notice)
1080 notice = lmap(
1081 lambda x: color_func(c['TWEET']['link'])(x)
1082 if x[0:4] == 'http'
1083 else x,
1084 notice)
1085 notice = lmap(
1086 lambda x: color_func(c['TWEET']['hashtag'])(x)
1087 if x.startswith('#')
1088 else x,
1089 notice)
1090 notice = ' '.join(notice)
1091 # Notice
1092 notice = light_magenta('Quoting: "') + notice + light_magenta('"')
1093 printNicely(notice)
1094 return formater
1095
1096
1097 # Start the color cycle
1098 start_cycle()