##// END OF EJS Templates
Made quote button actually button so it is impossible to accidentally quote its text
Made quote button actually button so it is impossible to accidentally quote its text

File last commit:

r1908:810844f7 default
r1909:004a4ff8 default
Show More
viewers.py
244 lines | 6.8 KiB | text/x-python | PythonLexer
import re
from PIL import Image
from django.contrib.staticfiles import finders
from django.contrib.staticfiles.templatetags.staticfiles import static
from django.core.files.images import get_image_dimensions
from django.template.defaultfilters import filesizeformat
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _, ungettext_lazy
from boards.utils import get_domain, cached_result, get_extension
from boards import settings
FILE_STUB_IMAGE = 'images/file.png'
FILE_STUB_URL = 'url'
FILE_FILEFORMAT = 'images/fileformats/{}.png'
FILE_TYPES_VIDEO = (
'video/webm',
'video/mp4',
'video/mpeg',
'video/ogv',
)
FILE_TYPE_SVG = 'image/svg+xml'
FILE_TYPES_AUDIO = (
'audio/ogg',
'audio/mpeg',
'audio/opus',
'audio/x-flac',
'audio/mpeg',
)
FILE_TYPES_IMAGE = (
'image/jpeg',
'image/jpg',
'image/png',
'image/bmp',
'image/gif',
)
PLAIN_FILE_FORMATS = {
'zip': 'archive',
'tar': 'archive',
'gz': 'archive',
'mid' : 'midi',
}
URL_PROTOCOLS = {
'magnet': 'magnet',
}
CSS_CLASS_IMAGE = 'image'
CSS_CLASS_THUMB = 'thumb'
ABSTRACT_VIEW = '<div class="image">'\
'{}'\
'<div class="image-metadata"><a href="{}" download >{}, {}</a>'\
' <a class="file-menu" href="#" data-type="{}" data-search-url="{}" data-filename="{}">🔍 </a></div>'\
'</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>'
IMAGE_FORMAT_VIEW = '<a class="{}" href="{full}">' \
'<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="{}">' \
'<img class="url-image" src="{}" width="{}" height="{}"/>' \
'</a>'
def get_viewers():
return AbstractViewer.__subclasses__()
def get_static_dimensions(filename):
file_path = finders.find(filename)
return get_image_dimensions(file_path)
# TODO Move this to utils
def file_exists(filename):
return finders.find(filename) is not None
class AbstractViewer:
def __init__(self, file, file_type, hash, url):
self.file = file
self.file_type = file_type
self.hash = hash
self.url = url
self.extension = get_extension(self.file.name)
@staticmethod
def supports(file_type):
return True
def get_view(self):
search_host = settings.get('External', 'ImageSearchHost')
if search_host:
if search_host.endswith('/'):
search_host = search_host[:-1]
search_url = search_host + self.file.url
else:
search_url = ''
return ABSTRACT_VIEW.format(self.get_format_view(), self.file.url,
self.file_type, filesizeformat(self.file.size),
self.file_type, search_url, self.file.name)
def get_format_view(self):
image_name = PLAIN_FILE_FORMATS.get(self.extension, self.extension)
file_name = FILE_FILEFORMAT.format(image_name)
if file_exists(file_name):
image = file_name
else:
image = FILE_STUB_IMAGE
w, h = get_static_dimensions(image)
return ABSTRACT_FORMAT_VIEW.format(self.file.url, static(image), w, h)
class VideoViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type in FILE_TYPES_VIDEO
def get_format_view(self):
return VIDEO_FORMAT_VIEW.format(self.file.url)
class AudioViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type in FILE_TYPES_AUDIO
def get_format_view(self):
return AUDIO_FORMAT_VIEW.format(self.file.url)
class SvgViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type == FILE_TYPE_SVG
def get_format_view(self):
return SVG_FORMAT_VIEW.format(self.file.url, self.file.url)
class ImageViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type in FILE_TYPES_IMAGE
def get_format_view(self):
metadata = '{}, {}'.format(self.file.name.split('.')[-1],
filesizeformat(self.file.size))
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()
preview_path = self.file.path.replace('.', '.200x150.')
try:
pre_width, pre_height = get_image_dimensions(preview_path)
except Exception:
return super().get_format_view()
split = self.file.url.rsplit('.', 1)
w, h = 200, 150
thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
return IMAGE_FORMAT_VIEW.format(CSS_CLASS_THUMB,
thumb_url,
self.hash,
str(pre_width),
str(pre_height), str(width), str(height),
full=self.file.url, image_meta=metadata)
class UrlViewer(AbstractViewer):
@staticmethod
def supports(file_type):
return file_type is None
def get_view(self):
return URL_VIEW.format(self.get_format_view(), get_domain(self.url))
def get_format_view(self):
protocol = self.url.split(':')[0]
domain = get_domain(self.url)
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
image_path = 'images/{}.png'.format(url_image_name)
image = static(image_path)
w, h = get_static_dimensions(image_path)
return URL_FORMAT_VIEW.format(self.url, image, w, h)
@cached_result()
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
"""
levels = domain.split('.')
while len(levels) > 1:
domain = '.'.join(levels)
filename = 'images/domains/{}.png'.format(domain)
if file_exists(filename):
return 'domains/' + domain
else:
del levels[0]