pygal/views/userviews.py

537 regels
17 KiB
Python

from django.shortcuts import render
from django.utils.translation import gettext as _
import geo
import mimetypes
from ..models import get_item_type, get_item_by_rel_path, TYPE_AUDIO, TYPE_FOLDER, TYPE_IMAGE, TYPE_OTHER, TYPE_VIDEO
import os
import pygal
from ..queries import search_result_query
import random
import themes
import time
ADDTAG_ENTRY = 'addtag-main'
INFOVIEW_ENTRY = 'infoview-main'
DOWNLOAD_ENTRY = 'download-main'
DOWNLOAD_FLAT_ENTRY = 'download-flat-sub'
DOWNLOAD_STRUCT_ENTRY = 'download-struct-sub'
FAVOURITE_ENTRY = 'favourite-main'
REPEAT_ENTRY = 'repeat-main'
SHUFFLE_ENTRY = 'shuffle-main'
def get_wrapper_class(full_path):
return {
TYPE_FOLDER: folder_view,
TYPE_IMAGE: image_view,
TYPE_VIDEO: video_view,
TYPE_AUDIO: audio_view,
TYPE_OTHER: other_view,
}.get(get_item_type(full_path), base_view)
def get_wrapper_instance(full_path, request):
return get_wrapper_class(full_path)(request, full_path)
def random_copy(request, lst):
shuffle_id = pygal.get_shuffle_id(request)
#
rv = lst[:]
if shuffle_id is not None:
r = random.Random()
r.seed(shuffle_id)
r.shuffle(rv)
return rv
class base_view(object):
def __init__(self, request, full_path):
self.request = request
self.full_path = full_path
#
self.item = get_item_by_rel_path(pygal.get_rel_path(full_path))
if self.item is None:
raise LookupError("Error while initialising base_view, but item for %s does not exist." % full_path)
self.is_item = self.item.type != TYPE_FOLDER
#
self.mime_type = mimetypes.types_map.get(os.path.splitext(self.full_path)[1])
self.template = 'pygal/empty.html'
@property
def tags(self):
return self.item.tag_set.all()
def may_read(self):
return self.item.may_read(self.request.user)
def may_modify(self):
return self.item.may_modify(self.request.user)
def context_adaption(self, context):
context['item'] = self
context['thumbnail_size'] = pygal.get_thumbnail_size(self.request)
context['title'] = self.name or ''
context[context.ACTIONBAR].extend(self.actionbar)
@property
def heading(self):
return '%s' % self.item.name
@property
def general_information(self):
rv = []
full_path = pygal.get_full_path(self.item.rel_path)
rv.append({'description': _('Name'), 'data': os.path.basename(full_path), 'url': None})
rv.append({'description': _('Creation Time'), 'data': self.item.item_data.formatted_datetime, 'url': None})
rv.append({'description': _('Path'), 'data': os.path.dirname(full_path), 'url': None})
rv.append({'description': _('Size'), 'data': self.__size_txt__(self.item.item_data.size) + 'B', 'url': None})
rv.append({'description': _('UID'), 'data': self.item.current_uid(), 'url': None})
return rv
def __actionbar__(self):
b = themes.bar()
if self.is_item:
if self.is_my_favourite:
b.append_entry(
FAVOURITE_ENTRY,
'',
themes.color_icon_url(self.request, 'is_favourite.png'),
pygal.url_favourite_unset(self.request, self.item.rel_path),
True,
False
)
else:
b.append_entry(
FAVOURITE_ENTRY,
'',
themes.color_icon_url(self.request, 'favourite.png'),
pygal.url_favourite_set(self.request, self.item.rel_path),
True,
False
)
if pygal.is_infoview(self.request):
b.append_entry(
INFOVIEW_ENTRY,
_('Info'),
themes.color_icon_url(self.request, 'info.png'),
pygal.url_infoview(self.request, self.item.rel_path),
True,
True
)
else:
b.append_entry(
INFOVIEW_ENTRY,
_('Info'),
themes.color_icon_url(self.request, 'info.png'),
pygal.url_infoview(self.request, self.item.rel_path, search=pygal.SEARCH_KEEP),
True,
False
)
b.append_entry(
DOWNLOAD_ENTRY,
_('Download'),
themes.color_icon_url(self.request, 'download.png'),
pygal.url_download(self.request, self.item.rel_path),
True,
False
)
if type(self) is not folder_view:
if pygal.is_repeatview(self.request):
b.append_entry(
REPEAT_ENTRY,
_('Repeat'),
themes.color_icon_url(self.request, 'stop.png'),
pygal.url_userview(self.request, self.item.rel_path, search=pygal.SEARCH_KEEP),
True,
True
)
else:
b.append_entry(
REPEAT_ENTRY,
_('Repeat'),
themes.color_icon_url(self.request, 'play.png'),
pygal.url_repeatview(self.request, self.item.rel_path),
True,
False
)
if pygal.get_shuffle_id(self.request) is None:
b.append_entry(
SHUFFLE_ENTRY,
_('Shuffle'),
themes.color_icon_url(self.request, 'shuffle.png'),
pygal.url_userview(self.request, self.item.rel_path, shuffle=pygal.SHUFFLE_ENABLE, search=pygal.SEARCH_KEEP),
True,
False
)
else:
b.append_entry(
SHUFFLE_ENTRY,
_('Shuffle'),
themes.color_icon_url(self.request, 'shuffle.png'),
pygal.url_userview(self.request, self.item.rel_path, shuffle=pygal.SHUFFLE_DISABLE, search=pygal.SEARCH_KEEP),
True,
True
)
if self.is_item and self.may_modify():
b.append_entry(
ADDTAG_ENTRY,
_('Add Tag'),
themes.color_icon_url(self.request, 'edit2.png'),
pygal.url_addtag(self.request, self.item.rel_path),
True,
False
)
return b
@property
def is_my_favourite(self):
return self.request.user in self.item.favourite_of.all()
@property
def actionbar(self):
return self.__actionbar__()
def __tagbar__(self):
b = themes.bar(self.request)
i = 0
for t in self.item.tag_set.all():
i += 1
edit_url = pygal.url_tagedit(self.request, t.id) if self.may_modify() else None
b.append_entry('tag-%d' % i, t.text, themes.color_icon_url(self.request, '%d.png' % (i % 10)), edit_url, True, False)
return b
@property
def tagbar(self):
return self.__tagbar__()
@property
def duration(self):
return self.item.item_data.duration + 1.5
@property
def url_item(self):
return pygal.url_item(self.request, self.item.rel_path)
@property
def url_repeatview(self):
return pygal.url_repeatview(self.request, self.item.rel_path)
@property
def is_repeatview(self):
return pygal.is_repeatview(self.request)
@property
def url_thumbnail(self):
return pygal.url_thumbnail(self.request, self.item.rel_path)
@property
def url_userview(self):
return pygal.url_userview(self.request, self.item.rel_path, search=pygal.SEARCH_KEEP)
@property
def url_webnail(self):
return pygal.url_webnail(self.request, self.item.rel_path)
@property
def name(self):
return self.item.name
@property
def date_txt(self):
return self.item.item_data.formatted_datetime
def __size_txt__(self, size):
unit = {
0: '',
1: 'k',
2: 'M',
3: 'G',
4: 'T',
}
u = 0
while u < 4 and size > 1000.:
u += 1
size /= 1000.
if size < 100.:
return '%.2f %s' % (size, unit.get(u, '?'))
else:
return '%.1f %s' % (size, unit.get(u, '?'))
def __duration_txt__(self, duration):
if duration >= 3600:
return time.strftime('%H:%M:%S', time.gmtime(duration))
else:
return time.strftime('%M:%S', time.gmtime(duration))
def __parent__(self):
if pygal.is_searchview(self.request):
return query_view(self.request, search_result_query(self.request))
else:
return get_wrapper_instance(os.path.dirname(self.full_path), self.request)
def __nxt_prv__(self, direction):
if direction not in [-1, 1]:
raise ValueError("Parameter direction is incorrect: %s" % repr(direction))
fp_il = random_copy(self.request, self.__parent__().sorted_fullpathlist())
i = fp_il.index(self.full_path)
lgt = len(fp_il)
for i in range(i + direction, i + direction * lgt, direction):
full_path = fp_il[i % lgt]
if get_item_type(full_path) != TYPE_FOLDER:
return get_wrapper_instance(full_path, self.request)
return self
@property
def nxt(self):
return self.__nxt_prv__(1)
@property
def prv(self):
return self.__nxt_prv__(-1)
def render(self, context):
return render(self.request, self.template, context=context)
class query_view(object):
def __init__(self, request, query):
self.request = request
self.query = query
#
self.template = 'pygal/overview.html'
#
self.__item_list__ = None
def context_adaption(self, context):
context['item'] = self
context['thumbnail_size'] = pygal.get_thumbnail_size(self.request)
context['title'] = self.name or ''
context[context.ACTIONBAR].extend(self.actionbar)
@property
def name(self):
if pygal.is_favouriteview(self.request):
return _('My Favourites')
elif pygal.is_searchview(self.request):
return _('Search: "%s"' % pygal.get_search_query(self.request))
else:
return '-'
def __actionbar__(self):
b = themes.bar()
if pygal.is_infoview(self.request):
b.append_entry(
INFOVIEW_ENTRY,
_('Info'),
themes.color_icon_url(self.request, 'info.png'),
pygal.url_infoview(self.request, ''),
True,
True
)
else:
b.append_entry(
INFOVIEW_ENTRY,
_('Info'),
themes.color_icon_url(self.request, 'info.png'),
pygal.url_infoview(self.request, ''),
True,
False
)
b.append_entry(
DOWNLOAD_ENTRY,
_('Download'),
themes.color_icon_url(self.request, 'download.png'),
None,
True,
False
)
b.append_entry_to_entry(
DOWNLOAD_ENTRY,
DOWNLOAD_STRUCT_ENTRY,
_('Download (Structured)'),
themes.gray_icon_url(self.request, 'download.png'),
pygal.url_download(self.request, ''),
True,
False
)
b.append_entry_to_entry(
DOWNLOAD_ENTRY,
DOWNLOAD_FLAT_ENTRY,
_('Download (Flat)'),
themes.gray_icon_url(self.request, 'download.png'),
pygal.url_download(self.request, '', flat=True),
True,
False
)
if pygal.get_shuffle_id(self.request) is None:
b.append_entry(
SHUFFLE_ENTRY,
_('Shuffle'),
themes.color_icon_url(self.request, 'shuffle.png'),
pygal.url_userview(self.request, '', shuffle=pygal.SHUFFLE_ENABLE, search=pygal.SEARCH_KEEP),
True,
False
)
else:
b.append_entry(
SHUFFLE_ENTRY,
_('Shuffle'),
themes.color_icon_url(self.request, 'shuffle.png'),
pygal.url_userview(self.request, '', shuffle=pygal.SHUFFLE_DISABLE, search=pygal.SEARCH_KEEP),
True,
True
)
return b
@property
def actionbar(self):
return self.__actionbar__()
def sorted_fullpathlist(self):
il = []
for item_model in self.query:
if item_model.may_read(self.request.user):
il.append(item_model)
il.sort(key=lambda entry: entry.sort_string(), reverse=True)
return [pygal.get_full_path(i.rel_path) for i in il]
def __init_itemlist__(self):
if self.__item_list__ is None:
self.__item_list__ = []
for full_path in self.sorted_fullpathlist():
w = get_wrapper_instance(full_path, self.request)
self.__item_list__.append(w)
@property
def item_list(self):
self.__init_itemlist__()
return random_copy(self.request, self.__item_list__)
def render(self, context):
return render(self.request, self.template, context=context)
class folder_view(base_view):
def __init__(self, *args, **kwargs):
base_view.__init__(self, *args, **kwargs)
#
self.template = 'pygal/overview.html'
#
self.__item_list__ = None
def __actionbar__(self):
b = base_view.__actionbar__(self)
b.append_entry_to_entry(
DOWNLOAD_ENTRY,
DOWNLOAD_STRUCT_ENTRY,
_('Download (Structured)'),
themes.gray_icon_url(self.request, 'download.png'),
pygal.url_download(self.request, self.item.rel_path),
True,
False
)
b.append_entry_to_entry(
DOWNLOAD_ENTRY,
DOWNLOAD_FLAT_ENTRY,
_('Download (Flat)'),
themes.gray_icon_url(self.request, 'download.png'),
pygal.url_download(self.request, self.item.rel_path, flat=True),
True,
False
)
return b
def sorted_fullpathlist(self):
return [pygal.get_full_path(i.rel_path) for i in self.item.sorted_itemlist()]
def __init_fullpathlist__(self):
if self.__item_list__ is None:
self.__item_list__ = []
for full_path in self.sorted_fullpathlist():
w = get_wrapper_instance(full_path, self.request)
self.__item_list__.append(w)
@property
def item_list(self):
self.__init_fullpathlist__()
return random_copy(self.request, self.__item_list__)
@property
def url_thumbnail(self):
return pygal.url_thumbnail(self. request, self.item.thumbnail_item().rel_path)
class image_view(base_view):
def __init__(self, *args, **kwargs):
base_view.__init__(self, *args, **kwargs)
#
self.template = 'pygal/image.html'
def __actionbar__(self):
b = base_view.__actionbar__(self)
gps_data = self.item.item_data.gps
if gps_data is not None:
b.append_entry(
'actionbar-gpslink',
_('GPS'),
themes.color_icon_url(self.request, 'gps.png'),
geo.osm.landmark_link(geo.gps.coordinate(**gps_data)),
True,
False
)
return b
@property
def width(self):
if self.item.item_data.orientation in [5, 6, 7, 8]:
return self.item.item_data.height
else:
return self.item.item_data.width
@property
def height(self):
if self.item.item_data.orientation in [5, 6, 7, 8]:
return self.item.item_data.width
else:
return self.item.item_data.height
class video_view(base_view):
def __init__(self, *args, **kwargs):
base_view.__init__(self, *args, **kwargs)
#
self.template = 'pygal/video.html'
@property
def use_internal_player(self):
return self.mime_type in [mimetypes.types_map.get(ext) for ext in ['.mp4', '.webm', '.ogv', '.flv', '.3gp', ]]
@property
def webnail_width(self):
w, h = self.item.item_data.width, self.item.item_data.height
return int(pygal.get_webnail_size(self.request) * w / max(w, h))
@property
def webnail_height(self):
w, h = self.item.item_data.width, self.item.item_data.height
return int(pygal.get_webnail_size(self.request) * h / max(w, h))
class audio_view(base_view):
def __init__(self, *args, **kwargs):
base_view.__init__(self, *args, **kwargs)
#
self.template = 'pygal/audio.html'
@property
def heading(self):
return '%02d - %s' % (self.item.item_data.track, self.item.item_data.title)
class other_view(base_view):
def __init__(self, *args, **kwargs):
base_view.__init__(self, *args, **kwargs)
#
self.template = 'pygal/other.html'