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