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