list icons

This commit is contained in:
j 2011-09-29 13:05:34 +00:00
parent d7a2833711
commit 64e7a534a7
6 changed files with 106 additions and 24 deletions

View file

@ -444,6 +444,7 @@ class Item(models.Model):
if not keys or 'posterRatio' in keys:
i['posterRatio'] = self.poster_width / self.poster_height
streams = self.streams()
i['durations'] = [s.duration for s in streams]
i['duration'] = sum(i['durations'])
@ -454,8 +455,16 @@ class Item(models.Model):
#only needed by admins
if keys and 'posters' in keys:
i['posters'] = self.get_posters()
frames = self.get_frames()
if keys and 'frames' in keys:
i['frames'] = self.get_frames()
i['frames'] = frames
if frames:
i['posterFrame'] = filter(lambda f: f['selected'], frames)[0]['position']
elif self.poster_frame != -1.0:
i['posterFrame'] = self.poster_frame
if keys:
info = {}
for key in keys:

View file

@ -10,11 +10,11 @@ import models
def parseCondition(condition, user):
'''
'''
print condition, user
k = condition.get('key', 'name')
k = {
'user': 'user__username',
'position': 'position__position',
'posterFrames': 'poster_frames',
}.get(k, k)
if not k:
k = 'name'
@ -132,4 +132,4 @@ class ListManager(Manager):
qs = qs.filter(Q(status='public') | Q(status='featured'))
else:
qs = qs.filter(Q(status='public') | Q(status='featured') | Q(user=user))
return qs.distinct()
return qs

View file

@ -3,13 +3,16 @@
from __future__ import division, with_statement
import os
import subprocess
from glob import glob
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
import ox
from ox.django.fields import DictField
from ox.django.fields import DictField, TupleField
from archive import extract
import managers
@ -31,10 +34,13 @@ class List(models.Model):
icon = models.ImageField(default=None, blank=True,
upload_to=lambda i, x: i.path("icon.jpg"))
poster_frames = TupleField(default=[], editable=False)
#is through table still required?
items = models.ManyToManyField('item.Item', related_name='lists',
through='ListItem')
items_sum = models.IntegerField(default=0)
subscribed_users = models.ManyToManyField(User, related_name='subscribed_lists')
objects = managers.ListManager()
@ -44,9 +50,10 @@ class List(models.Model):
self.type = 'static'
else:
self.type = 'smart'
self.items_sum = self.get_items_sum(self.user)
super(List, self).save(*args, **kwargs)
def get_number_of_items(self, user=None):
def get_items_sum(self, user=None):
if self.query.get('static', False):
return self.items.count()
else:
@ -78,11 +85,11 @@ class List(models.Model):
def json(self, keys=None, user=None):
if not keys:
keys=['id', 'name', 'user', 'type', 'query', 'status', 'subscribed']
keys=['id', 'name', 'user', 'type', 'query', 'status', 'subscribed', 'posterFrames']
response = {}
for key in keys:
if key == 'items':
response[key] = self.get_number_of_items(user)
response[key] = self.get_items_sum(user)
elif key == 'id':
response[key] = self.get_id()
elif key == 'user':
@ -90,30 +97,64 @@ class List(models.Model):
elif key == 'query':
if not self.query.get('static', False):
response[key] = self.query
elif key == 'subscribers':
response[key] = self.subscribed_users.all().count()
elif key == 'subscribed':
if user and not user.is_anonymous():
response[key] = self.subscribed_users.filter(id=user.id).exists()
else:
response[key] = getattr(self, key)
response[key] = getattr(self, {
'posterFrames': 'poster_frames'
}.get(key, key))
return response
def path(self, name=''):
h = self.get_id()
h = "%06d" % self.id
return os.path.join('lists', h[:2], h[2:4], h[4:6], h[6:], name)
def make_icon(self):
def update_icon(self):
frames = []
self.icon.name = self.path('icon.png')
for i in self.poster_frames:
qs = self.items.filter(itemId=i['item'])
if qs.count() > 0:
frame = qs[0].frame(i['position'])
if frame:
frames.append(frame)
self.icon.name = self.path('icon.jpg')
icon = self.icon.path
if frames:
while len(frames) < 4:
frames += frames
folder = os.path.dirname(icon)
ox.makedirs(folder)
for f in glob("%s/icon*.jpg" % folder):
os.unlink(f)
cmd = [
'scripts/list_icon',
settings.LIST_ICON,
'-f', ','.join(frames),
'-o', icon
]
p = subprocess.Popen(cmd)
p.wait()
self.save()
def get_icon(self, size=16):
path = self.path('icon%d.jpg' % size)
path = os.path.join(settings.MEDIA_ROOT, path)
if not os.path.exists(path):
folder = os.path.dirname(path)
ox.makedirs(folder)
if self.icon:
source = self.icon.path
max_size = min(self.icon.width, self.icon.height)
else:
source = os.path.join(settings.STATIC_ROOT, 'png/list256.png')
max_size = 256
if size < max_size:
extract.resize_image(source, path, size=size)
else:
path = source
return path
class ListItem(models.Model):
created = models.DateTimeField(auto_now_add=True)

View file

