##// END OF EJS Templates
Fixed popup image preview
neko259 -
r1596:b556dd6b default
parent child Browse files
Show More
@@ -1,78 +1,78 b''
1 import boards
1 import boards
2 from boards.models import STATUS_ARCHIVE
2 from boards.models import STATUS_ARCHIVE
3 from django.core.files.images import get_image_dimensions
3 from django.core.files.images import get_image_dimensions
4 from django.db import models
4 from django.db import models
5
5
6 from boards import utils
6 from boards import utils
7 from boards.models.attachment.viewers import get_viewers, AbstractViewer, \
7 from boards.models.attachment.viewers import get_viewers, AbstractViewer, \
8 FILE_TYPES_IMAGE
8 FILE_TYPES_IMAGE
9 from boards.utils import get_upload_filename, get_extension, cached_result
9 from boards.utils import get_upload_filename, get_extension, cached_result
10
10
11
11
12 class AttachmentManager(models.Manager):
12 class AttachmentManager(models.Manager):
13 def create_with_hash(self, file):
13 def create_with_hash(self, file):
14 file_hash = utils.get_file_hash(file)
14 file_hash = utils.get_file_hash(file)
15 existing = self.filter(hash=file_hash)
15 existing = self.filter(hash=file_hash)
16 if len(existing) > 0:
16 if len(existing) > 0:
17 attachment = existing[0]
17 attachment = existing[0]
18 else:
18 else:
19 # FIXME Use full mimetype here, need to modify viewers too
19 # FIXME Use full mimetype here, need to modify viewers too
20 file_type = get_extension(file.name)
20 file_type = get_extension(file.name)
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 get_random_images(self, count, tags=None):
26 def get_random_images(self, count, tags=None):
27 images = self.filter(mimetype__in=FILE_TYPES_IMAGE).exclude(
27 images = self.filter(mimetype__in=FILE_TYPES_IMAGE).exclude(
28 attachment_posts__thread__status=STATUS_ARCHIVE)
28 attachment_posts__thread__status=STATUS_ARCHIVE)
29 if tags is not None:
29 if tags is not None:
30 images = images.filter(attachment_posts__threads__tags__in=tags)
30 images = images.filter(attachment_posts__threads__tags__in=tags)
31 return images.order_by('?')[:count]
31 return images.order_by('?')[:count]
32
32
33
33
34 class Attachment(models.Model):
34 class Attachment(models.Model):
35 objects = AttachmentManager()
35 objects = AttachmentManager()
36
36
37 file = models.FileField(upload_to=get_upload_filename)
37 file = models.FileField(upload_to=get_upload_filename)
38 mimetype = models.CharField(max_length=50)
38 mimetype = models.CharField(max_length=50)
39 hash = models.CharField(max_length=36)
39 hash = models.CharField(max_length=36)
40 alias = models.TextField(unique=True, null=True, blank=True)
40 alias = models.TextField(unique=True, null=True, blank=True)
41
41
42 def get_view(self):
42 def get_view(self):
43 file_viewer = None
43 file_viewer = None
44 for viewer in get_viewers():
44 for viewer in get_viewers():
45 if viewer.supports(self.mimetype):
45 if viewer.supports(self.mimetype):
46 file_viewer = viewer
46 file_viewer = viewer
47 break
47 break
48 if file_viewer is None:
48 if file_viewer is None:
49 file_viewer = AbstractViewer
49 file_viewer = AbstractViewer
50
50
51 return file_viewer(self.file, self.mimetype).get_view()
51 return file_viewer(self.file, self.mimetype, self.hash).get_view()
52
52
53 def __str__(self):
53 def __str__(self):
54 return self.file.url
54 return self.file.url
55
55
56 def get_random_associated_post(self):
56 def get_random_associated_post(self):
57 posts = boards.models.Post.objects.filter(attachments__in=[self])
57 posts = boards.models.Post.objects.filter(attachments__in=[self])
58 return posts.order_by('?').first()
58 return posts.order_by('?').first()
59
59
60 @cached_result()
60 @cached_result()
61 def get_size(self):
61 def get_size(self):
62 if self.mimetype in FILE_TYPES_IMAGE:
62 if self.mimetype in FILE_TYPES_IMAGE:
63 return get_image_dimensions(self.file)
63 return get_image_dimensions(self.file)
64 else:
64 else:
65 return 200, 150
65 return 200, 150
66
66
67 def get_thumb_url(self):
67 def get_thumb_url(self):
68 split = self.file.url.rsplit('.', 1)
68 split = self.file.url.rsplit('.', 1)
69 w, h = 200, 150
69 w, h = 200, 150
70 return '%s.%sx%s.%s' % (split[0], w, h, split[1])
70 return '%s.%sx%s.%s' % (split[0], w, h, split[1])
71
71
72 @cached_result()
72 @cached_result()
73 def get_preview_size(self):
73 def get_preview_size(self):
74 if self.mimetype in FILE_TYPES_IMAGE:
74 if self.mimetype in FILE_TYPES_IMAGE:
75 preview_path = self.file.path.replace('.', '.200x150.')
75 preview_path = self.file.path.replace('.', '.200x150.')
76 return get_image_dimensions(preview_path)
76 return get_image_dimensions(preview_path)
77 else:
77 else:
78 return 200, 150
78 return 200, 150
@@ -1,128 +1,131 b''
1 from django.core.files.images import get_image_dimensions
1 from django.core.files.images import get_image_dimensions
2 from django.template.defaultfilters import filesizeformat
2 from django.template.defaultfilters import filesizeformat
3 from django.contrib.staticfiles.templatetags.staticfiles import static
3 from django.contrib.staticfiles.templatetags.staticfiles import static
4
4
5 FILE_STUB_IMAGE = 'images/file.png'
5 FILE_STUB_IMAGE = 'images/file.png'
6
6
7 FILE_TYPES_VIDEO = (
7 FILE_TYPES_VIDEO = (
8 'webm',
8 'webm',
9 'mp4',
9 'mp4',
10 'mpeg',
10 'mpeg',
11 'ogv',
11 'ogv',
12 )
12 )
13 FILE_TYPE_SVG = 'svg'
13 FILE_TYPE_SVG = 'svg'
14 FILE_TYPES_AUDIO = (
14 FILE_TYPES_AUDIO = (
15 'ogg',
15 'ogg',
16 'mp3',
16 'mp3',
17 'opus',
17 'opus',
18 )
18 )
19 FILE_TYPES_IMAGE = (
19 FILE_TYPES_IMAGE = (
20 'jpeg',
20 'jpeg',
21 'jpg',
21 'jpg',
22 'png',
22 'png',
23 'bmp',
23 'bmp',
24 'gif',
24 'gif',
25 )
25 )
26
26
27 PLAIN_FILE_FORMATS = {
27 PLAIN_FILE_FORMATS = {
28 'pdf': 'pdf',
28 'pdf': 'pdf',
29 'djvu': 'djvu',
29 'djvu': 'djvu',
30 'txt': 'txt',
30 'txt': 'txt',
31 }
31 }
32
32
33 CSS_CLASS_IMAGE = 'image'
33 CSS_CLASS_IMAGE = 'image'
34 CSS_CLASS_THUMB = 'thumb'
34 CSS_CLASS_THUMB = 'thumb'
35
35
36
36
37 def get_viewers():
37 def get_viewers():
38 return AbstractViewer.__subclasses__()
38 return AbstractViewer.__subclasses__()
39
39
40
40
41 class AbstractViewer:
41 class AbstractViewer:
42 def __init__(self, file, file_type):
42 def __init__(self, file, file_type, hash):
43 self.file = file
43 self.file = file
44 self.file_type = file_type
44 self.file_type = file_type
45 self.hash = hash
45
46
46 @staticmethod
47 @staticmethod
47 def supports(file_type):
48 def supports(file_type):
48 return True
49 return True
49
50
50 def get_view(self):
51 def get_view(self):
51 return '<div class="image">'\
52 return '<div class="image">'\
52 '{}'\
53 '{}'\
53 '<div class="image-metadata"><a href="{}" download >{}, {}</a></div>'\
54 '<div class="image-metadata"><a href="{}" download >{}, {}</a></div>'\
54 '</div>'.format(self.get_format_view(), self.file.url,
55 '</div>'.format(self.get_format_view(), self.file.url,
55 self.file_type, filesizeformat(self.file.size))
56 self.file_type, filesizeformat(self.file.size))
56
57
57 def get_format_view(self):
58 def get_format_view(self):
58 if self.file_type in PLAIN_FILE_FORMATS:
59 if self.file_type in PLAIN_FILE_FORMATS:
59 image = 'images/fileformats/{}.png'.format(
60 image = 'images/fileformats/{}.png'.format(
60 PLAIN_FILE_FORMATS[self.file_type])
61 PLAIN_FILE_FORMATS[self.file_type])
61 else:
62 else:
62 image = FILE_STUB_IMAGE
63 image = FILE_STUB_IMAGE
63
64
64 return '<a href="{}">'\
65 return '<a href="{}">'\
65 '<img src="{}" width="200" height="150"/>'\
66 '<img src="{}" width="200" height="150"/>'\
66 '</a>'.format(self.file.url, static(image))
67 '</a>'.format(self.file.url, static(image))
67
68
68
69
69 class VideoViewer(AbstractViewer):
70 class VideoViewer(AbstractViewer):
70 @staticmethod
71 @staticmethod
71 def supports(file_type):
72 def supports(file_type):
72 return file_type in FILE_TYPES_VIDEO
73 return file_type in FILE_TYPES_VIDEO
73
74
74 def get_format_view(self):
75 def get_format_view(self):
75 return '<video width="200" height="150" controls src="{}"></video>'\
76 return '<video width="200" height="150" controls src="{}"></video>'\
76 .format(self.file.url)
77 .format(self.file.url)
77
78
78
79
79 class AudioViewer(AbstractViewer):
80 class AudioViewer(AbstractViewer):
80 @staticmethod
81 @staticmethod
81 def supports(file_type):
82 def supports(file_type):
82 return file_type in FILE_TYPES_AUDIO
83 return file_type in FILE_TYPES_AUDIO
83
84
84 def get_format_view(self):
85 def get_format_view(self):
85 return '<audio controls src="{}"></audio>'.format(self.file.url)
86 return '<audio controls src="{}"></audio>'.format(self.file.url)
86
87
87
88
88 class SvgViewer(AbstractViewer):
89 class SvgViewer(AbstractViewer):
89 @staticmethod
90 @staticmethod
90 def supports(file_type):
91 def supports(file_type):
91 return file_type == FILE_TYPE_SVG
92 return file_type == FILE_TYPE_SVG
92
93
93 def get_format_view(self):
94 def get_format_view(self):
94 return '<a class="thumb" href="{}">'\
95 return '<a class="thumb" href="{}">'\
95 '<img class="post-image-preview" width="200" height="150" src="{}" />'\
96 '<img class="post-image-preview" width="200" height="150" src="{}" />'\
96 '</a>'.format(self.file.url, self.file.url)
97 '</a>'.format(self.file.url, self.file.url)
97
98
98
99
99 class ImageViewer(AbstractViewer):
100 class ImageViewer(AbstractViewer):
100 @staticmethod
101 @staticmethod
101 def supports(file_type):
102 def supports(file_type):
102 return file_type in FILE_TYPES_IMAGE
103 return file_type in FILE_TYPES_IMAGE
103
104
104 def get_format_view(self):
105 def get_format_view(self):
105 metadata = '{}, {}'.format(self.file.name.split('.')[-1],
106 metadata = '{}, {}'.format(self.file.name.split('.')[-1],
106 filesizeformat(self.file.size))
107 filesizeformat(self.file.size))
107 width, height = get_image_dimensions(self.file.file)
108 width, height = get_image_dimensions(self.file.file)
108 preview_path = self.file.path.replace('.', '.200x150.')
109 preview_path = self.file.path.replace('.', '.200x150.')
109 pre_width, pre_height = get_image_dimensions(preview_path)
110 pre_width, pre_height = get_image_dimensions(preview_path)
110
111
111 split = self.file.url.rsplit('.', 1)
112 split = self.file.url.rsplit('.', 1)
112 w, h = 200, 150
113 w, h = 200, 150
113 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
114 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
114
115
115 return '<a class="{}" href="{full}">' \
116 return '<a class="{}" href="{full}">' \
116 '<img class="post-image-preview"' \
117 '<img class="post-image-preview"' \
117 ' src="{}"' \
118 ' src="{}"' \
119 ' alt="{}"' \
118 ' width="{}"' \
120 ' width="{}"' \
119 ' height="{}"' \
121 ' height="{}"' \
120 ' data-width="{}"' \
122 ' data-width="{}"' \
121 ' data-height="{}" />' \
123 ' data-height="{}" />' \
122 '</a>' \
124 '</a>' \
123 .format(CSS_CLASS_THUMB,
125 .format(CSS_CLASS_THUMB,
124 thumb_url,
126 thumb_url,
127 self.hash,
125 str(pre_width),
128 str(pre_width),
126 str(pre_height), str(width), str(height),
129 str(pre_height), str(width), str(height),
127 full=self.file.url, image_meta=metadata)
130 full=self.file.url, image_meta=metadata)
128
131
General Comments 0
You need to be logged in to leave comments. Login now