##// END OF EJS Templates
Use proper settings for max landing threads. Show thread last update time instead of number of posts
Use proper settings for max landing threads. Show thread last update time instead of number of posts

File last commit:

r1986:0b41439a default
r2001:6d66389f default
Show More
viewers.py
237 lines | 6.7 KiB | text/x-python | PythonLexer
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 boards import settings
from boards.utils import get_domain, cached_result, get_extension
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="{}" data-id="{}">&#8942; </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, id, url):
self.file = file
self.file_type = file_type
self.id = id
self.url = url
self.extension = get_extension(self.file.name).lower()
@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, self.id)
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.id,
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]