##// END OF EJS Templates
Show url as a tooltip of attachment
neko259 -
r2090:cfe3a188 default
parent child Browse files
Show More
@@ -1,243 +1,243 b''
1 1 from django.contrib.staticfiles import finders
2 2 from django.contrib.staticfiles.templatetags.staticfiles import static
3 3 from django.core.files.images import get_image_dimensions
4 4 from django.template.defaultfilters import filesizeformat
5 5
6 6 from boards import settings
7 7 from boards.abstracts.constants import THUMB_SIZES
8 8 from boards.settings import SECTION_EXTERNAL
9 9 from boards.utils import get_domain, cached_result, get_extension
10 10
11 11 URL_IMAGE_PATH = 'images/{}.png'
12 12
13 13 PROTOCOL_DELIMITER = ':'
14 14 DOMAIN_DELIMITER = '.'
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
56 56 ABSTRACT_VIEW = '<div class="image">'\
57 57 '{}'\
58 58 '<div class="image-metadata"><a href="{}" download >{}, {}</a>'\
59 59 ' <a class="file-menu" href="#" data-type="{}" data-search-url="{}" data-filename="{}" data-id="{}">&#8942; </a></div>'\
60 60 '</div>'
61 61 URL_VIEW = '<div class="image">' \
62 62 '{}' \
63 63 '<div class="image-metadata">{}</div>' \
64 64 '</div>'
65 65 ABSTRACT_FORMAT_VIEW = '<a href="{}">'\
66 66 '<img class="url-image" src="{}" width="{}" height="{}"/>'\
67 67 '</a>'
68 68 VIDEO_FORMAT_VIEW = '<video width="200" height="150" controls src="{}"></video>'
69 69 AUDIO_FORMAT_VIEW = '<audio controls src="{}"></audio>'
70 70 IMAGE_FORMAT_VIEW = '<a class="thumb" href="{full}">' \
71 71 '<img class="post-image-preview"' \
72 72 ' src="{}"' \
73 73 ' alt="{}"' \
74 74 ' width="{}"' \
75 75 ' height="{}"' \
76 76 ' data-width="{}"' \
77 77 ' data-height="{}" />' \
78 78 '</a>'
79 79 SVG_FORMAT_VIEW = '<a class="thumb" href="{}">'\
80 80 '<img class="post-image-preview" width="200" height="150" src="{}" />'\
81 81 '</a>'
82 82 URL_FORMAT_VIEW = '<a href="{}">' \
83 '<img class="url-image" src="{}" width="{}" height="{}"/>' \
83 '<img class="url-image" src="{}" width="{}" height="{}" title="{}" />' \
84 84 '</a>'
85 85
86 86
87 87 def get_viewers():
88 88 return AbstractViewer.__subclasses__()
89 89
90 90
91 91 class AbstractViewer:
92 92 def __init__(self, file, file_type, id, url):
93 93 self.file = file
94 94 self.file_type = file_type
95 95 self.id = id
96 96 self.url = url
97 97 self.extension = get_extension(self.file.name).lower()
98 98
99 99 @staticmethod
100 100 def supports(file_type):
101 101 return True
102 102
103 103 def get_view(self):
104 104 return ABSTRACT_VIEW.format(self.get_format_view(), self.file.url,
105 105 self.file_type, filesizeformat(self.file.size),
106 106 self.file_type, self._get_search_url(), self.file.name, self.id)
107 107
108 108 def _get_search_url(self):
109 109 search_host = settings.get(SECTION_EXTERNAL, 'ImageSearchHost')
110 110 if search_host:
111 111 if search_host.endswith('/'):
112 112 search_host = search_host[:-1]
113 113 search_url = search_host + self.file.url
114 114 else:
115 115 search_url = ''
116 116 return search_url
117 117
118 118 def get_format_view(self):
119 119 image_name = PLAIN_FILE_FORMATS.get(self.extension, self.extension)
120 120 file_name = FILE_FILEFORMAT.format(image_name)
121 121
122 122 if self.file_exists(file_name):
123 123 image = file_name
124 124 else:
125 125 image = FILE_STUB_IMAGE
126 126
127 127 w, h = self.get_static_dimensions(image)
128 128
129 129 return ABSTRACT_FORMAT_VIEW.format(self.file.url, static(image), w, h)
130 130
131 131 @cached_result()
132 132 def get_static_dimensions(self, filename):
133 133 file_path = finders.find(filename)
134 134 return get_image_dimensions(file_path)
135 135
136 136 @cached_result()
137 137 def file_exists(self, filename):
138 138 return finders.find(filename) is not None
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 try:
175 175 width, height = get_image_dimensions(self.file.path)
176 176 except Exception:
177 177 # If the image is a decompression bomb, treat it as just a regular
178 178 # file
179 179 return super().get_format_view()
180 180
181 181 preview_path = self.file.path.replace('.', '.200x150.')
182 182 try:
183 183 pre_width, pre_height = get_image_dimensions(preview_path)
184 184 except Exception:
185 185 return super().get_format_view()
186 186
187 187 split = self.file.url.rsplit('.', 1)
188 188 w, h = THUMB_SIZES[0]
189 189 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
190 190
191 191 return IMAGE_FORMAT_VIEW.format(
192 192 thumb_url,
193 193 self.id,
194 194 pre_width, pre_height, width, height,
195 195 full=self.file.url)
196 196
197 197
198 198 class UrlViewer(AbstractViewer):
199 199 @staticmethod
200 200 def supports(file_type):
201 201 return file_type is None
202 202
203 203 def get_view(self):
204 204 return URL_VIEW.format(self.get_format_view(), get_domain(self.url))
205 205
206 206 def get_format_view(self):
207 207 protocol = self.url.split(PROTOCOL_DELIMITER)[0]
208 208
209 209 domain = get_domain(self.url)
210 210
211 211 image_path = URL_IMAGE_PATH.format(self._get_image_name(protocol, domain))
212 212 image = static(image_path)
213 213 w, h = self.get_static_dimensions(image_path)
214 214
215 return URL_FORMAT_VIEW.format(self.url, image, w, h)
215 return URL_FORMAT_VIEW.format(self.url, image, w, h, self.url)
216 216
217 217 def _find_image_for_domains(self, domain):
218 218 """
219 219 Searches for the domain image for every domain level except top.
220 220 E.g. for l3.example.co.uk it will search for l3.example.co.uk, then
221 221 example.co.uk, then co.uk
222 222 """
223 223 levels = domain.split(DOMAIN_DELIMITER)
224 224 while len(levels) > 1:
225 225 domain = DOMAIN_DELIMITER.join(levels)
226 226
227 227 filename = 'images/domains/{}.png'.format(domain)
228 228 if self.file_exists(filename):
229 229 return 'domains/' + domain
230 230 else:
231 231 del levels[0]
232 232
233 233 @cached_result()
234 234 def _get_image_name(self, protocol, domain):
235 235 if protocol in URL_PROTOCOLS:
236 236 url_image_name = URL_PROTOCOLS.get(protocol)
237 237 elif domain:
238 238 url_image_name = self._find_image_for_domains(domain) or FILE_STUB_URL
239 239 else:
240 240 url_image_name = FILE_STUB_URL
241 241
242 242 return url_image_name
243 243
General Comments 0
You need to be logged in to leave comments. Login now