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