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