@ -2,10 +2,12 @@
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
from django.db.models import Max
from django.db.models import Max, Sum
from django.http import HttpResponseForbidden, Http404
from ox.utils import json
from ox.django.decorators import login_required_json
from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response
from ox.django.http import HttpFileResponse
import models
from api.actions import actions
@ -25,10 +27,13 @@ def _order_query(qs, sort):
if operator != '-':
operator = ''
key = {
'subscribed': 'subscribed_users'
'subscribed': 'subscribed_users',
'items': 'items_sum'
}.get(e['key'], e['key'])
order = '%s%s' % (operator, key)
order_by.append(order)
if key == 'subscribers':
qs = qs.annotate(subscribers=Sum('subscribed_users'))
if order_by:
qs = qs.order_by(*order_by)
return qs
@ -181,6 +186,13 @@ def addList(request):
param data {
name: value,
}
possible keys to create list:
name
description
type
query
items
return {
status: {'code': int, 'text': string},
data: {
@ -197,7 +209,7 @@ def addList(request):
while not created:
list, created = models.List.objects.get_or_create(name=name, user=request.user)
num += 1
name = data['name'] + ' (%d)' % num
name = data['name'] + ' [%d]' % num
for key in data:
if key == 'query' and not data['query']:
@ -223,6 +235,10 @@ def addList(request):
list.description = data['description']
list.save()
if 'items' in data:
for item in Item.objects.filter(itemId__in=data['items']):
list.add(item)
if list.status == 'featured':
pos, created = models.Position.objects.get_or_create(list=list,
user=request.user, section='featured')
@ -246,9 +262,11 @@ def editList(request):
id: listId,
key: value,
}
keys: name, status, query, position
keys: name, status, query, position, posterFrames
if you change status you have to provide position of list
posterFrames:
array with objects that have item/position
return {
status: {'code': int, 'text': string},
data: {
@ -330,6 +348,9 @@ def editList(request):
if list.status == 'private':
pos.section = 'personal'
pos.save()
if 'posterFrames' in data:
list.poster_frames = tuple(data['posterFrames'])
list.update_icon()
list.save()
response['data'] = list.json(user=request.user)
else:
@ -462,3 +483,13 @@ def sortLists(request):
response = json_response()
return render_to_json_response(response)
actions.register(sortLists, cache=False)
def icon(request, id, size=16):
if not size:
size = 16
list = get_list_or_404_json(id)
icon = list.get_icon(int(size))
if icon:
return HttpFileResponse(icon, content_type='image/jpeg')
raise Http404

View file

@ -16,15 +16,14 @@ from optparse import OptionParser
from ox.image import drawText, wrapText
import sys
static_root = os.path.join(os.path.dirname(__file__), '..', '..', 'static')
def render_list_icon(frames, icon):
icon_width = 256
icon_height = 256
icon_image = Image.new('RGBA', (icon_width, icon_height))
frame_height = icon_height / 4
frame_ratio = 4 / 3
frame_height = int(icon_height / 2)
frame_ratio = 1
frame_width = int(round(frame_height * frame_ratio))
for i, frame in enumerate(frames):
frame_image = Image.open(frame)
@ -38,8 +37,9 @@ def render_list_icon(frames, icon):
frame_image = frame_image.resize((frame_width_, int(frame_width_ / frame_image_ratio)), Image.ANTIALIAS)
top = int((frame_image.size[1] - frame_height) / 2)
frame_image = frame_image.crop((0, top, frame_width_, top + frame_height))
icon_image.paste(frame_image, (i % 3 * frame_width + (1 if i % 2 == 2 else 0), int(i / 3) * frame_height))
mask_image = Image.open(ox.path.join(static_root, 'png', 'icon.mask.png'))
icon_image.paste(frame_image, (i % 2 * frame_width + (1 if i % 2 == 2 else 0),
int(i / 2) * frame_height))
mask_image = Image.open(os.path.join(static_root, 'png', 'iconMask.png'))
mask_image = mask_image.resize((icon_width, icon_height))
icon_image.putalpha(mask_image)
icon_image.save(icon)
@ -47,7 +47,7 @@ def render_list_icon(frames, icon):
def main():
parser = OptionParser()
parser.add_option('-f', '--frames', dest='frames', help='Poster frames (image files to be read)', default='')
parser.add_option('-i', '--icon', dest='icon', help='Icon (image file to be written)')
parser.add_option('-o', '--icon', dest='icon', help='Icon (image file to be written)')
(options, args) = parser.parse_args()
if options.icon == None:
parser.print_help()
@ -55,7 +55,7 @@ def main():
frames = options.frames.replace(', ', ',').split(',')
render_list_icon(frames, opt.icon)
render_list_icon(frames, options.icon)
if __name__ == "__main__":
main()

View file

@ -28,6 +28,7 @@ urlpatterns = patterns('',
(r'^file/(?P<oshash>.*)$', 'archive.views.lookup_file'),
(r'^api/$', include('api.urls')),
(r'', include('item.urls')),
(r'^list/(?P<id>.*?)/icon(?P<size>\d*).jpg$', 'itemlist.views.icon'),
(r'^robots.txt$', serve_static_file, {'location': os.path.join(settings.STATIC_ROOT, 'robots.txt'), 'content_type': 'text/plain'}),
(r'^favicon.ico$', serve_static_file, {'location': os.path.join(settings.STATIC_ROOT, 'png/icon.16.png'), 'content_type': 'image/x-icon'}),
)