202b629a31220b33aa61e6f891222f63847e4d7b
[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 # Output
627 printNicely('')
628 printNicely(meta)
629 draw(t=t['retweeted_status'], noti=True)
630
631
632 def notify_favorite(e):
633 """
634 Notify a favorite event
635 """
636 # Retrieve info
637 target = e['target']
638 if target['screen_name'] != c['original_name']:
639 return
640 source = e['source']
641 target_object = e['target_object']
642 created_at = e['created_at']
643 # Format
644 source_user = cycle_color(source['name']) + \
645 color_func(c['NOTIFICATION']['source_nick'])(
646 ' @' + source['screen_name'])
647 notify = color_func(c['NOTIFICATION']['notify'])(
648 'favorited your tweet')
649 date = parser.parse(created_at)
650 date = arrow.get(date).to('local')
651 lang, encode = locale.getdefaultlocale()
652 clock = arrow.get(date).to('local').humanize(locale=lang)
653 clock = color_func(c['NOTIFICATION']['clock'])(clock)
654 meta = c['NOTIFY_FORMAT']
655 meta = source_user.join(meta.split('#source_user'))
656 meta = notify.join(meta.split('#notify'))
657 meta = clock.join(meta.split('#clock'))
658 # Output
659 printNicely('')
660 printNicely(meta)
661 draw(t=target_object, noti=True)
662
663
664 def notify_unfavorite(e):
665 """
666 Notify a unfavorite event
667 """
668 # Retrieve info
669 target = e['target']
670 if target['screen_name'] != c['original_name']:
671 return
672 source = e['source']
673 target_object = e['target_object']
674 created_at = e['created_at']
675 # Format
676 source_user = cycle_color(source['name']) + \
677 color_func(c['NOTIFICATION']['source_nick'])(
678 ' @' + source['screen_name'])
679 notify = color_func(c['NOTIFICATION']['notify'])(
680 'unfavorited your tweet')
681 date = parser.parse(created_at)
682 date = arrow.get(date).to('local')
683 lang, encode = locale.getdefaultlocale()
684 clock = arrow.get(date).to('local').humanize(locale=lang)
685 clock = color_func(c['NOTIFICATION']['clock'])(clock)
686 meta = c['NOTIFY_FORMAT']
687 meta = source_user.join(meta.split('#source_user'))
688 meta = notify.join(meta.split('#notify'))
689 meta = clock.join(meta.split('#clock'))
690 # Output
691 printNicely('')
692 printNicely(meta)
693 draw(t=target_object, noti=True)
694
695
696 def notify_follow(e):
697 """
698 Notify a follow event
699 """
700 # Retrieve info
701 target = e['target']
702 if target['screen_name'] != c['original_name']:
703 return
704 source = e['source']
705 created_at = e['created_at']
706 # Format
707 source_user = cycle_color(source['name']) + \
708 color_func(c['NOTIFICATION']['source_nick'])(
709 ' @' + source['screen_name'])
710 notify = color_func(c['NOTIFICATION']['notify'])(
711 'followed you')
712 date = parser.parse(created_at)
713 date = arrow.get(date).to('local')
714 lang, encode = locale.getdefaultlocale()
715 clock = arrow.get(date).to('local').humanize(locale=lang)
716 clock = color_func(c['NOTIFICATION']['clock'])(clock)
717 meta = c['NOTIFY_FORMAT']
718 meta = source_user.join(meta.split('#source_user'))
719 meta = notify.join(meta.split('#notify'))
720 meta = clock.join(meta.split('#clock'))
721 # Output
722 printNicely('')
723 printNicely(meta)
724
725
726 def notify_list_member_added(e):
727 """
728 Notify a list_member_added event
729 """
730 # Retrieve info
731 target = e['target']
732 if target['screen_name'] != c['original_name']:
733 return
734 source = e['source']
735 target_object = [e['target_object']] # list of Twitter list
736 created_at = e['created_at']
737 # Format
738 source_user = cycle_color(source['name']) + \
739 color_func(c['NOTIFICATION']['source_nick'])(
740 ' @' + source['screen_name'])
741 notify = color_func(c['NOTIFICATION']['notify'])(
742 'added you to a list')
743 date = parser.parse(created_at)
744 date = arrow.get(date).to('local')
745 lang, encode = locale.getdefaultlocale()
746 clock = arrow.get(date).to('local').humanize(locale=lang)
747 clock = color_func(c['NOTIFICATION']['clock'])(clock)
748 meta = c['NOTIFY_FORMAT']
749 meta = source_user.join(meta.split('#source_user'))
750 meta = notify.join(meta.split('#notify'))
751 meta = clock.join(meta.split('#clock'))
752 # Output
753 printNicely('')
754 printNicely(meta)
755 print_list(target_object, noti=True)
756
757
758 def notify_list_member_removed(e):
759 """
760 Notify a list_member_removed event
761 """
762 # Retrieve info
763 target = e['target']
764 if target['screen_name'] != c['original_name']:
765 return
766 source = e['source']
767 target_object = [e['target_object']] # list of Twitter list
768 created_at = e['created_at']
769 # Format
770 source_user = cycle_color(source['name']) + \
771 color_func(c['NOTIFICATION']['source_nick'])(
772 ' @' + source['screen_name'])
773 notify = color_func(c['NOTIFICATION']['notify'])(
774 'removed you from a list')
775 date = parser.parse(created_at)
776 date = arrow.get(date).to('local')
777 lang, encode = locale.getdefaultlocale()
778 clock = arrow.get(date).to('local').humanize(locale=lang)
779 clock = color_func(c['NOTIFICATION']['clock'])(clock)
780 meta = c['NOTIFY_FORMAT']
781 meta = source_user.join(meta.split('#source_user'))
782 meta = notify.join(meta.split('#notify'))
783 meta = clock.join(meta.split('#clock'))
784 # Output
785 printNicely('')
786 printNicely(meta)
787 print_list(target_object, noti=True)
788
789
790 def notify_list_user_subscribed(e):
791 """
792 Notify a list_user_subscribed event
793 """
794 # Retrieve info
795 target = e['target']
796 if target['screen_name'] != c['original_name']:
797 return
798 source = e['source']
799 target_object = [e['target_object']] # list of Twitter list
800 created_at = e['created_at']
801 # Format
802 source_user = cycle_color(source['name']) + \
803 color_func(c['NOTIFICATION']['source_nick'])(
804 ' @' + source['screen_name'])
805 notify = color_func(c['NOTIFICATION']['notify'])(
806 'subscribed to your list')
807 date = parser.parse(created_at)
808 date = arrow.get(date).to('local')
809 lang, encode = locale.getdefaultlocale()
810 clock = arrow.get(date).to('local').humanize(locale=lang)
811 clock = color_func(c['NOTIFICATION']['clock'])(clock)
812 meta = c['NOTIFY_FORMAT']
813 meta = source_user.join(meta.split('#source_user'))
814 meta = notify.join(meta.split('#notify'))
815 meta = clock.join(meta.split('#clock'))
816 # Output
817 printNicely('')
818 printNicely(meta)
819 print_list(target_object, noti=True)
820
821
822 def notify_list_user_unsubscribed(e):
823 """
824 Notify a list_user_unsubscribed event
825 """
826 # Retrieve info
827 target = e['target']
828 if target['screen_name'] != c['original_name']:
829 return
830 source = e['source']
831 target_object = [e['target_object']] # list of Twitter list
832 created_at = e['created_at']
833 # Format
834 source_user = cycle_color(source['name']) + \
835 color_func(c['NOTIFICATION']['source_nick'])(
836 ' @' + source['screen_name'])
837 notify = color_func(c['NOTIFICATION']['notify'])(
838 'unsubscribed from your list')
839 date = parser.parse(created_at)
840 date = arrow.get(date).to('local')
841 lang, encode = locale.getdefaultlocale()
842 clock = arrow.get(date).to('local').humanize(locale=lang)
843 clock = color_func(c['NOTIFICATION']['clock'])(clock)
844 meta = c['NOTIFY_FORMAT']
845 meta = source_user.join(meta.split('#source_user'))
846 meta = notify.join(meta.split('#notify'))
847 meta = clock.join(meta.split('#clock'))
848 # Output
849 printNicely('')
850 printNicely(meta)
851 print_list(target_object, noti=True)
852
853
854 def nothing(e):
855 """
856 Do nothing for other event
857 """
858 return
859
860
861 def print_event(e):
862 """
863 Notify an event
864 """
865 event_dict = {
866 'retweet': notify_retweet,
867 'favorite': notify_favorite,
868 'unfavorite': notify_unfavorite,
869 'follow': notify_follow,
870 'list_member_added': notify_list_member_added,
871 'list_member_removed': notify_list_member_removed,
872 'list_user_subscribed': notify_list_user_subscribed,
873 'list_user_unsubscribed': notify_list_user_unsubscribed,
874 }
875 event_dict.get(e['event'], nothing)(e)
876
877
878 def show_profile(u):
879 """
880 Show a profile
881 """
882 # Retrieve info
883 name = u['name']
884 screen_name = u['screen_name']
885 description = u['description']
886 profile_image_url = u['profile_image_url']
887 location = u['location']
888 url = u['url']
889 created_at = u['created_at']
890 statuses_count = u['statuses_count']
891 friends_count = u['friends_count']
892 followers_count = u['followers_count']
893
894 # Create content
895 statuses_count = color_func(
896 c['PROFILE']['statuses_count'])(
897 str(statuses_count) +
898 ' tweets')
899 friends_count = color_func(
900 c['PROFILE']['friends_count'])(
901 str(friends_count) +
902 ' following')
903 followers_count = color_func(
904 c['PROFILE']['followers_count'])(
905 str(followers_count) +
906 ' followers')
907 count = statuses_count + ' ' + friends_count + ' ' + followers_count
908 user = cycle_color(
909 name) + color_func(c['PROFILE']['nick'])(' @' + screen_name + ' : ') + count
910 profile_image_raw_url = 'Profile photo: ' + \
911 color_func(c['PROFILE']['profile_image_url'])(profile_image_url)
912 description = ''.join(
913 lmap(lambda x: x + ' ' * 4 if x == '\n' else x, description))
914 description = color_func(c['PROFILE']['description'])(description)
915 location = 'Location : ' + color_func(c['PROFILE']['location'])(location)
916 url = 'URL : ' + (color_func(c['PROFILE']['url'])(url) if url else '')
917 date = parser.parse(created_at)
918 lang, encode = locale.getdefaultlocale()
919 clock = arrow.get(date).to('local').humanize(locale=lang)
920 clock = 'Join at ' + color_func(c['PROFILE']['clock'])(clock)
921
922 # Format
923 line1 = u"{u:>{uw}}".format(
924 u=user,
925 uw=len(user) + 2,
926 )
927 line2 = u"{p:>{pw}}".format(
928 p=profile_image_raw_url,
929 pw=len(profile_image_raw_url) + 4,
930 )
931 line3 = u"{d:>{dw}}".format(
932 d=description,
933 dw=len(description) + 4,
934 )
935 line4 = u"{l:>{lw}}".format(
936 l=location,
937 lw=len(location) + 4,
938 )
939 line5 = u"{u:>{uw}}".format(
940 u=url,
941 uw=len(url) + 4,
942 )
943 line6 = u"{c:>{cw}}".format(
944 c=clock,
945 cw=len(clock) + 4,
946 )
947
948 # Display
949 printNicely('')
950 printNicely(line1)
951 if c['IMAGE_ON_TERM']:
952 try:
953 response = requests.get(profile_image_url)
954 image_to_display(BytesIO(response.content))
955 except:
956 pass
957 else:
958 printNicely(line2)
959 for line in [line3, line4, line5, line6]:
960 printNicely(line)
961 printNicely('')
962
963
964 def print_trends(trends):
965 """
966 Display topics
967 """
968 for topic in trends[:c['TREND_MAX']]:
969 name = topic['name']
970 url = topic['url']
971 line = cycle_color(name) + ': ' + color_func(c['TREND']['url'])(url)
972 printNicely(line)
973 printNicely('')
974
975
976 def print_list(group, noti=False):
977 """
978 Display a list
979 """
980 for grp in group:
981 # Format
982 name = grp['full_name']
983 name = color_func(c['GROUP']['name'])(name + ' : ')
984 member = str(grp['member_count'])
985 member = color_func(c['GROUP']['member'])(member + ' member')
986 subscriber = str(grp['subscriber_count'])
987 subscriber = color_func(
988 c['GROUP']['subscriber'])(
989 subscriber +
990 ' subscriber')
991 description = grp['description'].strip()
992 description = color_func(c['GROUP']['description'])(description)
993 mode = grp['mode']
994 mode = color_func(c['GROUP']['mode'])('Type: ' + mode)
995 created_at = grp['created_at']
996 date = parser.parse(created_at)
997 lang, encode = locale.getdefaultlocale()
998 clock = arrow.get(date).to('local').humanize(locale=lang)
999 clock = 'Created at ' + color_func(c['GROUP']['clock'])(clock)
1000
1001 prefix = ' ' * 2
1002 # Add spaces in begining of line if this is inside a notification
1003 if noti:
1004 prefix = ' ' * 2 + prefix
1005 # Create lines
1006 line1 = prefix + name + member + ' ' + subscriber
1007 line2 = prefix + ' ' * 2 + description
1008 line3 = prefix + ' ' * 2 + mode
1009 line4 = prefix + ' ' * 2 + clock
1010
1011 # Display
1012 printNicely('')
1013 printNicely(line1)
1014 printNicely(line2)
1015 printNicely(line3)
1016 printNicely(line4)
1017
1018 if not noti:
1019 printNicely('')
1020
1021
1022 def show_calendar(month, date, rel):
1023 """
1024 Show the calendar in rainbow mode
1025 """
1026 month = random_rainbow(month)
1027 date = ' '.join([cycle_color(i) for i in date.split(' ')])
1028 today = str(int(os.popen('date +\'%d\'').read().strip()))
1029 # Display
1030 printNicely(month)
1031 printNicely(date)
1032 for line in rel:
1033 ary = line.split(' ')
1034 ary = lmap(
1035 lambda x: color_func(c['CAL']['today'])(x)
1036 if x == today
1037 else color_func(c['CAL']['days'])(x),
1038 ary)
1039 printNicely(' '.join(ary))
1040
1041
1042 def format_quote(tweet):
1043 """
1044 Quoting format
1045 """
1046 # Retrieve info
1047 screen_name = '@' + tweet['user']['screen_name']
1048 text = tweet['text']
1049 # Validate quote format
1050 if '#owner' not in c['QUOTE_FORMAT']:
1051 printNicely(light_magenta('Quote should contains #owner'))
1052 return False
1053 if '#comment' not in c['QUOTE_FORMAT']:
1054 printNicely(light_magenta('Quote format should have #comment'))
1055 return False
1056 # Build formater
1057 formater = ''
1058 try:
1059 formater = c['QUOTE_FORMAT']
1060 formater = screen_name.join(formater.split('#owner'))
1061 formater = text.join(formater.split('#tweet'))
1062 formater = emojize(formater)
1063 formater = u2str(formater)
1064 except:
1065 pass
1066 # Highlight like a tweet
1067 notice = formater.split()
1068 notice = lmap(
1069 lambda x: light_green(x)
1070 if x == '#comment'
1071 else x,
1072 notice)
1073 notice = lmap(
1074 lambda x: color_func(c['TWEET']['rt'])(x)
1075 if x == 'RT'
1076 else x,
1077 notice)
1078 notice = lmap(lambda x: cycle_color(x) if x[0] == '@' else x, notice)
1079 notice = lmap(
1080 lambda x: color_func(c['TWEET']['link'])(x)
1081 if x[0:4] == 'http'
1082 else x,
1083 notice)
1084 notice = lmap(
1085 lambda x: color_func(c['TWEET']['hashtag'])(x)
1086 if x.startswith('#')
1087 else x,
1088 notice)
1089 notice = ' '.join(notice)
1090 # Notice
1091 notice = light_magenta('Quoting: "') + notice + light_magenta('"')
1092 printNicely(notice)
1093 return formater
1094
1095
1096 # Start the color cycle
1097 start_cycle()