comparison pics2/pics_app.py @ 54:496714f2fd8c

first live version of pics2
author paulo
date Mon, 03 Jun 2013 00:30:24 -0700
parents 0482bffd7d7f
children 0249782e231e
comparison
equal deleted inserted replaced
1:6a94c3b87174 2:33cc05f1f73b
1 import os 1 import os
2 import re 2 import re
3 import glob 3 import glob
4 import traceback 4 import traceback
5 import datetime
6 import random
7 import urlparse
5 8
6 import html 9 import html
7 10
8 import logging 11 import logging
9 logging.basicConfig( 12 logging.basicConfig(
12 format="%(asctime)s %(levelname)-8s %(message)s", 15 format="%(asctime)s %(levelname)-8s %(message)s",
13 ) 16 )
14 17
15 18
16 19
17 def _get_pics_url(environ, dirpath): 20 def _is_pics_dir(dirpath):
18 script_name = environ.get("SCRIPT_NAME", '') 21 return os.path.exists(os.path.join(dirpath, "_picsroot"))
19 return os.path.normpath(os.path.join(os.path.dirname(script_name), dirpath)) 22
20 23
21 24 def _get_dir_dt(dirpath):
22 def _get_app_url(environ, dirpath): 25 if _is_pics_dir(dirpath):
23 script_name = environ.get("SCRIPT_NAME", '') 26 dirpath = os.path.join(dirpath, "_picsroot")
24 return os.path.normpath(os.path.join(script_name, dirpath)) 27
28 return datetime.datetime.fromtimestamp(os.stat(dirpath).st_mtime)
29
30
31 def _format_dt(dt):
32 return dt.strftime("%Y-%m-%d")
25 33
26 34
27 def _parse_path_info(path_info): 35 def _parse_path_info(path_info):
28 ppi = path_info.split(os.sep) 36 ppi = path_info.split(os.sep)
29 if len(ppi) > 1 and ppi[-1] == '': 37 if len(ppi) > 1 and ppi[-1] == '':
30 del ppi[-1] 38 del ppi[-1]
31 39
32 return ppi 40 return ppi
33 41
34 42
35 def _get_standard_html_doc(title):
36 root = html.HTML("html")
37
38 header = root.header
39 header.title(title)
40
41 body = root.body
42 body.h1(title)
43
44 return (root, header, body)
45
46
47 def _numeric_pad_basename(path, maxdigits=20): 43 def _numeric_pad_basename(path, maxdigits=20):
48 return os.path.basename(path).zfill(maxdigits) 44 return os.path.basename(path).zfill(maxdigits)
49 45
50 46
51 def _get_images(d): 47 def _get_images(d):
55 51
56 browse_fns = [os.path.join(d, "browse", os.path.basename(i)) for i in thumb_fns] 52 browse_fns = [os.path.join(d, "browse", os.path.basename(i)) for i in thumb_fns]
57 logging.debug("browse_fns = %s" % browse_fns) 53 logging.debug("browse_fns = %s" % browse_fns)
58 54
59 return zip(thumb_fns, browse_fns) 55 return zip(thumb_fns, browse_fns)
60 56
61 57
62 def _go_thumbnail_links_to_browse_imgs_html_body(environ, body, t, b): 58 class Main:
63 thumb_img_url = _get_pics_url(environ, t) 59 def _get_pics_url(self, dirpath):
64 browse_url = _get_app_url(environ, b) 60 script_name = self._environ.get("SCRIPT_NAME", '')
65 body.a(href=browse_url).img(src=thumb_img_url) 61 return os.path.normpath(os.path.join(os.path.dirname(script_name), dirpath))
66 62
67 63
68 def main(environ): 64 def _get_app_url(self, dirpath):
69 page_func = None 65 script_name = self._environ.get("SCRIPT_NAME", '')
70 66 return os.path.normpath(os.path.join(script_name, dirpath))
71 logging.debug("environ['PATH_INFO'] = %s" % environ["PATH_INFO"]) 67
72 logging.debug("environ['SCRIPT_NAME'] = %s" % environ["SCRIPT_NAME"]) 68
73 69 def _get_standard_html_doc(self, title):
74 pi = environ["PATH_INFO"] 70 root = html.HTML("html")
75 ppi = _parse_path_info(pi) 71
76 logging.debug("ppi = %s" % ppi) 72 header = root.header
77 73 header.link(rel="stylesheet", type="text/css", href=self._get_pics_url("index.css"))
78 if len(ppi) < 1 or ppi[0] != '': 74 header.title(title)
79 raise AssertionError("Parsed path length must start empty: " + pi) 75
80 76 body = root.body
81 if len(ppi) >= 2 and os.path.exists(os.path.join(ppi[1], "_picsroot")): 77 body.h1(title)
82 if len(ppi) == 2: 78
83 page_func = page_thumbs 79 return (root, header, body)
84 elif len(ppi) >= 4 and ppi[2] == "browse" and os.path.exists(os.path.join(*ppi)): 80
85 page_func = page_browse 81
86 elif len(ppi) == 1: 82 def _go_thumbnail_links_to_browse_imgs_html_body(self, body, t, b, selclass=None):
87 page_func = page_index 83 thumb_img_url = self._get_pics_url(t)
88 84 browse_url = self._get_app_url(b)
89 if page_func is None: 85
90 raise RuntimeError("Cannot find path: " + pi) 86 a = body.a(href=browse_url)
91 87
92 return unicode(page_func(environ)).encode("utf-8") 88 if selclass is not None:
93 89 a.img(src=thumb_img_url, klass=selclass)
94 90 else:
95 def page_index(environ): 91 a.img(src=thumb_img_url)
96 (html_root, html_header, html_body) = _get_standard_html_doc("pics index") 92
97 93 body.text(' ')
98 return html_root 94
99 95
100 96 def __init__(self, environ):
101 def page_thumbs(environ): 97 self._environ = environ
102 ppi = _parse_path_info(environ["PATH_INFO"]) 98 self._page_func = None
103 d = os.path.join(*ppi) 99
104 (html_root, html_header, html_body) = _get_standard_html_doc(d) 100 #logging.debug("environ = %s" % (sorted(self._environ.items(), key=lambda x: x[0]),))
105 101 logging.debug("environ['PATH_INFO'] = %s" % self._environ["PATH_INFO"])
106 html_p = html_body.p 102 logging.debug("environ['SCRIPT_NAME'] = %s" % self._environ["SCRIPT_NAME"])
107 for (t, b) in _get_images(d): 103 logging.debug("environ['QUERY_STRING'] = %s" % self._environ["QUERY_STRING"])
108 _go_thumbnail_links_to_browse_imgs_html_body(environ, html_p, t, b) 104
109 105 pi = self._environ["PATH_INFO"]
110 return html_root 106 ppi = _parse_path_info(pi)
111 107 logging.debug("ppi = %s" % ppi)
112 108
113 def page_browse(environ): 109 if len(ppi) < 1 or ppi[0] != '':
114 ppi = _parse_path_info(environ["PATH_INFO"]) 110 raise AssertionError("Parsed path length must start empty: " + pi)
115 d = os.path.join(*ppi[:2]) 111
116 imgs = _get_images(d) 112 if len(ppi) >= 2 and _is_pics_dir(ppi[1]):
117 img = os.path.join(*ppi) 113 if len(ppi) == 2:
118 114 self._page_func = self.page_thumbs
119 # thumbnail preview ribbon 115 elif len(ppi) >= 4 and ppi[2] == "browse" and os.path.exists(os.path.join(*ppi)):
120 w = 7 # must be odd 116 self._page_func = self.page_browse
121 v = w/2 117 elif len(ppi) == 1:
122 imgs_circ = [None] * w 118 self._page_func = self.page_index
123 x = None 119
124 n = len(imgs) 120 if self._page_func is None:
125 for (i, (t, b)) in enumerate(imgs): 121 raise RuntimeError("Cannot find path: " + pi)
126 if b == img: 122
127 x = i + 1 123
128 imgs_circ[v] = (t, b) 124 def page(self):
129 for j in range(1, v + 1): 125 return unicode(self._page_func()).encode("utf-8")
130 if (i + j) < n: imgs_circ[v + j] = imgs[i + j] 126
131 if (i - j) >= 0: imgs_circ[v - j] = imgs[i - j] 127
132 128 def page_index(self):
133 break 129 n = 5 # number of thumbnails to display
134 130
135 if x is None: 131 (html_root, html_header, html_body) = self._get_standard_html_doc("Pictures")
136 raise AssertionError 132
137 133 pics_dirs = []
138 (html_root, html_header, html_body) = _get_standard_html_doc(u"%s \u2014 %s of %s" % (d, x, len(imgs))) 134 for i in os.listdir('.'):
139 135 if _is_pics_dir(i):
140 browse_img_url = _get_pics_url(environ, img) 136 pics_dirs.append((i, _get_dir_dt(i)))
141 html_body.p.img(src=browse_img_url) 137
142 138 pics_dirs.sort(key=lambda x: x[1], reverse=True)
143 logging.debug("imgs_circ = %s" % imgs_circ) 139
144 140 for (d, dt) in pics_dirs:
145 html_p_ribbon = html_body.p 141 html_body.h2.a(d, href=self._get_app_url(d))
146 for i in imgs_circ: 142 html_body.h3(_format_dt(dt))
147 if i is not None: 143
148 (t, b) = i 144 imgs = _get_images(d)
149 _go_thumbnail_links_to_browse_imgs_html_body(environ, html_p_ribbon, t, b) 145 imgs_idx = [(i, img) for (i, img) in enumerate(imgs)]
150 146
151 return html_root 147 sampled_imgs_idx = random.sample(imgs_idx, min(len(imgs_idx), n))
148 sampled_imgs_idx.sort(key=lambda x: x[0])
149
150 html_p = html_body.p
151 for (i, (t, b)) in sampled_imgs_idx:
152 self._go_thumbnail_links_to_browse_imgs_html_body(html_p, t, b)
153
154 return html_root
155
156
157 def page_thumbs(self):
158 ppi = _parse_path_info(self._environ["PATH_INFO"])
159 d = os.path.join(*ppi)
160 (html_root, html_header, html_body) = self._get_standard_html_doc(d)
161
162 qs = urlparse.parse_qs(self._environ["QUERY_STRING"])
163 from_img = None
164 if "from" in qs:
165 from_img = qs["from"][0]
166
167 html_p = html_body.p
168 for (t, b) in _get_images(d):
169 if from_img is not None and b == from_img:
170 self._go_thumbnail_links_to_browse_imgs_html_body(html_p, t, b, "sel2")
171 else:
172 self._go_thumbnail_links_to_browse_imgs_html_body(html_p, t, b)
173
174 html_body.a("(Other pictures)", href=self._get_app_url(''))
175 return html_root
176
177
178 def page_browse(self):
179 ppi = _parse_path_info(self._environ["PATH_INFO"])
180 d = os.path.join(*ppi[:2])
181 imgs = _get_images(d)
182 img = os.path.join(*ppi)
183
184 # thumbnail preview ribbon
185 w = 7 # must be odd
186 v = w/2
187 imgs_circ = [None] * w
188 x = None
189 n = len(imgs)
190 for (i, (t, b)) in enumerate(imgs):
191 if b == img:
192 x = i + 1
193 imgs_circ[v] = (t, b)
194 for j in range(1, v + 1):
195 if (i + j) < n: imgs_circ[v + j] = imgs[i + j]
196 if (i - j) >= 0: imgs_circ[v - j] = imgs[i - j]
197
198 break
199
200 if x is None:
201 raise AssertionError
202
203 (html_root, html_header, html_body) = self._get_standard_html_doc(u"%s \u2014 %s of %s" % (d, x, len(imgs)))
204
205 browse_img_url = self._get_pics_url(img)
206 html_body.p.img(src=browse_img_url)
207
208 logging.debug("imgs_circ = %s" % imgs_circ)
209
210 html_p = html_body.p
211 for i in imgs_circ:
212 if i is not None:
213 (t, b) = i
214 if b == img:
215 self._go_thumbnail_links_to_browse_imgs_html_body(html_p, t, d + "?from=" + img, "sel")
216 else:
217 self._go_thumbnail_links_to_browse_imgs_html_body(html_p, t, b)
218
219 return html_root
152 220
153 221
154 def app(environ, start_response): 222 def app(environ, start_response):
155 response_code = "500 Internal Server Error" 223 response_code = "500 Internal Server Error"
156 response_type = "text/plain; charset=UTF-8" 224 response_type = "text/plain; charset=UTF-8"
157 225
158 try: 226 try:
159 response_body = main(environ) 227 response_body = Main(environ).page()
160 response_code = "200 OK" 228 response_code = "200 OK"
161 response_type = "text/html; charset=UTF-8" 229 response_type = "text/html; charset=UTF-8"
162 except: 230 except:
163 response_body = traceback.format_exc() 231 response_body = traceback.format_exc()
164 232