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