c2119ff779e03cf0ca77631991ddccf81398f0f2
[rainbowstream.git] / rainbowstream / draw.py
1 import random
2 import itertools
3 import requests
4 import datetime
5 import time
6
7 from twitter.util import printNicely
8 from functools import wraps
9 from pyfiglet import figlet_format
10 from functools import reduce
11 from StringIO import StringIO
12 from dateutil import parser
13 from .c_image import *
14 from .colors import *
15 from .config import *
16 from .db import *
17
18
19 db = RainbowDB()
20
21 def init_cycle():
22 """
23 Init the cycle
24 """
25 colors_shuffle = [globals()[i.encode('utf8')]
26 if not i.startswith('RGB_')
27 else RGB(int(i[4:]))
28 for i in c['CYCLE_COLOR']]
29 return itertools.cycle(colors_shuffle)
30 cyc = init_cycle()
31
32 def order_rainbow(s):
33 """
34 Print a string with ordered color with each character
35 """
36 c = [colors_shuffle[i % 7](s[i]) for i in xrange(len(s))]
37 return reduce(lambda x, y: x + y, c)
38
39
40 def random_rainbow(s):
41 """
42 Print a string with random color with each character
43 """
44 c = [random.choice(colors_shuffle)(i) for i in s]
45 return reduce(lambda x, y: x + y, c)
46
47
48 def Memoize(func):
49 """
50 Memoize decorator
51 """
52 cache = {}
53
54 @wraps(func)
55 def wrapper(*args):
56 if args not in cache:
57 cache[args] = func(*args)
58 return cache[args]
59 return wrapper
60
61
62 @Memoize
63 def cycle_color(s):
64 """
65 Cycle the colors_shuffle
66 """
67 return next(cyc)(s)
68
69
70 def ascii_art(text):
71 """
72 Draw the Ascii Art
73 """
74 fi = figlet_format(text, font='doom')
75 print('\n'.join(
76 [next(cyc)(i) for i in fi.split('\n')]
77 ))
78
79
80 def check_theme():
81 """
82 Check current theme and update if necessary
83 """
84 exists = db.theme_query()
85 themes = [t.theme_name for t in exists]
86 if c['theme'] != themes[0]:
87 c['theme'] = themes[0]
88 # Determine path
89 if c['theme'] == 'custom':
90 config = os.environ.get(
91 'HOME',
92 os.environ.get('USERPROFILE',
93 '')) + os.sep + '.rainbow_config.json'
94 else:
95 config = 'rainbowstream/colorset/'+c['theme']+'.json'
96 # Load new config
97 data = load_config(config)
98 if data:
99 for d in data:
100 c[d] = data[d]
101 # Re-init color cycle
102 cyc = init_cycle()
103
104
105 def color_func(func_name):
106 """
107 Call color function base on name
108 """
109 pure = func_name.encode('utf8')
110 if pure.startswith('RGB_') and pure[4:].isdigit():
111 return RGB(int(pure[4:]))
112 return globals()[pure]
113
114
115 def draw(t, iot=False, keyword=None, fil=[], ig=[]):
116 """
117 Draw the rainbow
118 """
119
120 check_theme()
121 # Retrieve tweet
122 tid = t['id']
123 text = t['text']
124 screen_name = t['user']['screen_name']
125 name = t['user']['name']
126 created_at = t['created_at']
127 favorited = t['favorited']
128 date = parser.parse(created_at)
129 date = date - datetime.timedelta(seconds=time.timezone)
130 clock = date.strftime('%Y/%m/%d %H:%M:%S')
131
132 # Get expanded url
133 try:
134 expanded_url = []
135 url = []
136 urls = t['entities']['urls']
137 for u in urls:
138 expanded_url.append(u['expanded_url'])
139 url.append(u['url'])
140 except:
141 expanded_url = None
142 url = None
143
144 # Get media
145 try:
146 media_url = []
147 media = t['entities']['media']
148 for m in media:
149 media_url.append(m['media_url'])
150 except:
151 media_url = None
152
153 # Filter and ignore
154 screen_name = '@' + screen_name
155 if fil and screen_name not in fil:
156 return
157 if ig and screen_name in ig:
158 return
159
160 # Get rainbow id
161 res = db.tweet_to_rainbow_query(tid)
162 if not res:
163 db.tweet_store(tid)
164 res = db.tweet_to_rainbow_query(tid)
165 rid = res[0].rainbow_id
166
167 # Format info
168 user = cycle_color(
169 name) + color_func(c['TWEET']['nick'])(' ' + screen_name + ' ')
170 meta = color_func(c['TWEET']['clock'])(
171 '[' + clock + '] ') + color_func(c['TWEET']['id'])('[id=' + str(rid) + '] ')
172 if favorited:
173 meta = meta + color_func(c['TWEET']['favorite'])(u'\u2605')
174 tweet = text.split()
175 # Replace url
176 if expanded_url:
177 for index in range(len(expanded_url)):
178 tweet = map(
179 lambda x: expanded_url[index] if x == url[index] else x,
180 tweet)
181 # Highlight RT
182 tweet = map(
183 lambda x: color_func(
184 c['TWEET']['rt'])(x) if x == 'RT' else x,
185 tweet)
186 # Highlight screen_name
187 tweet = map(lambda x: cycle_color(x) if x[0] == '@' else x, tweet)
188 # Highlight link
189 tweet = map(
190 lambda x: color_func(
191 c['TWEET']['link'])(x) if x[
192 0:4] == 'http' else x,
193 tweet)
194 # Highlight search keyword
195 if keyword:
196 tweet = map(
197 lambda x: color_func(c['TWEET']['keyword'])(x) if
198 ''.join(c for c in x if c.isalnum()).lower() == keyword.lower()
199 else x,
200 tweet
201 )
202 # Recreate tweet
203 tweet = ' '.join(tweet)
204
205 # Draw rainbow
206 line1 = u"{u:>{uw}}:".format(
207 u=user,
208 uw=len(user) + 2,
209 )
210 line2 = u"{c:>{cw}}".format(
211 c=meta,
212 cw=len(meta) + 2,
213 )
214 line3 = ' ' + tweet
215
216 printNicely('')
217 printNicely(line1)
218 printNicely(line2)
219 printNicely(line3)
220
221 # Display Image
222 if iot and media_url:
223 for mu in media_url:
224 response = requests.get(mu)
225 image_to_display(StringIO(response.content))
226
227
228 def print_message(m):
229 """
230 Print direct message
231 """
232 sender_screen_name = '@' + m['sender_screen_name']
233 sender_name = m['sender']['name']
234 text = m['text']
235 recipient_screen_name = '@' + m['recipient_screen_name']
236 recipient_name = m['recipient']['name']
237 mid = m['id']
238 date = parser.parse(m['created_at'])
239 date = date - datetime.timedelta(seconds=time.timezone)
240 clock = date.strftime('%Y/%m/%d %H:%M:%S')
241
242 # Get rainbow id
243 res = db.message_to_rainbow_query(mid)
244 if not res:
245 db.message_store(mid)
246 res = db.message_to_rainbow_query(mid)
247 rid = res[0].rainbow_id
248
249 # Draw
250 sender = cycle_color(
251 sender_name) + color_func(c['MESSAGE']['sender'])(' ' + sender_screen_name + ' ')
252 recipient = cycle_color(recipient_name) + color_func(
253 c['MESSAGE']['recipient'])(
254 ' ' + recipient_screen_name + ' ')
255 user = sender + color_func(c['MESSAGE']['to'])(' >>> ') + recipient
256 meta = color_func(
257 c['MESSAGE']['clock'])(
258 '[' + clock + ']') + color_func(
259 c['MESSAGE']['id'])(
260 ' [message_id=' + str(rid) + '] ')
261 text = ''.join(map(lambda x: x + ' ' if x == '\n' else x, text))
262
263 line1 = u"{u:>{uw}}:".format(
264 u=user,
265 uw=len(user) + 2,
266 )
267 line2 = u"{c:>{cw}}".format(
268 c=meta,
269 cw=len(meta) + 2,
270 )
271
272 line3 = ' ' + text
273
274 printNicely('')
275 printNicely(line1)
276 printNicely(line2)
277 printNicely(line3)
278
279
280 def show_profile(u, iot=False):
281 """
282 Show a profile
283 """
284 # Retrieve info
285 name = u['name']
286 screen_name = u['screen_name']
287 description = u['description']
288 profile_image_url = u['profile_image_url']
289 location = u['location']
290 url = u['url']
291 created_at = u['created_at']
292 statuses_count = u['statuses_count']
293 friends_count = u['friends_count']
294 followers_count = u['followers_count']
295
296 # Create content
297 statuses_count = color_func(
298 c['PROFILE']['statuses_count'])(
299 str(statuses_count) +
300 ' tweets')
301 friends_count = color_func(
302 c['PROFILE']['friends_count'])(
303 str(friends_count) +
304 ' following')
305 followers_count = color_func(
306 c['PROFILE']['followers_count'])(
307 str(followers_count) +
308 ' followers')
309 count = statuses_count + ' ' + friends_count + ' ' + followers_count
310 user = cycle_color(
311 name) + color_func(c['PROFILE']['nick'])(' @' + screen_name + ' : ') + count
312 profile_image_raw_url = 'Profile photo: ' + \
313 color_func(c['PROFILE']['profile_image_url'])(profile_image_url)
314 description = ''.join(
315 map(lambda x: x + ' ' * 4 if x == '\n' else x, description))
316 description = color_func(c['PROFILE']['description'])(description)
317 location = 'Location : ' + color_func(c['PROFILE']['location'])(location)
318 url = 'URL : ' + (color_func(c['PROFILE']['url'])(url) if url else '')
319 date = parser.parse(created_at)
320 date = date - datetime.timedelta(seconds=time.timezone)
321 clock = date.strftime('%Y/%m/%d %H:%M:%S')
322 clock = 'Join at ' + color_func(c['PROFILE']['clock'])(clock)
323
324 # Format
325 line1 = u"{u:>{uw}}".format(
326 u=user,
327 uw=len(user) + 2,
328 )
329 line2 = u"{p:>{pw}}".format(
330 p=profile_image_raw_url,
331 pw=len(profile_image_raw_url) + 4,
332 )
333 line3 = u"{d:>{dw}}".format(
334 d=description,
335 dw=len(description) + 4,
336 )
337 line4 = u"{l:>{lw}}".format(
338 l=location,
339 lw=len(location) + 4,
340 )
341 line5 = u"{u:>{uw}}".format(
342 u=url,
343 uw=len(url) + 4,
344 )
345 line6 = u"{c:>{cw}}".format(
346 c=clock,
347 cw=len(clock) + 4,
348 )
349
350 # Display
351 printNicely('')
352 printNicely(line1)
353 if iot:
354 response = requests.get(profile_image_url)
355 image_to_display(StringIO(response.content), 2, 20)
356 else:
357 printNicely(line2)
358 for line in [line3, line4, line5, line6]:
359 printNicely(line)
360 printNicely('')
361
362
363 def print_trends(trends):
364 """
365 Display topics
366 """
367 for topic in trends[:c['TREND_MAX']]:
368 name = topic['name']
369 url = topic['url']
370 line = cycle_color(name) + ': ' + color_func(c['TREND']['url'])(url)
371 printNicely(line)
372 printNicely('')