##// END OF EJS Templates
Version bump
Version bump

File last commit:

r2090:cfe3a188 default
r2109:2f9d7bc7 4.11.0 default
Show More
viewers.py
243 lines | 6.9 KiB | text/x-python | PythonLexer
neko259
Move attachment domains list to a separate module
r1716 from django.contrib.staticfiles import finders
from django.contrib.staticfiles.templatetags.staticfiles import static
neko259
Store images as regular attachments instead of separate model
r1590 from django.core.files.images import get_image_dimensions
neko259
Added support for different attachment types
r1273 from django.template.defaultfilters import filesizeformat
neko259
Move attachment domains list to a separate module
r1716
neko259
Adapt to django-2.0
r1986 from boards import settings
neko259
Refactorings, refactorings...
r2008 from boards.abstracts.constants import THUMB_SIZES
from boards.settings import SECTION_EXTERNAL
neko259
Added ability to prevent downloading URL to a file
r1871 from boards.utils import get_domain, cached_result, get_extension
neko259
Added an image for wikipedia domain. Retrieve only 2nd level domain for the image, ignoring the 3rd level
r1715
neko259
Removed redundant viewers code
r2040 URL_IMAGE_PATH = 'images/{}.png'
neko259
Refactorings, refactorings...
r2008 PROTOCOL_DELIMITER = ':'
DOMAIN_DELIMITER = '.'
neko259
Support audio viewer
r1279 FILE_STUB_IMAGE = 'images/file.png'
neko259
Different images for different URL protocols
r1677 FILE_STUB_URL = 'url'
neko259
Added image for midi/mid file format. Store only common file formats (e.g. same image for different formats) in the code, otherwise get the image file directly from the statics
r1779 FILE_FILEFORMAT = 'images/fileformats/{}.png'
neko259
Support audio viewer
r1279
neko259
Added statistics management command
r1727
neko259
Video formats are not limited to webm
r1307 FILE_TYPES_VIDEO = (
neko259
Use mimetype instead of extensions for file type wherever it is used
r1866 'video/webm',
'video/mp4',
'video/mpeg',
'video/ogv',
neko259
Video formats are not limited to webm
r1307 )
neko259
Fixed SVG viewer
r1908 FILE_TYPE_SVG = 'image/svg+xml'
neko259
Support audio viewer
r1279 FILE_TYPES_AUDIO = (
neko259
Use mimetype instead of extensions for file type wherever it is used
r1866 'audio/ogg',
neko259
mp3 is of type audio/mpeg, not audio/mp3
r1870 'audio/mpeg',
neko259
Use mimetype instead of extensions for file type wherever it is used
r1866 'audio/opus',
neko259
Fixed flac mimetype for viewing
r1867 'audio/x-flac',
neko259
Try all chunks when detecting file mimetype
r1869 'audio/mpeg',
neko259
Support audio viewer
r1279 )
neko259
Store images as regular attachments instead of separate model
r1590 FILE_TYPES_IMAGE = (
neko259
Use mimetype instead of extensions for file type wherever it is used
r1866 'image/jpeg',
'image/jpg',
'image/png',
'image/bmp',
'image/gif',
neko259
Store images as regular attachments instead of separate model
r1590 )
neko259
Support audio viewer
r1279
neko259
Added images for different file formats
r1326 PLAIN_FILE_FORMATS = {
neko259
Added ability to prevent downloading URL to a file
r1871 'zip': 'archive',
'tar': 'archive',
neko259
Added image for archive file format
r1713 'gz': 'archive',
neko259
Added ability to prevent downloading URL to a file
r1871 'mid' : 'midi',
neko259
Added images for different file formats
r1326 }
neko259
Different images for different URL protocols
r1677 URL_PROTOCOLS = {
'magnet': 'magnet',
}
neko259
Store images as regular attachments instead of separate model
r1590 CSS_CLASS_IMAGE = 'image'
neko259
Refactored attachment viewers to store view htmls as constants
r1828 ABSTRACT_VIEW = '<div class="image">'\
'{}'\
neko259
Added sticker as a separate entity for the attachment aliases
r1937 '<div class="image-metadata"><a href="{}" download >{}, {}</a>'\
neko259
New menu icon for images
r1944 ' <a class="file-menu" href="#" data-type="{}" data-search-url="{}" data-filename="{}" data-id="{}">&#8942; </a></div>'\
neko259
Refactored attachment viewers to store view htmls as constants
r1828 '</div>'
URL_VIEW = '<div class="image">' \
'{}' \
'<div class="image-metadata">{}</div>' \
'</div>'
ABSTRACT_FORMAT_VIEW = '<a href="{}">'\
'<img class="url-image" src="{}" width="{}" height="{}"/>'\
'</a>'
VIDEO_FORMAT_VIEW = '<video width="200" height="150" controls src="{}"></video>'
AUDIO_FORMAT_VIEW = '<audio controls src="{}"></audio>'
neko259
Removed redundant viewers code
r2040 IMAGE_FORMAT_VIEW = '<a class="thumb" href="{full}">' \
neko259
Refactored attachment viewers to store view htmls as constants
r1828 '<img class="post-image-preview"' \
' src="{}"' \
' alt="{}"' \
' width="{}"' \
' height="{}"' \
' data-width="{}"' \
' data-height="{}" />' \
'</a>'
SVG_FORMAT_VIEW = '<a class="thumb" href="{}">'\
'<img class="post-image-preview" width="200" height="150" src="{}" />'\
'</a>'
URL_FORMAT_VIEW = '<a href="{}">' \
neko259
Show url as a tooltip of attachment
r2090 '<img class="url-image" src="{}" width="{}" height="{}" title="{}" />' \
neko259
Refactored attachment viewers to store view htmls as constants
r1828 '</a>'
neko259
Added support for different attachment types
r1273
neko259
Autodetect attachment viewers by getting all abstract viewer subclasses
r1286 def get_viewers():
return AbstractViewer.__subclasses__()
neko259
Added support for different attachment types
r1273 class AbstractViewer:
neko259
Added local stickers feature
r1940 def __init__(self, file, file_type, id, url):
neko259
Added support for different attachment types
r1273 self.file = file
self.file_type = file_type
neko259
Added local stickers feature
r1940 self.id = id
neko259
Load URL if the file could not be loaded
r1660 self.url = url
neko259
Added postmark for 3gp
r1967 self.extension = get_extension(self.file.name).lower()
neko259
Added support for different attachment types
r1273
@staticmethod
def supports(file_type):
neko259
Support audio viewer
r1279 return True
neko259
Added support for different attachment types
r1273
def get_view(self):
neko259
Refactorings, refactorings...
r2008 return ABSTRACT_VIEW.format(self.get_format_view(), self.file.url,
self.file_type, filesizeformat(self.file.size),
self.file_type, self._get_search_url(), self.file.name, self.id)
def _get_search_url(self):
search_host = settings.get(SECTION_EXTERNAL, 'ImageSearchHost')
neko259
Build file search menu on the JS side
r1817 if search_host:
neko259
Remove backslash from image search host
r1821 if search_host.endswith('/'):
search_host = search_host[:-1]
neko259
Build file search menu on the JS side
r1817 search_url = search_host + self.file.url
else:
search_url = ''
neko259
Refactorings, refactorings...
r2008 return search_url
neko259
Show file metadata for all attachments
r1300
def get_format_view(self):
neko259
Added ability to prevent downloading URL to a file
r1871 image_name = PLAIN_FILE_FORMATS.get(self.extension, self.extension)
neko259
Added image for midi/mid file format. Store only common file formats (e.g. same image for different formats) in the code, otherwise get the image file directly from the statics
r1779 file_name = FILE_FILEFORMAT.format(image_name)
neko259
Cache some of the attachment viewers logic
r2014 if self.file_exists(file_name):
neko259
Added image for midi/mid file format. Store only common file formats (e.g. same image for different formats) in the code, otherwise get the image file directly from the statics
r1779 image = file_name
neko259
Added images for different file formats
r1326 else:
image = FILE_STUB_IMAGE
neko259
Cache some of the attachment viewers logic
r2014 w, h = self.get_static_dimensions(image)
neko259
Use real image stub sizes, not 200x150
r1684
neko259
Refactored attachment viewers to store view htmls as constants
r1828 return ABSTRACT_FORMAT_VIEW.format(self.file.url, static(image), w, h)
neko259
Added support for different attachment types
r1273
neko259
Cache some of the attachment viewers logic
r2014 @cached_result()
def get_static_dimensions(self, filename):
file_path = finders.find(filename)
return get_image_dimensions(file_path)
@cached_result()
def file_exists(self, filename):
return finders.find(filename) is not None
neko259
Added support for different attachment types
r1273
neko259
Video formats are not limited to webm
r1307 class VideoViewer(AbstractViewer):
neko259
Added support for different attachment types
r1273 @staticmethod
def supports(file_type):
neko259
Video formats are not limited to webm
r1307 return file_type in FILE_TYPES_VIDEO
neko259
Added support for different attachment types
r1273
neko259
Show file metadata for all attachments
r1300 def get_format_view(self):
neko259
Refactored attachment viewers to store view htmls as constants
r1828 return VIDEO_FORMAT_VIEW.format(self.file.url)
neko259
Added support for different attachment types
r1273
neko259
Support audio viewer
r1279
class AudioViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type in FILE_TYPES_AUDIO
neko259
Show file metadata for all attachments
r1300 def get_format_view(self):
neko259
Refactored attachment viewers to store view htmls as constants
r1828 return AUDIO_FORMAT_VIEW.format(self.file.url)
neko259
Added basic SVG support
r1284
class SvgViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type == FILE_TYPE_SVG
neko259
Show file metadata for all attachments
r1300 def get_format_view(self):
neko259
Refactored attachment viewers to store view htmls as constants
r1828 return SVG_FORMAT_VIEW.format(self.file.url, self.file.url)
neko259
Store images as regular attachments instead of separate model
r1590
class ImageViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type in FILE_TYPES_IMAGE
def get_format_view(self):
neko259
Decompression bomb protection in image viewing
r1820 try:
width, height = get_image_dimensions(self.file.path)
except Exception:
# If the image is a decompression bomb, treat it as just a regular
# file
return super().get_format_view()
neko259
Store images as regular attachments instead of separate model
r1590 preview_path = self.file.path.replace('.', '.200x150.')
neko259
Fixed viewing an image without a preview
r1906 try:
pre_width, pre_height = get_image_dimensions(preview_path)
except Exception:
return super().get_format_view()
neko259
Store images as regular attachments instead of separate model
r1590
split = self.file.url.rsplit('.', 1)
neko259
Refactorings, refactorings...
r2008 w, h = THUMB_SIZES[0]
neko259
Store images as regular attachments instead of separate model
r1590 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
neko259
Removed redundant viewers code
r2040 return IMAGE_FORMAT_VIEW.format(
thumb_url,
self.id,
pre_width, pre_height, width, height,
full=self.file.url)
neko259
Store images as regular attachments instead of separate model
r1590
neko259
Load URL if the file could not be loaded
r1660
class UrlViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type is None
def get_view(self):
neko259
Refactored attachment viewers to store view htmls as constants
r1828 return URL_VIEW.format(self.get_format_view(), get_domain(self.url))
neko259
Different images for different URL protocols
r1677
neko259
Load URL if the file could not be loaded
r1660 def get_format_view(self):
neko259
Refactorings, refactorings...
r2008 protocol = self.url.split(PROTOCOL_DELIMITER)[0]
neko259
Show domain next to URL if available
r1765
domain = get_domain(self.url)
neko259
Added ability to add links to specific domains and show the domain logo as an image substitute
r1695
neko259
Removed redundant viewers code
r2040 image_path = URL_IMAGE_PATH.format(self._get_image_name(protocol, domain))
neko259
Simplify adding new domain images. Not there is no separate dict, just searching a file by name from a static finder
r1718 image = static(image_path)
neko259
Cache some of the attachment viewers logic
r2014 w, h = self.get_static_dimensions(image_path)
neko259
Use real image stub sizes, not 200x150
r1684
neko259
Show url as a tooltip of attachment
r2090 return URL_FORMAT_VIEW.format(self.url, image, w, h, self.url)
neko259
Show domain next to URL if available
r1765
neko259
Search for image for every domain level starting from the lowest one. Cache this into memcached
r1772 def _find_image_for_domains(self, domain):
"""
Searches for the domain image for every domain level except top.
E.g. for l3.example.co.uk it will search for l3.example.co.uk, then
example.co.uk, then co.uk
"""
neko259
Refactorings, refactorings...
r2008 levels = domain.split(DOMAIN_DELIMITER)
neko259
Search for image for every domain level starting from the lowest one. Cache this into memcached
r1772 while len(levels) > 1:
neko259
Refactorings, refactorings...
r2008 domain = DOMAIN_DELIMITER.join(levels)
neko259
Show domain next to URL if available
r1765
neko259
Search for image for every domain level starting from the lowest one. Cache this into memcached
r1772 filename = 'images/domains/{}.png'.format(domain)
neko259
Cache some of the attachment viewers logic
r2014 if self.file_exists(filename):
neko259
Search for image for every domain level starting from the lowest one. Cache this into memcached
r1772 return 'domains/' + domain
else:
del levels[0]
neko259
Cache tweaks
r2015
@cached_result()
def _get_image_name(self, protocol, domain):
if protocol in URL_PROTOCOLS:
url_image_name = URL_PROTOCOLS.get(protocol)
elif domain:
url_image_name = self._find_image_for_domains(domain) or FILE_STUB_URL
else:
url_image_name = FILE_STUB_URL
return url_image_name