##// END OF EJS Templates
Show attachment alias if it has one
neko259 -
r1912:6d13074b default
parent child Browse files
Show More
@@ -1,158 +1,159 b''
1 from itertools import zip_longest
1 from itertools import zip_longest
2
2
3 import boards
3 import boards
4 from boards.models import STATUS_ARCHIVE
4 from boards.models import STATUS_ARCHIVE
5 from django.core.files.images import get_image_dimensions
5 from django.core.files.images import get_image_dimensions
6 from django.db import models
6 from django.db import models
7
7
8 from boards import utils
8 from boards import utils
9 from boards.models.attachment.viewers import get_viewers, AbstractViewer, \
9 from boards.models.attachment.viewers import get_viewers, AbstractViewer, \
10 FILE_TYPES_IMAGE
10 FILE_TYPES_IMAGE
11 from boards.utils import get_upload_filename, get_extension, cached_result, \
11 from boards.utils import get_upload_filename, get_extension, cached_result, \
12 get_file_mimetype
12 get_file_mimetype
13
13
14
14
15 class AttachmentManager(models.Manager):
15 class AttachmentManager(models.Manager):
16 def create_with_hash(self, file):
16 def create_with_hash(self, file):
17 file_hash = utils.get_file_hash(file)
17 file_hash = utils.get_file_hash(file)
18 attachment = self.get_existing_duplicate(file_hash, file)
18 attachment = self.get_existing_duplicate(file_hash, file)
19 if not attachment:
19 if not attachment:
20 file_type = get_file_mimetype(file)
20 file_type = get_file_mimetype(file)
21 attachment = self.create(file=file, mimetype=file_type,
21 attachment = self.create(file=file, mimetype=file_type,
22 hash=file_hash)
22 hash=file_hash)
23
23
24 return attachment
24 return attachment
25
25
26 def create_from_url(self, url):
26 def create_from_url(self, url):
27 existing = self.filter(url=url)
27 existing = self.filter(url=url)
28 if len(existing) > 0:
28 if len(existing) > 0:
29 attachment = existing[0]
29 attachment = existing[0]
30 else:
30 else:
31 attachment = self.create(url=url)
31 attachment = self.create(url=url)
32 return attachment
32 return attachment
33
33
34 def get_random_images(self, count, tags=None):
34 def get_random_images(self, count, tags=None):
35 images = self.filter(mimetype__in=FILE_TYPES_IMAGE).exclude(
35 images = self.filter(mimetype__in=FILE_TYPES_IMAGE).exclude(
36 attachment_posts__thread__status=STATUS_ARCHIVE)
36 attachment_posts__thread__status=STATUS_ARCHIVE)
37 if tags is not None:
37 if tags is not None:
38 images = images.filter(attachment_posts__threads__tags__in=tags)
38 images = images.filter(attachment_posts__threads__tags__in=tags)
39 return images.order_by('?')[:count]
39 return images.order_by('?')[:count]
40
40
41 def get_existing_duplicate(self, file_hash, file):
41 def get_existing_duplicate(self, file_hash, file):
42 """
42 """
43 Gets an attachment with the same file if one exists.
43 Gets an attachment with the same file if one exists.
44 """
44 """
45 existing = self.filter(hash=file_hash)
45 existing = self.filter(hash=file_hash)
46 attachment = None
46 attachment = None
47 for existing_attachment in existing:
47 for existing_attachment in existing:
48 existing_file = existing_attachment.file
48 existing_file = existing_attachment.file
49
49
50 file_chunks = file.chunks()
50 file_chunks = file.chunks()
51 existing_file_chunks = existing_file.chunks()
51 existing_file_chunks = existing_file.chunks()
52
52
53 if self._compare_chunks(file_chunks, existing_file_chunks):
53 if self._compare_chunks(file_chunks, existing_file_chunks):
54 attachment = existing_attachment
54 attachment = existing_attachment
55 return attachment
55 return attachment
56
56
57 def _compare_chunks(self, chunks1, chunks2):
57 def _compare_chunks(self, chunks1, chunks2):
58 """
58 """
59 Compares 2 chunks of different sizes (e.g. first chunk array contains
59 Compares 2 chunks of different sizes (e.g. first chunk array contains
60 all data in 1 chunk, and other one -- in a multiple of smaller ones.
60 all data in 1 chunk, and other one -- in a multiple of smaller ones.
61 """
61 """
62 equal = True
62 equal = True
63
63
64 position1 = 0
64 position1 = 0
65 position2 = 0
65 position2 = 0
66 chunk1 = None
66 chunk1 = None
67 chunk2 = None
67 chunk2 = None
68 chunk1ended = False
68 chunk1ended = False
69 chunk2ended = False
69 chunk2ended = False
70 while True:
70 while True:
71 if not chunk1 or len(chunk1) <= position1:
71 if not chunk1 or len(chunk1) <= position1:
72 try:
72 try:
73 chunk1 = chunks1.__next__()
73 chunk1 = chunks1.__next__()
74 position1 = 0
74 position1 = 0
75 except StopIteration:
75 except StopIteration:
76 chunk1ended = True
76 chunk1ended = True
77 if not chunk2 or len(chunk2) <= position2:
77 if not chunk2 or len(chunk2) <= position2:
78 try:
78 try:
79 chunk2 = chunks2.__next__()
79 chunk2 = chunks2.__next__()
80 position2 = 0
80 position2 = 0
81 except StopIteration:
81 except StopIteration:
82 chunk2ended = True
82 chunk2ended = True
83
83
84 if chunk1ended and chunk2ended:
84 if chunk1ended and chunk2ended:
85 # Same size chunksm checked for equality previously
85 # Same size chunksm checked for equality previously
86 break
86 break
87 elif chunk1ended or chunk2ended:
87 elif chunk1ended or chunk2ended:
88 # Different size chunks, not equal
88 # Different size chunks, not equal
89 equal = False
89 equal = False
90 break
90 break
91 elif chunk1[position1] != chunk2[position2]:
91 elif chunk1[position1] != chunk2[position2]:
92 # Different bytes, not equal
92 # Different bytes, not equal
93 equal = False
93 equal = False
94 break
94 break
95 else:
95 else:
96 position1 += 1
96 position1 += 1
97 position2 += 1
97 position2 += 1
98 return equal
98 return equal
99
99
100
100
101 class Attachment(models.Model):
101 class Attachment(models.Model):
102 objects = AttachmentManager()
102 objects = AttachmentManager()
103
103
104 class Meta:
104 class Meta:
105 app_label = 'boards'
105 app_label = 'boards'
106 ordering = ('id',)
106 ordering = ('id',)
107
107
108 file = models.FileField(upload_to=get_upload_filename, null=True)
108 file = models.FileField(upload_to=get_upload_filename, null=True)
109 mimetype = models.CharField(max_length=200, null=True)
109 mimetype = models.CharField(max_length=200, null=True)
110 hash = models.CharField(max_length=36, null=True)
110 hash = models.CharField(max_length=36, null=True)
111 alias = models.TextField(unique=True, null=True)
111 alias = models.TextField(unique=True, null=True)
112 url = models.TextField(blank=True, default='')
112 url = models.TextField(blank=True, default='')
113
113
114 def get_view(self):
114 def get_view(self):
115 file_viewer = None
115 file_viewer = None
116 for viewer in get_viewers():
116 for viewer in get_viewers():
117 if viewer.supports(self.mimetype):
117 if viewer.supports(self.mimetype):
118 file_viewer = viewer
118 file_viewer = viewer
119 break
119 break
120 if file_viewer is None:
120 if file_viewer is None:
121 file_viewer = AbstractViewer
121 file_viewer = AbstractViewer
122
122
123 return file_viewer(self.file, self.mimetype, self.hash, self.url).get_view()
123 return file_viewer(self.file, self.mimetype, self.hash, self.url,
124 self.alias).get_view()
124
125
125 def __str__(self):
126 def __str__(self):
126 return self.url or self.file.url
127 return self.url or self.file.url
127
128
128 def get_random_associated_post(self):
129 def get_random_associated_post(self):
129 posts = boards.models.Post.objects.filter(attachments__in=[self])
130 posts = boards.models.Post.objects.filter(attachments__in=[self])
130 return posts.order_by('?').first()
131 return posts.order_by('?').first()
131
132
132 @cached_result()
133 @cached_result()
133 def get_size(self):
134 def get_size(self):
134 if self.file:
135 if self.file:
135 if self.mimetype in FILE_TYPES_IMAGE:
136 if self.mimetype in FILE_TYPES_IMAGE:
136 return get_image_dimensions(self.file)
137 return get_image_dimensions(self.file)
137 else:
138 else:
138 return 200, 150
139 return 200, 150
139
140
140 def get_thumb_url(self):
141 def get_thumb_url(self):
141 split = self.file.url.rsplit('.', 1)
142 split = self.file.url.rsplit('.', 1)
142 w, h = 200, 150
143 w, h = 200, 150
143 return '%s.%sx%s.%s' % (split[0], w, h, split[1])
144 return '%s.%sx%s.%s' % (split[0], w, h, split[1])
144
145
145 @cached_result()
146 @cached_result()
146 def get_preview_size(self):
147 def get_preview_size(self):
147 size = 200, 150
148 size = 200, 150
148 if self.mimetype in FILE_TYPES_IMAGE:
149 if self.mimetype in FILE_TYPES_IMAGE:
149 preview_path = self.file.path.replace('.', '.200x150.')
150 preview_path = self.file.path.replace('.', '.200x150.')
150 try:
151 try:
151 size = get_image_dimensions(preview_path)
152 size = get_image_dimensions(preview_path)
152 except Exception:
153 except Exception:
153 pass
154 pass
154
155
155 return size
156 return size
156
157
157 def is_internal(self):
158 def is_internal(self):
158 return self.url is None or len(self.url) == 0
159 return self.url is None or len(self.url) == 0
@@ -1,244 +1,247 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, get_extension
12 from boards.utils import get_domain, cached_result, get_extension
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+xml'
27 FILE_TYPE_SVG = 'image/svg+xml'
28 FILE_TYPES_AUDIO = (
28 FILE_TYPES_AUDIO = (
29 'audio/ogg',
29 'audio/ogg',
30 'audio/mpeg',
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 'zip': 'archive',
44 'zip': 'archive',
45 'tar': 'archive',
45 'tar': 'archive',
46 'gz': 'archive',
46 'gz': 'archive',
47 'mid' : 'midi',
47 'mid' : '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, alias):
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 self.extension = get_extension(self.file.name)
108 self.extension = get_extension(self.file.name)
109 self.alias = alias
109
110
110 @staticmethod
111 @staticmethod
111 def supports(file_type):
112 def supports(file_type):
112 return True
113 return True
113
114
114 def get_view(self):
115 def get_view(self):
115 search_host = settings.get('External', 'ImageSearchHost')
116 search_host = settings.get('External', 'ImageSearchHost')
116 if search_host:
117 if search_host:
117 if search_host.endswith('/'):
118 if search_host.endswith('/'):
118 search_host = search_host[:-1]
119 search_host = search_host[:-1]
119 search_url = search_host + self.file.url
120 search_url = search_host + self.file.url
120 else:
121 else:
121 search_url = ''
122 search_url = ''
122
123
123 return ABSTRACT_VIEW.format(self.get_format_view(), self.file.url,
124 alias = self.alias + '<br />' if self.alias else ''
125
126 return ABSTRACT_VIEW.format(self.get_format_view(), alias, self.file.url,
124 self.file_type, filesizeformat(self.file.size),
127 self.file_type, filesizeformat(self.file.size),
125 self.file_type, search_url, self.file.name)
128 self.file_type, search_url, self.file.name)
126
129
127 def get_format_view(self):
130 def get_format_view(self):
128 image_name = PLAIN_FILE_FORMATS.get(self.extension, self.extension)
131 image_name = PLAIN_FILE_FORMATS.get(self.extension, self.extension)
129 file_name = FILE_FILEFORMAT.format(image_name)
132 file_name = FILE_FILEFORMAT.format(image_name)
130
133
131 if file_exists(file_name):
134 if file_exists(file_name):
132 image = file_name
135 image = file_name
133 else:
136 else:
134 image = FILE_STUB_IMAGE
137 image = FILE_STUB_IMAGE
135
138
136 w, h = get_static_dimensions(image)
139 w, h = get_static_dimensions(image)
137
140
138 return ABSTRACT_FORMAT_VIEW.format(self.file.url, static(image), w, h)
141 return ABSTRACT_FORMAT_VIEW.format(self.file.url, static(image), w, h)
139
142
140
143
141 class VideoViewer(AbstractViewer):
144 class VideoViewer(AbstractViewer):
142 @staticmethod
145 @staticmethod
143 def supports(file_type):
146 def supports(file_type):
144 return file_type in FILE_TYPES_VIDEO
147 return file_type in FILE_TYPES_VIDEO
145
148
146 def get_format_view(self):
149 def get_format_view(self):
147 return VIDEO_FORMAT_VIEW.format(self.file.url)
150 return VIDEO_FORMAT_VIEW.format(self.file.url)
148
151
149
152
150 class AudioViewer(AbstractViewer):
153 class AudioViewer(AbstractViewer):
151 @staticmethod
154 @staticmethod
152 def supports(file_type):
155 def supports(file_type):
153 return file_type in FILE_TYPES_AUDIO
156 return file_type in FILE_TYPES_AUDIO
154
157
155 def get_format_view(self):
158 def get_format_view(self):
156 return AUDIO_FORMAT_VIEW.format(self.file.url)
159 return AUDIO_FORMAT_VIEW.format(self.file.url)
157
160
158
161
159 class SvgViewer(AbstractViewer):
162 class SvgViewer(AbstractViewer):
160 @staticmethod
163 @staticmethod
161 def supports(file_type):
164 def supports(file_type):
162 return file_type == FILE_TYPE_SVG
165 return file_type == FILE_TYPE_SVG
163
166
164 def get_format_view(self):
167 def get_format_view(self):
165 return SVG_FORMAT_VIEW.format(self.file.url, self.file.url)
168 return SVG_FORMAT_VIEW.format(self.file.url, self.file.url)
166
169
167
170
168 class ImageViewer(AbstractViewer):
171 class ImageViewer(AbstractViewer):
169 @staticmethod
172 @staticmethod
170 def supports(file_type):
173 def supports(file_type):
171 return file_type in FILE_TYPES_IMAGE
174 return file_type in FILE_TYPES_IMAGE
172
175
173 def get_format_view(self):
176 def get_format_view(self):
174 metadata = '{}, {}'.format(self.file.name.split('.')[-1],
177 metadata = '{}, {}'.format(self.file.name.split('.')[-1],
175 filesizeformat(self.file.size))
178 filesizeformat(self.file.size))
176
179
177 try:
180 try:
178 width, height = get_image_dimensions(self.file.path)
181 width, height = get_image_dimensions(self.file.path)
179 except Exception:
182 except Exception:
180 # If the image is a decompression bomb, treat it as just a regular
183 # If the image is a decompression bomb, treat it as just a regular
181 # file
184 # file
182 return super().get_format_view()
185 return super().get_format_view()
183
186
184 preview_path = self.file.path.replace('.', '.200x150.')
187 preview_path = self.file.path.replace('.', '.200x150.')
185 try:
188 try:
186 pre_width, pre_height = get_image_dimensions(preview_path)
189 pre_width, pre_height = get_image_dimensions(preview_path)
187 except Exception:
190 except Exception:
188 return super().get_format_view()
191 return super().get_format_view()
189
192
190 split = self.file.url.rsplit('.', 1)
193 split = self.file.url.rsplit('.', 1)
191 w, h = 200, 150
194 w, h = 200, 150
192 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
195 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
193
196
194 return IMAGE_FORMAT_VIEW.format(CSS_CLASS_THUMB,
197 return IMAGE_FORMAT_VIEW.format(CSS_CLASS_THUMB,
195 thumb_url,
198 thumb_url,
196 self.hash,
199 self.hash,
197 str(pre_width),
200 str(pre_width),
198 str(pre_height), str(width), str(height),
201 str(pre_height), str(width), str(height),
199 full=self.file.url, image_meta=metadata)
202 full=self.file.url, image_meta=metadata)
200
203
201
204
202 class UrlViewer(AbstractViewer):
205 class UrlViewer(AbstractViewer):
203 @staticmethod
206 @staticmethod
204 def supports(file_type):
207 def supports(file_type):
205 return file_type is None
208 return file_type is None
206
209
207 def get_view(self):
210 def get_view(self):
208 return URL_VIEW.format(self.get_format_view(), get_domain(self.url))
211 return URL_VIEW.format(self.get_format_view(), get_domain(self.url))
209
212
210 def get_format_view(self):
213 def get_format_view(self):
211 protocol = self.url.split(':')[0]
214 protocol = self.url.split(':')[0]
212
215
213 domain = get_domain(self.url)
216 domain = get_domain(self.url)
214
217
215 if protocol in URL_PROTOCOLS:
218 if protocol in URL_PROTOCOLS:
216 url_image_name = URL_PROTOCOLS.get(protocol)
219 url_image_name = URL_PROTOCOLS.get(protocol)
217 elif domain:
220 elif domain:
218 url_image_name = self._find_image_for_domains(domain) or FILE_STUB_URL
221 url_image_name = self._find_image_for_domains(domain) or FILE_STUB_URL
219 else:
222 else:
220 url_image_name = FILE_STUB_URL
223 url_image_name = FILE_STUB_URL
221
224
222 image_path = 'images/{}.png'.format(url_image_name)
225 image_path = 'images/{}.png'.format(url_image_name)
223 image = static(image_path)
226 image = static(image_path)
224 w, h = get_static_dimensions(image_path)
227 w, h = get_static_dimensions(image_path)
225
228
226 return URL_FORMAT_VIEW.format(self.url, image, w, h)
229 return URL_FORMAT_VIEW.format(self.url, image, w, h)
227
230
228 @cached_result()
231 @cached_result()
229 def _find_image_for_domains(self, domain):
232 def _find_image_for_domains(self, domain):
230 """
233 """
231 Searches for the domain image for every domain level except top.
234 Searches for the domain image for every domain level except top.
232 E.g. for l3.example.co.uk it will search for l3.example.co.uk, then
235 E.g. for l3.example.co.uk it will search for l3.example.co.uk, then
233 example.co.uk, then co.uk
236 example.co.uk, then co.uk
234 """
237 """
235 levels = domain.split('.')
238 levels = domain.split('.')
236 while len(levels) > 1:
239 while len(levels) > 1:
237 domain = '.'.join(levels)
240 domain = '.'.join(levels)
238
241
239 filename = 'images/domains/{}.png'.format(domain)
242 filename = 'images/domains/{}.png'.format(domain)
240 if file_exists(filename):
243 if file_exists(filename):
241 return 'domains/' + domain
244 return 'domains/' + domain
242 else:
245 else:
243 del levels[0]
246 del levels[0]
244
247
General Comments 0
You need to be logged in to leave comments. Login now