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