fe13d172a5f6feef7f75d605e73574be7d82356f
9 from twitter
.util
import printNicely
10 from functools
import wraps
11 from pyfiglet
import figlet_format
12 from dateutil
import parser
13 from .c_image
import *
16 from .py3patch
import *
18 # Draw global variables
26 colors_shuffle
= [globals()[i
.encode('utf8')]
27 if not str(i
).isdigit()
28 else term_color(int(i
))
29 for i
in c
['CYCLE_COLOR']]
30 return itertools
.cycle(colors_shuffle
)
37 dg
['cyc'] = init_cycle()
43 Print a string with ordered color with each character
45 colors_shuffle
= [globals()[i
.encode('utf8')]
46 if not str(i
).isdigit()
47 else term_color(int(i
))
48 for i
in c
['CYCLE_COLOR']]
49 colored
= [colors_shuffle
[i
% 7](s
[i
]) for i
in xrange(len(s
))]
50 return ''.join(colored
)
53 def random_rainbow(s
):
55 Print a string with random color with each character
57 colors_shuffle
= [globals()[i
.encode('utf8')]
58 if not str(i
).isdigit()
59 else term_color(int(i
))
60 for i
in c
['CYCLE_COLOR']]
61 colored
= [random
.choice(colors_shuffle
)(i
) for i
in s
]
62 return ''.join(colored
)
71 if args
not in dg
['cache']:
72 dg
['cache'][args
] = func(*args
)
73 return dg
['cache'][args
]
80 Cycle the colors_shuffle
82 return next(dg
['cyc'])(s
)
89 fi
= figlet_format(text
, font
='doom')
91 [next(dg
['cyc'])(i
) for i
in fi
.split('\n')]
97 Check if config is changed
100 data
= get_all_config()
103 if data
[key
] != c
[key
]:
109 def validate_theme(theme
):
111 Validate a theme exists or not
113 # Theme changed check
114 files
= os
.listdir(os
.path
.dirname(__file__
) + '/colorset')
115 themes
= [f
.split('.')[0] for f
in files
if f
.split('.')[-1] == 'json']
116 return theme
in themes
119 def reload_theme(value
, prev
):
121 Check current theme and update if necessary
124 config
= os
.path
.dirname(
125 __file__
) + '/colorset/' + value
+ '.json'
127 data
= load_config(config
)
131 # Restart color cycle and update config
133 set_config('THEME', value
)
138 def color_func(func_name
):
140 Call color function base on name
142 if str(func_name
).isdigit():
143 return term_color(int(func_name
))
144 return globals()[func_name
]
147 def draw(t
, keyword
=None, humanize
=True, fil
=[], ig
=[]):
157 screen_name
= t
['user']['screen_name']
158 name
= t
['user']['name']
159 created_at
= t
['created_at']
160 favorited
= t
['favorited']
161 retweet_count
= t
['retweet_count']
162 favorite_count
= t
['favorite_count']
163 date
= parser
.parse(created_at
)
164 date
= arrow
.get(date
).to('local')
166 lang
, encode
= locale
.getdefaultlocale()
167 clock
= arrow
.get(date
).to('local').humanize(locale
=lang
)
170 clock_format
= c
['FORMAT']['TWEET']['CLOCK_FORMAT']
172 clock_format
= '%Y/%m/%d %H:%M:%S'
173 clock
= date
.datetime
.strftime(clock_format
)
175 # Pull extended retweet text
177 text
= 'RT @' + t
['retweeted_status']['user']['screen_name'] + ': ' +\
178 t
['retweeted_status']['text']
182 # Unescape HTML character
183 text
= unescape(text
)
189 urls
= t
['entities']['urls']
191 expanded_url
.append(u
['expanded_url'])
200 media
= t
['entities']['media']
202 media_url
.append(m
['media_url'])
207 screen_name
= '@' + screen_name
208 fil
= list(set((fil
or []) + c
['ONLY_LIST']))
209 ig
= list(set((ig
or []) + c
['IGNORE_LIST']))
210 if fil
and screen_name
not in fil
:
212 if ig
and screen_name
in ig
:
216 if tid
not in c
['tweet_dict']:
217 c
['tweet_dict'].append(tid
)
218 rid
= len(c
['tweet_dict']) - 1
220 rid
= c
['tweet_dict'].index(tid
)
223 name
= cycle_color(name
)
224 nick
= color_func(c
['TWEET']['nick'])(screen_name
)
229 fav
= color_func(c
['TWEET']['favorited'])(u
'\u2605')
234 for index
in xrange(len(expanded_url
)):
236 lambda x
: expanded_url
[index
]
242 lambda x
: color_func(c
['TWEET']['rt'])(x
)
246 # Highlight screen_name
247 tweet
= lmap(lambda x
: cycle_color(x
) if x
[0] == '@' else x
, tweet
)
250 lambda x
: color_func(c
['TWEET']['link'])(x
)
256 lambda x
: color_func(c
['TWEET']['hashtag'])(x
)
261 tweet
= ' '.join(tweet
)
263 roj
= re
.search(keyword
, tweet
, re
.IGNORECASE
)
266 ary
= tweet
.split(occur
)
267 delimiter
= color_func(c
['TWEET']['keyword'])(occur
)
268 tweet
= delimiter
.join(ary
)
270 # Load config formater
273 formater
= c
['FORMAT']['TWEET']['DISPLAY']
274 formater
= name
.join(formater
.split('#name'))
275 formater
= nick
.join(formater
.split('#nick'))
276 formater
= fav
.join(formater
.split('#fav'))
277 formater
= tweet
.join(formater
.split('#tweet'))
279 word
= [wo
for wo
in formater
.split() if '#clock' in wo
][0]
280 delimiter
= color_func(c
['TWEET']['clock'])(
281 clock
.join(word
.split('#clock')))
282 formater
= delimiter
.join(formater
.split(word
))
284 word
= [wo
for wo
in formater
.split() if '#id' in wo
][0]
285 delimiter
= color_func(c
['TWEET']['id'])(id.join(word
.split('#id')))
286 formater
= delimiter
.join(formater
.split(word
))
287 # Change retweet count word
288 word
= [wo
for wo
in formater
.split() if '#rt_count' in wo
][0]
289 delimiter
= color_func(c
['TWEET']['retweet_count'])(
290 str(retweet_count
).join(word
.split('#rt_count')))
291 formater
= delimiter
.join(formater
.split(word
))
292 # Change favorites count word
293 word
= [wo
for wo
in formater
.split() if '#fa_count' in wo
][0]
294 delimiter
= color_func(c
['TWEET']['favorite_count'])(
295 str(favorite_count
).join(word
.split('#fa_count')))
296 formater
= delimiter
.join(formater
.split(word
))
301 printNicely(formater
)
304 if c
['IMAGE_ON_TERM'] and media_url
:
307 response
= requests
.get(mu
)
308 image_to_display(BytesIO(response
.content
))
310 printNicely(red('Sorry, image link is broken'))
313 def print_threads(d
):
315 Print threads of messages
320 messages
= d
[partner
]
321 count
= len(messages
)
322 screen_name
= '@' + partner
[0]
324 screen_name
= color_func(c
['MESSAGE']['partner'])(screen_name
)
325 name
= cycle_color(name
)
326 thread_id
= color_func(c
['MESSAGE']['id'])('thread_id:' + str(id))
327 line
= ' ' * 2 + name
+ ' ' + screen_name
+ \
328 ' (' + str(count
) + ' message) ' + thread_id
336 def print_thread(partner
, me_nick
, me_name
):
338 Print a thread of messages
340 # Sort messages by time
341 messages
= dg
['thread'][partner
]
342 messages
.sort(key
=lambda x
: parser
.parse(x
['created_at']))
343 # Use legacy display on non-ascii text message
344 text_ary
= [m
['text'] for m
in messages
]
345 not_ascii_text_ary
= [t
for t
in text_ary
if not is_ascii(t
)]
346 if not_ascii_text_ary
:
351 # Print the first line
352 dg
['frame_margin'] = margin
= 2
353 partner_nick
= partner
[0]
354 partner_name
= partner
[1]
355 left_size
= len(partner_nick
) + len(partner_name
) + 2
356 right_size
= len(me_nick
) + len(me_name
) + 2
357 partner_nick
= color_func(c
['MESSAGE']['partner'])('@' + partner_nick
)
358 partner_name
= cycle_color(partner_name
)
359 me_screen_name
= color_func(c
['MESSAGE']['me'])('@' + me_nick
)
360 me_name
= cycle_color(me_name
)
361 left
= ' ' * margin
+ partner_name
+ ' ' + partner_nick
362 right
= me_name
+ ' ' + me_screen_name
+ ' ' * margin
363 h
, w
= os
.popen('stty size', 'r').read().split()
365 line
= '{}{}{}'.format(
366 left
, ' ' * (w
- left_size
- right_size
- 2 * margin
), right
)
372 if m
['sender_screen_name'] == me_nick
:
373 print_right_message(m
)
374 elif m
['recipient_screen_name'] == me_nick
:
375 print_left_message(m
)
378 def print_right_message(m
):
380 Print a message on the right of screen
382 h
, w
= os
.popen('stty size', 'r').read().split()
384 frame_width
= w
// 3 - dg
['frame_margin']
385 step
= frame_width
- 2 * dg
['frame_margin']
386 slicing
= [m
['text'][i
:i
+ step
] for i
in range(0, len(m
['text']), step
)]
387 spaces
= w
- frame_width
- dg
['frame_margin']
388 dotline
= ' ' * spaces
+ '-' * frame_width
389 dotline
= color_func(c
['MESSAGE']['me_frame'])(dotline
)
393 fill
= step
- len(line
)
394 screen_line
= ' ' * spaces
+ '| ' + line
+ ' ' * fill
+ ' '
395 if slicing
[-1] == line
:
396 screen_line
= screen_line
+ ' >'
398 screen_line
= screen_line
+ '|'
399 screen_line
= color_func(c
['MESSAGE']['me_frame'])(screen_line
)
400 printNicely(screen_line
)
403 date
= parser
.parse(m
['created_at'])
404 date
= arrow
.get(date
).to('local').datetime
405 clock_format
= '%Y/%m/%d %H:%M:%S'
407 clock_format
= c
['FORMAT']['MESSAGE']['CLOCK_FORMAT']
410 clock
= date
.strftime(clock_format
)
412 if m
['id'] not in c
['message_dict']:
413 c
['message_dict'].append(m
['id'])
414 rid
= len(c
['message_dict']) - 1
416 rid
= c
['message_dict'].index(m
['id'])
421 virtual_meta
= formater
= c
['THREAD_META_RIGHT']
422 virtual_meta
= clock
.join(virtual_meta
.split('#clock'))
423 virtual_meta
= id.join(virtual_meta
.split('#id'))
425 word
= [wo
for wo
in formater
.split() if '#clock' in wo
][0]
426 delimiter
= color_func(c
['MESSAGE']['clock'])(
427 clock
.join(word
.split('#clock')))
428 formater
= delimiter
.join(formater
.split(word
))
430 word
= [wo
for wo
in formater
.split() if '#id' in wo
][0]
431 delimiter
= color_func(c
['MESSAGE']['id'])(id.join(word
.split('#id')))
432 formater
= delimiter
.join(formater
.split(word
))
434 printNicely(red('Wrong format in config.'))
437 line
= ' ' * (w
- len(virtual_meta
) - dg
['frame_margin']) + meta
441 def print_left_message(m
):
443 Print a message on the left of screen
445 h
, w
= os
.popen('stty size', 'r').read().split()
447 frame_width
= w
// 3 - dg
['frame_margin']
448 step
= frame_width
- 2 * dg
['frame_margin']
449 slicing
= [m
['text'][i
:i
+ step
] for i
in range(0, len(m
['text']), step
)]
450 spaces
= dg
['frame_margin']
451 dotline
= ' ' * spaces
+ '-' * frame_width
452 dotline
= color_func(c
['MESSAGE']['partner_frame'])(dotline
)
456 fill
= step
- len(line
)
457 screen_line
= ' ' + line
+ ' ' * fill
+ ' |'
458 if slicing
[-1] == line
:
459 screen_line
= ' ' * (spaces
- 1) + '< ' + screen_line
461 screen_line
= ' ' * spaces
+ '|' + screen_line
462 screen_line
= color_func(c
['MESSAGE']['partner_frame'])(screen_line
)
463 printNicely(screen_line
)
466 date
= parser
.parse(m
['created_at'])
467 date
= arrow
.get(date
).to('local').datetime
468 clock_format
= '%Y/%m/%d %H:%M:%S'
470 clock_format
= c
['FORMAT']['MESSAGE']['CLOCK_FORMAT']
473 clock
= date
.strftime(clock_format
)
475 if m
['id'] not in c
['message_dict']:
476 c
['message_dict'].append(m
['id'])
477 rid
= len(c
['message_dict']) - 1
479 rid
= c
['message_dict'].index(m
['id'])
484 virtual_meta
= formater
= c
['THREAD_META_LEFT']
485 virtual_meta
= clock
.join(virtual_meta
.split('#clock'))
486 virtual_meta
= id.join(virtual_meta
.split('#id'))
488 word
= [wo
for wo
in formater
.split() if '#clock' in wo
][0]
489 delimiter
= color_func(c
['MESSAGE']['clock'])(
490 clock
.join(word
.split('#clock')))
491 formater
= delimiter
.join(formater
.split(word
))
493 word
= [wo
for wo
in formater
.split() if '#id' in wo
][0]
494 delimiter
= color_func(c
['MESSAGE']['id'])(id.join(word
.split('#id')))
495 formater
= delimiter
.join(formater
.split(word
))
497 printNicely(red('Wrong format in config.'))
500 line
= ' ' * dg
['frame_margin'] + meta
504 def print_message(m
):
509 sender_screen_name
= '@' + m
['sender_screen_name']
510 sender_name
= m
['sender']['name']
511 text
= unescape(m
['text'])
512 recipient_screen_name
= '@' + m
['recipient_screen_name']
513 recipient_name
= m
['recipient']['name']
515 date
= parser
.parse(m
['created_at'])
516 date
= arrow
.get(date
).to('local').datetime
517 clock_format
= '%Y/%m/%d %H:%M:%S'
519 clock_format
= c
['FORMAT']['MESSAGE']['CLOCK_FORMAT']
522 clock
= date
.strftime(clock_format
)
525 if mid
not in c
['message_dict']:
526 c
['message_dict'].append(mid
)
527 rid
= len(c
['message_dict']) - 1
529 rid
= c
['message_dict'].index(mid
)
532 sender_name
= cycle_color(sender_name
)
533 sender_nick
= color_func(c
['MESSAGE']['sender'])(sender_screen_name
)
534 recipient_name
= cycle_color(recipient_name
)
535 recipient_nick
= color_func(
536 c
['MESSAGE']['recipient'])(recipient_screen_name
)
537 to
= color_func(c
['MESSAGE']['to'])('>>>')
541 text
= ''.join(lmap(lambda x
: x
+ ' ' if x
== '\n' else x
, text
))
543 # Load config formater
545 formater
= c
['FORMAT']['MESSAGE']['DISPLAY']
546 formater
= sender_name
.join(formater
.split("#sender_name"))
547 formater
= sender_nick
.join(formater
.split("#sender_nick"))
548 formater
= to
.join(formater
.split("#to"))
549 formater
= recipient_name
.join(formater
.split("#recipient_name"))
550 formater
= recipient_nick
.join(formater
.split("#recipient_nick"))
551 formater
= text
.join(formater
.split("#message"))
553 word
= [wo
for wo
in formater
.split() if '#clock' in wo
][0]
554 delimiter
= color_func(c
['MESSAGE']['clock'])(
555 clock
.join(word
.split('#clock')))
556 formater
= delimiter
.join(formater
.split(word
))
558 word
= [wo
for wo
in formater
.split() if '#id' in wo
][0]
559 delimiter
= color_func(c
['MESSAGE']['id'])(id.join(word
.split('#id')))
560 formater
= delimiter
.join(formater
.split(word
))
562 printNicely(red('Wrong format in config.'))
566 printNicely(formater
)
575 screen_name
= u
['screen_name']
576 description
= u
['description']
577 profile_image_url
= u
['profile_image_url']
578 location
= u
['location']
580 created_at
= u
['created_at']
581 statuses_count
= u
['statuses_count']
582 friends_count
= u
['friends_count']
583 followers_count
= u
['followers_count']
586 statuses_count
= color_func(
587 c
['PROFILE']['statuses_count'])(
588 str(statuses_count
) +
590 friends_count
= color_func(
591 c
['PROFILE']['friends_count'])(
594 followers_count
= color_func(
595 c
['PROFILE']['followers_count'])(
596 str(followers_count
) +
598 count
= statuses_count
+ ' ' + friends_count
+ ' ' + followers_count
600 name
) + color_func(c
['PROFILE']['nick'])(' @' + screen_name
+ ' : ') + count
601 profile_image_raw_url
= 'Profile photo: ' + \
602 color_func(c
['PROFILE']['profile_image_url'])(profile_image_url
)
603 description
= ''.join(
604 lmap(lambda x
: x
+ ' ' * 4 if x
== '\n' else x
, description
))
605 description
= color_func(c
['PROFILE']['description'])(description
)
606 location
= 'Location : ' + color_func(c
['PROFILE']['location'])(location
)
607 url
= 'URL : ' + (color_func(c
['PROFILE']['url'])(url
) if url
else '')
608 date
= parser
.parse(created_at
)
609 lang
, encode
= locale
.getdefaultlocale()
610 clock
= arrow
.get(date
).to('local').humanize(locale
=lang
)
611 clock
= 'Join at ' + color_func(c
['PROFILE']['clock'])(clock
)
614 line1
= u
"{u:>{uw}}".format(
618 line2
= u
"{p:>{pw}}".format(
619 p
=profile_image_raw_url
,
620 pw
=len(profile_image_raw_url
) + 4,
622 line3
= u
"{d:>{dw}}".format(
624 dw
=len(description
) + 4,
626 line4
= u
"{l:>{lw}}".format(
628 lw
=len(location
) + 4,
630 line5
= u
"{u:>{uw}}".format(
634 line6
= u
"{c:>{cw}}".format(
642 if c
['IMAGE_ON_TERM']:
644 response
= requests
.get(profile_image_url
)
645 image_to_display(BytesIO(response
.content
))
650 for line
in [line3
, line4
, line5
, line6
]:
655 def print_trends(trends
):
659 for topic
in trends
[:c
['TREND_MAX']]:
662 line
= cycle_color(name
) + ': ' + color_func(c
['TREND']['url'])(url
)
667 def print_list(group
):
673 name
= grp
['full_name']
674 name
= color_func(c
['GROUP']['name'])(name
+ ' : ')
675 member
= str(grp
['member_count'])
676 member
= color_func(c
['GROUP']['member'])(member
+ ' member')
677 subscriber
= str(grp
['subscriber_count'])
678 subscriber
= color_func(
679 c
['GROUP']['subscriber'])(
682 description
= grp
['description'].strip()
683 description
= color_func(c
['GROUP']['description'])(description
)
685 mode
= color_func(c
['GROUP']['mode'])('Type: ' + mode
)
686 created_at
= grp
['created_at']
687 date
= parser
.parse(created_at
)
688 lang
, encode
= locale
.getdefaultlocale()
689 clock
= arrow
.get(date
).to('local').humanize(locale
=lang
)
690 clock
= 'Created at ' + color_func(c
['GROUP']['clock'])(clock
)
693 line1
= ' ' * 2 + name
+ member
+ ' ' + subscriber
694 line2
= ' ' * 4 + description
695 line3
= ' ' * 4 + mode
696 line4
= ' ' * 4 + clock
708 def show_calendar(month
, date
, rel
):
710 Show the calendar in rainbow mode
712 month
= random_rainbow(month
)
713 date
= ' '.join([cycle_color(i
) for i
in date
.split(' ')])
714 today
= str(int(os
.popen('date +\'%d\'').read().strip()))
719 ary
= line
.split(' ')
721 lambda x
: color_func(c
['CAL']['today'])(x
)
723 else color_func(c
['CAL']['days'])(x
),
725 printNicely(' '.join(ary
))
728 def format_quote(tweet
):
733 screen_name
= '@' + tweet
['user']['screen_name']
735 # Validate quote format
736 if '#owner' not in c
['QUOTE_FORMAT']:
737 printNicely(light_magenta('Quote should contains #owner'))
739 if '#comment' not in c
['QUOTE_FORMAT']:
740 printNicely(light_magenta('Quote format should have #comment'))
745 formater
= c
['QUOTE_FORMAT']
746 formater
= screen_name
.join(formater
.split('#owner'))
747 formater
= text
.join(formater
.split('#tweet'))
748 formater
= u2str(formater
)
751 # Highlight like a tweet
752 notice
= formater
.split()
754 lambda x
: light_green(x
)
759 lambda x
: color_func(c
['TWEET']['rt'])(x
)
763 notice
= lmap(lambda x
: cycle_color(x
) if x
[0] == '@' else x
, notice
)
765 lambda x
: color_func(c
['TWEET']['link'])(x
)
770 lambda x
: color_func(c
['TWEET']['hashtag'])(x
)
774 notice
= ' '.join(notice
)
776 notice
= light_magenta('Quoting: "') + notice
+ light_magenta('"')
781 # Start the color cycle