##// END OF EJS Templates
Refactored attachment viewers to store view htmls as constants
neko259 -
r1828:fb6d2612 default
parent child Browse files
Show More
@@ -1,231 +1,238 b''
1 1 import re
2 2
3 3 from PIL import Image
4 4
5 5 from django.contrib.staticfiles import finders
6 6 from django.contrib.staticfiles.templatetags.staticfiles import static
7 7 from django.core.files.images import get_image_dimensions
8 8 from django.template.defaultfilters import filesizeformat
9 9 from django.core.urlresolvers import reverse
10 10 from django.utils.translation import ugettext_lazy as _, ungettext_lazy
11 11
12 12 from boards.utils import get_domain, cached_result
13 13 from boards import settings
14 14
15 15
16 16 FILE_STUB_IMAGE = 'images/file.png'
17 17 FILE_STUB_URL = 'url'
18 18 FILE_FILEFORMAT = 'images/fileformats/{}.png'
19 19
20 20
21 21 FILE_TYPES_VIDEO = (
22 22 'webm',
23 23 'mp4',
24 24 'mpeg',
25 25 'ogv',
26 26 )
27 27 FILE_TYPE_SVG = 'svg'
28 28 FILE_TYPES_AUDIO = (
29 29 'ogg',
30 30 'mp3',
31 31 'opus',
32 32 )
33 33 FILE_TYPES_IMAGE = (
34 34 'jpeg',
35 35 'jpg',
36 36 'png',
37 37 'bmp',
38 38 'gif',
39 39 )
40 40
41 41 PLAIN_FILE_FORMATS = {
42 42 'zip': 'archive',
43 43 'tar': 'archive',
44 44 'gz': 'archive',
45 45 'mid' : 'midi',
46 46 }
47 47
48 48 URL_PROTOCOLS = {
49 49 'magnet': 'magnet',
50 50 }
51 51
52 52 CSS_CLASS_IMAGE = 'image'
53 53 CSS_CLASS_THUMB = 'thumb'
54 54
55 ABSTRACT_VIEW = '<div class="image">'\
56 '{}'\
57 '<div class="image-metadata"><a href="{}" download >{}, {}</a>'\
58 ' <a class="file-menu" href="#" data-type="{}" data-search-url="{}" data-filename="{}">πŸ” </a></div>'\
59 '</div>'
60 URL_VIEW = '<div class="image">' \
61 '{}' \
62 '<div class="image-metadata">{}</div>' \
63 '</div>'
64 ABSTRACT_FORMAT_VIEW = '<a href="{}">'\
65 '<img class="url-image" src="{}" width="{}" height="{}"/>'\
66 '</a>'
67 VIDEO_FORMAT_VIEW = '<video width="200" height="150" controls src="{}"></video>'
68 AUDIO_FORMAT_VIEW = '<audio controls src="{}"></audio>'
69 IMAGE_FORMAT_VIEW = '<a class="{}" href="{full}">' \
70 '<img class="post-image-preview"' \
71 ' src="{}"' \
72 ' alt="{}"' \
73 ' width="{}"' \
74 ' height="{}"' \
75 ' data-width="{}"' \
76 ' data-height="{}" />' \
77 '</a>'
78 SVG_FORMAT_VIEW = '<a class="thumb" href="{}">'\
79 '<img class="post-image-preview" width="200" height="150" src="{}" />'\
80 '</a>'
81 URL_FORMAT_VIEW = '<a href="{}">' \
82 '<img class="url-image" src="{}" width="{}" height="{}"/>' \
83 '</a>'
84
55 85
56 86 def get_viewers():
57 87 return AbstractViewer.__subclasses__()
58 88
59 89
60 90 def get_static_dimensions(filename):
61 91 file_path = finders.find(filename)
62 92 return get_image_dimensions(file_path)
63 93
64 94
65 95 # TODO Move this to utils
66 96 def file_exists(filename):
67 97 return finders.find(filename) is not None
68 98
69 99
70 100 class AbstractViewer:
71 101 def __init__(self, file, file_type, hash, url):
72 102 self.file = file
73 103 self.file_type = file_type
74 104 self.hash = hash
75 105 self.url = url
76 106
77 107 @staticmethod
78 108 def supports(file_type):
79 109 return True
80 110
81 111 def get_view(self):
82 112 search_host = settings.get('External', 'ImageSearchHost')
83 113 if search_host:
84 114 if search_host.endswith('/'):
85 115 search_host = search_host[:-1]
86 116 search_url = search_host + self.file.url
87 117 else:
88 118 search_url = ''
89 119
90 return '<div class="image">'\
91 '{}'\
92 '<div class="image-metadata"><a href="{}" download >{}, {}</a>'\
93 ' <a class="file-menu" href="#" data-type="{}" data-search-url="{}" data-filename="{}">πŸ” </a></div>'\
94 '</div>'.format(self.get_format_view(), self.file.url,
95 self.file_type, filesizeformat(self.file.size),
96 self.file_type, search_url, self.file.name)
120 return ABSTRACT_VIEW.format(self.get_format_view(), self.file.url,
121 self.file_type, filesizeformat(self.file.size),
122 self.file_type, search_url, self.file.name)
97 123
98 124 def get_format_view(self):
99 125 image_name = PLAIN_FILE_FORMATS.get(self.file_type, self.file_type)
100 126 file_name = FILE_FILEFORMAT.format(image_name)
101 127
102 128 if file_exists(file_name):
103 129 image = file_name
104 130 else:
105 131 image = FILE_STUB_IMAGE
106 132
107 133 w, h = get_static_dimensions(image)
108 134
109 return '<a href="{}">'\
110 '<img class="url-image" src="{}" width="{}" height="{}"/>'\
111 '</a>'.format(self.file.url, static(image), w, h)
135 return ABSTRACT_FORMAT_VIEW.format(self.file.url, static(image), w, h)
112 136
113 137
114 138 class VideoViewer(AbstractViewer):
115 139 @staticmethod
116 140 def supports(file_type):
117 141 return file_type in FILE_TYPES_VIDEO
118 142
119 143 def get_format_view(self):
120 return '<video width="200" height="150" controls src="{}"></video>'\
121 .format(self.file.url)
144 return VIDEO_FORMAT_VIEW.format(self.file.url)
122 145
123 146
124 147 class AudioViewer(AbstractViewer):
125 148 @staticmethod
126 149 def supports(file_type):
127 150 return file_type in FILE_TYPES_AUDIO
128 151
129 152 def get_format_view(self):
130 return '<audio controls src="{}"></audio>'.format(self.file.url)
153 return AUDIO_FORMAT_VIEW.format(self.file.url)
131 154
132 155
133 156 class SvgViewer(AbstractViewer):
134 157 @staticmethod
135 158 def supports(file_type):
136 159 return file_type == FILE_TYPE_SVG
137 160
138 161 def get_format_view(self):
139 return '<a class="thumb" href="{}">'\
140 '<img class="post-image-preview" width="200" height="150" src="{}" />'\
141 '</a>'.format(self.file.url, self.file.url)
162 return SVG_FORMAT_VIEW.format(self.file.url, self.file.url)
142 163
143 164
144 165 class ImageViewer(AbstractViewer):
145 166 @staticmethod
146 167 def supports(file_type):
147 168 return file_type in FILE_TYPES_IMAGE
148 169
149 170 def get_format_view(self):
150 171 metadata = '{}, {}'.format(self.file.name.split('.')[-1],
151 172 filesizeformat(self.file.size))
152 173
153 174 try:
154 175 width, height = get_image_dimensions(self.file.path)
155 176 except Exception:
156 177 # If the image is a decompression bomb, treat it as just a regular
157 178 # file
158 179 return super().get_format_view()
159 180
160 181 preview_path = self.file.path.replace('.', '.200x150.')
161 182 pre_width, pre_height = get_image_dimensions(preview_path)
162 183
163 184 split = self.file.url.rsplit('.', 1)
164 185 w, h = 200, 150
165 186 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
166 187
167 return '<a class="{}" href="{full}">' \
168 '<img class="post-image-preview"' \
169 ' src="{}"' \
170 ' alt="{}"' \
171 ' width="{}"' \
172 ' height="{}"' \
173 ' data-width="{}"' \
174 ' data-height="{}" />' \
175 '</a>' \
176 .format(CSS_CLASS_THUMB,
177 thumb_url,
178 self.hash,
179 str(pre_width),
180 str(pre_height), str(width), str(height),
181 full=self.file.url, image_meta=metadata)
188 return IMAGE_FORMAT_VIEW.format(CSS_CLASS_THUMB,
189 thumb_url,
190 self.hash,
191 str(pre_width),
192 str(pre_height), str(width), str(height),
193 full=self.file.url, image_meta=metadata)
182 194
183 195
184 196 class UrlViewer(AbstractViewer):
185 197 @staticmethod
186 198 def supports(file_type):
187 199 return file_type is None
188 200
189 201 def get_view(self):
190 return '<div class="image">' \
191 '{}' \
192 '<div class="image-metadata">{}</div>' \
193 '</div>'.format(self.get_format_view(), get_domain(self.url))
202 return URL_VIEW.format(self.get_format_view(), get_domain(self.url))
194 203
195 204 def get_format_view(self):
196 205 protocol = self.url.split(':')[0]
197 206
198 207 domain = get_domain(self.url)
199 208
200 209 if protocol in URL_PROTOCOLS:
201 210 url_image_name = URL_PROTOCOLS.get(protocol)
202 211 elif domain:
203 212 url_image_name = self._find_image_for_domains(domain) or FILE_STUB_URL
204 213 else:
205 214 url_image_name = FILE_STUB_URL
206 215
207 216 image_path = 'images/{}.png'.format(url_image_name)
208 217 image = static(image_path)
209 218 w, h = get_static_dimensions(image_path)
210 219
211 return '<a href="{}">' \
212 '<img class="url-image" src="{}" width="{}" height="{}"/>' \
213 '</a>'.format(self.url, image, w, h)
220 return URL_FORMAT_VIEW.format(self.url, image, w, h)
214 221
215 222 @cached_result()
216 223 def _find_image_for_domains(self, domain):
217 224 """
218 225 Searches for the domain image for every domain level except top.
219 226 E.g. for l3.example.co.uk it will search for l3.example.co.uk, then
220 227 example.co.uk, then co.uk
221 228 """
222 229 levels = domain.split('.')
223 230 while len(levels) > 1:
224 231 domain = '.'.join(levels)
225 232
226 233 filename = 'images/domains/{}.png'.format(domain)
227 234 if file_exists(filename):
228 235 return 'domains/' + domain
229 236 else:
230 237 del levels[0]
231 238
General Comments 0
You need to be logged in to leave comments. Login now