forked from 0x2620/pandora
data/external_data, start properties for items and bin editing
This commit is contained in:
parent
67a31d1f58
commit
7f9a4e252e
4 changed files with 214 additions and 20 deletions
6
README
6
README
|
@ -30,9 +30,11 @@ Install rabbitmq and carrot:
|
||||||
Development:
|
Development:
|
||||||
we are using django, http://docs.djangoproject.com/en/dev/
|
we are using django, http://docs.djangoproject.com/en/dev/
|
||||||
|
|
||||||
|
Nginx setup:
|
||||||
|
sudo apt-get install nginx
|
||||||
|
|
||||||
Apache setup:
|
or if you use apache:
|
||||||
sudo apt-get install libapache2-mod-wsgi libapache2-mod-xsendfile
|
sudo apt-get install libapache2-mod-xsendfile
|
||||||
|
|
||||||
add pandora repository:
|
add pandora repository:
|
||||||
sudo apt-get install python-software-properties
|
sudo apt-get install python-software-properties
|
||||||
|
|
|
@ -9,6 +9,7 @@ from oxdjango.shortcuts import json_response, render_to_json_response, get_objec
|
||||||
import models
|
import models
|
||||||
|
|
||||||
from api.views import html_snapshot
|
from api.views import html_snapshot
|
||||||
|
from item.models import siteJson
|
||||||
|
|
||||||
def intro(request):
|
def intro(request):
|
||||||
context = RequestContext(request, {'settings':settings})
|
context = RequestContext(request, {'settings':settings})
|
||||||
|
@ -32,9 +33,11 @@ def api_getPage(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
|
|
||||||
def site_json(request):
|
def site_json(request):
|
||||||
|
return render_to_json_response(siteJson())
|
||||||
|
'''
|
||||||
siteSettings = {}
|
siteSettings = {}
|
||||||
for s in models.SiteSettings.objects.all():
|
for s in models.SiteSettings.objects.all():
|
||||||
siteSettings[s.key] = s.value
|
siteSettings[s.key] = s.value
|
||||||
context = RequestContext(request, {'settings':settings, 'siteSettings': siteSettings})
|
context = RequestContext(request, {'settings':settings, 'siteSettings': siteSettings})
|
||||||
return render_to_response('site.json', context, mimetype="application/javascript")
|
return render_to_response('site.json', context, mimetype="application/javascript")
|
||||||
|
'''
|
||||||
|
|
0
pandora/item/migrations/__init__.py
Normal file
0
pandora/item/migrations/__init__.py
Normal file
|
@ -29,6 +29,195 @@ import utils
|
||||||
from archive import extract
|
from archive import extract
|
||||||
|
|
||||||
|
|
||||||
|
class Property(models.Model):
|
||||||
|
name = models.CharField(null=True, max_length=255, unique=True)
|
||||||
|
title = models.CharField(null=True, max_length=255)
|
||||||
|
#types: string, person, role, location, date, array
|
||||||
|
type = models.CharField(null=True, max_length=255)
|
||||||
|
array = models.BooleanField(default=False)
|
||||||
|
position = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
#sort values: title, string, integer, float, date
|
||||||
|
sort = models.CharField(null=True, max_length=255)
|
||||||
|
|
||||||
|
totals = models.BooleanField(default=False)
|
||||||
|
admin = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
def json(self):
|
||||||
|
j = {}
|
||||||
|
for key in ('type', 'sort', 'title', 'array', 'totals', 'admin'):
|
||||||
|
value = getattr(self, key)
|
||||||
|
if value:
|
||||||
|
j[key] = value
|
||||||
|
return j
|
||||||
|
|
||||||
|
class Bin(models.Model):
|
||||||
|
name = models.CharField(null=True, max_length=255, unique=True)
|
||||||
|
title = models.CharField(null=True, max_length=255)
|
||||||
|
#types: keyword, location, text
|
||||||
|
type = models.CharField(null=True, max_length=255)
|
||||||
|
position = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
overlapping = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
find = models.BooleanField(default=True)
|
||||||
|
#words / item duration(wpm), total words, cuts per minute, cuts, number of layers, number of layers/duration
|
||||||
|
sort = models.CharField(null=True, max_length=255)
|
||||||
|
|
||||||
|
def properties(self):
|
||||||
|
p = {}
|
||||||
|
if self.find:
|
||||||
|
p[self.name] = {'type': 'bin', 'find': True}
|
||||||
|
if self.sort:
|
||||||
|
print 'FIXME: need to add sort stuff'
|
||||||
|
return p
|
||||||
|
|
||||||
|
properties = {
|
||||||
|
'title': {'type': 'string', 'sort': 'title', 'find': True},
|
||||||
|
'director': {'type': 'person', 'array': True, 'sort': 'string', 'find': True},
|
||||||
|
'country': {'type': 'string', 'array': True, 'sort': 'sring', 'find': True},
|
||||||
|
'year': {'type': 'string', 'sort': 'string', 'find': True},
|
||||||
|
'language': {'type': 'string', 'array': True, 'sort': 'string', 'find': True},
|
||||||
|
'runtime': {'type': 'integer', 'sort': 'integer'},
|
||||||
|
'writer': {'type': 'person', 'array': True, 'sort': 'string', 'find': True},
|
||||||
|
'producer': {'type': 'person', 'array': True, 'sort': 'string', 'find': True},
|
||||||
|
'cinematographer': {'type': 'person', 'array': True, 'sort': 'string', 'find': True},
|
||||||
|
'editor': {'type': 'person', 'array': True, 'sort': 'string', 'find': True},
|
||||||
|
'actors': {'type': 'role', 'array': True, 'sort': 'length', 'find': True},
|
||||||
|
'genre': {'type': 'string', 'array': True, 'sort': 'length', 'find': True},
|
||||||
|
'keywords': {'type': 'string', 'array': True, 'sort': 'length', 'find': True},
|
||||||
|
'summary': {'type': 'title', 'sort': 'length', 'find': True},
|
||||||
|
'trivia': {'type': 'title', 'sort': 'length', 'find': True},
|
||||||
|
'releasedate': {'type': 'date', 'sort': 'date', 'find': True},
|
||||||
|
'runtime': {'type': 'integer', 'sort': 'integer', 'totals': True},
|
||||||
|
|
||||||
|
'budget': {'type': 'float', 'sort': 'float'},
|
||||||
|
'gross': {'type': 'float', 'sort': 'float'},
|
||||||
|
'profit': {'type': 'float', 'sort': 'float'},
|
||||||
|
|
||||||
|
'rating': {'type': 'integer', 'sort': 'integer'},
|
||||||
|
'votes': {'type': 'integer', 'sort': 'integer'},
|
||||||
|
'published': {'type': 'date', 'sort': 'date'},
|
||||||
|
'modified': {'type': 'date', 'sort': 'date'},
|
||||||
|
'popularity': {'type': 'date', 'sort': 'date'},
|
||||||
|
|
||||||
|
#file properties // are those even configurable? think not
|
||||||
|
'aspectratio': {'type': 'faction', 'sort': 'float'},
|
||||||
|
'duration': {'type': 'float', 'sort': 'float', 'totals': True, "admin": True},
|
||||||
|
'color': {'type': 'color', 'sort': 'color'},
|
||||||
|
'saturation': {'type': 'integer', 'sort': 'integer'},
|
||||||
|
'brightness': {'type': 'integer', 'sort': 'integer'},
|
||||||
|
'volume': {'type': 'integer', 'sort': 'integer'},
|
||||||
|
'resolution': {'type': 'integer', 'array': True, 'sort': 'integer'}, #FIXME
|
||||||
|
'pixels': {'type': 'integer', 'sort': 'string', 'totals': True},
|
||||||
|
'size': {'type': 'title', 'sort': 'string', 'totals': True, 'admin': True},
|
||||||
|
'bitrate': {'type': 'title', 'sort': 'string'},
|
||||||
|
'files': {'type': 'title', 'sort': 'string', 'totals': True, 'admin': True},
|
||||||
|
'filename': {'type': 'title', 'sort': 'string'},
|
||||||
|
|
||||||
|
#Layer properties // those need to be defined with bins
|
||||||
|
'dialog': {'type': 'title', 'find': True},
|
||||||
|
#'clips': {'type': 'title', 'sort': 'string'},
|
||||||
|
#'cuts': {'type': 'title', 'sort': 'string'},
|
||||||
|
'cutsperminute': {'type': 'integer', 'title': 'Cuts per minute', 'sort': 'string'},
|
||||||
|
'words': {'type': 'title', 'sort': 'string'},
|
||||||
|
'wordsperminute': {'type': 'integer','title': 'Words per minute', 'sort': 'string'},
|
||||||
|
}
|
||||||
|
|
||||||
|
def siteJson():
|
||||||
|
r = {}
|
||||||
|
r['findKeys'] = [{"id": "all", "title": "All"}]
|
||||||
|
for k in properties:
|
||||||
|
i = properties[k]
|
||||||
|
if i.get('find', False):
|
||||||
|
f = {"id": k, "title": i.get('title', k.capitalize())}
|
||||||
|
if i.get('autocomplete', False):
|
||||||
|
f['autocomplete'] = True
|
||||||
|
r['findKeys'].append(f)
|
||||||
|
r['groups'] = filter(lambda k: 'array' in properties[k], properties.keys())
|
||||||
|
r['itemViews'] = [
|
||||||
|
{"id": "info", "title": "Info"},
|
||||||
|
{"id": "statistics", "title": "Statistics"},
|
||||||
|
{"id": "clips", "title": "Clips"},
|
||||||
|
{"id": "timeline", "title": "Timeline"},
|
||||||
|
{"id": "map", "title": "Map"},
|
||||||
|
{"id": "calendar", "title": "Calendar"},
|
||||||
|
{"id": "files", "title": "Files", "admin": True}
|
||||||
|
]
|
||||||
|
r['listViews'] = [
|
||||||
|
{"id": "list", "title": "as List"},
|
||||||
|
{"id": "icons", "title": "as Icons"},
|
||||||
|
{"id": "info", "title": "with Info"},
|
||||||
|
{"id": "clips", "title": "with Clips"},
|
||||||
|
{"id": "timelines", "title": "with Timelines"},
|
||||||
|
{"id": "maps", "title": "with Maps"},
|
||||||
|
{"id": "calendars", "title": "with Calendars"},
|
||||||
|
{"id": "clip", "title": "as Clips"},
|
||||||
|
{"id": "map", "title": "on Map"},
|
||||||
|
{"id": "calendar", "title": "on Calendar"}
|
||||||
|
]
|
||||||
|
r['site'] = {
|
||||||
|
"name": settings.SITENAME,
|
||||||
|
"id": settings.SITEID,
|
||||||
|
"url": settings.URL
|
||||||
|
}
|
||||||
|
r['sections'] = [
|
||||||
|
{"id": "history", "title": "History"},
|
||||||
|
{"id": "lists", "title": "My Lists"},
|
||||||
|
{"id": "public", "title": "Public Lists"},
|
||||||
|
{"id": "featured", "title": "Featured Lists"}
|
||||||
|
]
|
||||||
|
r['sortKeys'] = []
|
||||||
|
for k in properties:
|
||||||
|
i = properties[k]
|
||||||
|
if 'sort' in i:
|
||||||
|
f = {
|
||||||
|
"id": k,
|
||||||
|
"title": i.get('title', k.capitalize()),
|
||||||
|
"operator": i.get('operator', ''),
|
||||||
|
"align": i.get('align', 'left'),
|
||||||
|
"width": i.get('width', 180),
|
||||||
|
}
|
||||||
|
if not i.get('removable', True):
|
||||||
|
f['removable'] = False
|
||||||
|
r['sortKeys'].append(f)
|
||||||
|
|
||||||
|
r['totals'] = [{"id": "items"}]
|
||||||
|
for k in properties:
|
||||||
|
i = properties[k]
|
||||||
|
if i.get('totals', False):
|
||||||
|
f = {"id": k}
|
||||||
|
if i.get('admin', False):
|
||||||
|
f['admin'] = True
|
||||||
|
r['totals'].append(f)
|
||||||
|
|
||||||
|
#FIXME: defaults should also be populated from properties
|
||||||
|
r["user"] = {
|
||||||
|
"group": "guest",
|
||||||
|
"preferences": {},
|
||||||
|
"ui": {
|
||||||
|
"columns": ["id", "title", "director", "country", "year", "language", "genre"],
|
||||||
|
"findQuery": {"conditions": [], "operator": ""},
|
||||||
|
"groupsQuery": {"conditions": [], "operator": "|"},
|
||||||
|
"groupsSize": 128,
|
||||||
|
"itemView": "info",
|
||||||
|
"listQuery": {"conditions": [], "operator": ""},
|
||||||
|
"listsSize": 192,
|
||||||
|
"listView": "list",
|
||||||
|
"sections": ["history", "lists", "public", "featured"],
|
||||||
|
"showGroups": True,
|
||||||
|
"showInfo": True,
|
||||||
|
"showLists": True,
|
||||||
|
"showMovies": True,
|
||||||
|
"sort": [
|
||||||
|
{"key": "director", "operator": ""}
|
||||||
|
],
|
||||||
|
"theme": "classic"
|
||||||
|
},
|
||||||
|
"username": ""
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
|
||||||
def getItem(info):
|
def getItem(info):
|
||||||
'''
|
'''
|
||||||
info dict with:
|
info dict with:
|
||||||
|
@ -40,7 +229,7 @@ def getItem(info):
|
||||||
except Item.DoesNotExist:
|
except Item.DoesNotExist:
|
||||||
item = Item(itemId=info['imdbId'])
|
item = Item(itemId=info['imdbId'])
|
||||||
if 'title' in info and 'directors' in info:
|
if 'title' in info and 'directors' in info:
|
||||||
item.imdb = {
|
item.external_data = {
|
||||||
'title': info['title'],
|
'title': info['title'],
|
||||||
'directors': info['directors'],
|
'directors': info['directors'],
|
||||||
'year': info.get('year', '')
|
'year': info.get('year', '')
|
||||||
|
@ -59,7 +248,7 @@ def getItem(info):
|
||||||
item = Item.objects.get(itemId=info['oxdbId'])
|
item = Item.objects.get(itemId=info['oxdbId'])
|
||||||
except Item.DoesNotExist:
|
except Item.DoesNotExist:
|
||||||
item = Item()
|
item = Item()
|
||||||
item.metadata = {
|
item.data = {
|
||||||
'title': info['title'],
|
'title': info['title'],
|
||||||
'directors': info['directors'],
|
'directors': info['directors'],
|
||||||
'year': info.get('year', '')
|
'year': info.get('year', '')
|
||||||
|
@ -68,7 +257,7 @@ def getItem(info):
|
||||||
|
|
||||||
for key in ('episode_title', 'series_title', 'season', 'episode'):
|
for key in ('episode_title', 'series_title', 'season', 'episode'):
|
||||||
if key in info and info[key]:
|
if key in info and info[key]:
|
||||||
item.metadata[key] = info[key]
|
item.data[key] = info[key]
|
||||||
item.save()
|
item.save()
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
@ -80,7 +269,7 @@ class Item(models.Model):
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
published = models.DateTimeField(default=datetime.now, editable=False)
|
published = models.DateTimeField(default=datetime.now, editable=False)
|
||||||
|
|
||||||
#only items that have metadata from files are available,
|
#only items that have data from files are available,
|
||||||
#this is indicated by setting available to True
|
#this is indicated by setting available to True
|
||||||
available = models.BooleanField(default=False, db_index=True)
|
available = models.BooleanField(default=False, db_index=True)
|
||||||
|
|
||||||
|
@ -90,10 +279,10 @@ class Item(models.Model):
|
||||||
objects = managers.ItemManager()
|
objects = managers.ItemManager()
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
if self.metadata and key in self.metadata:
|
if self.data and key in self.data:
|
||||||
return self.metadata[key]
|
return self.data[key]
|
||||||
if self.imdb and key in self.imdb:
|
if self.external_data and key in self.external_data:
|
||||||
return self.imdb[key]
|
return self.external_data[key]
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def editable(self, user):
|
def editable(self, user):
|
||||||
|
@ -104,7 +293,7 @@ class Item(models.Model):
|
||||||
#FIXME: how to map the keys to the right place to write them to?
|
#FIXME: how to map the keys to the right place to write them to?
|
||||||
for key in data:
|
for key in data:
|
||||||
if key != 'id':
|
if key != 'id':
|
||||||
setattr(self.metadata, key, data[key])
|
setattr(self.data, key, data[key])
|
||||||
self.oxdb.save()
|
self.oxdb.save()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
@ -118,14 +307,14 @@ class Item(models.Model):
|
||||||
_reviews[w.title] = r[0]
|
_reviews[w.title] = r[0]
|
||||||
return _reviews
|
return _reviews
|
||||||
|
|
||||||
imdb = fields.DictField(default={}, editable=False)
|
external_data = fields.DictField(default={}, editable=False)
|
||||||
metadata = fields.DictField(default={}, editable=False)
|
data = fields.DictField(default={}, editable=False)
|
||||||
|
|
||||||
json = fields.DictField(default={}, editable=False)
|
json = fields.DictField(default={}, editable=False)
|
||||||
|
|
||||||
def updateImdb(self):
|
def updateImdb(self):
|
||||||
if len(self.itemId) == 7:
|
if len(self.itemId) == 7:
|
||||||
self.imdb = ox.web.imdb.Imdb(self.itemId)
|
self.external_data = ox.web.imdb.Imdb(self.itemId)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
poster = models.ImageField(default=None, blank=True, upload_to=lambda m, x: os.path.join(itemid_path(m.itemId), "poster.jpg"))
|
poster = models.ImageField(default=None, blank=True, upload_to=lambda m, x: os.path.join(itemid_path(m.itemId), "poster.jpg"))
|
||||||
|
@ -272,7 +461,7 @@ class Item(models.Model):
|
||||||
|
|
||||||
def get_layers(self):
|
def get_layers(self):
|
||||||
layers = {}
|
layers = {}
|
||||||
layers['cuts'] = self.metadata.get('cuts', {})
|
layers['cuts'] = self.data.get('cuts', {})
|
||||||
|
|
||||||
layers['subtitles'] = {}
|
layers['subtitles'] = {}
|
||||||
#FIXME: subtitles should be stored in Layer
|
#FIXME: subtitles should be stored in Layer
|
||||||
|
@ -491,9 +680,9 @@ class Item(models.Model):
|
||||||
if 'video' in stream.info:
|
if 'video' in stream.info:
|
||||||
extract.timeline(stream.video.path, self.timeline_prefix)
|
extract.timeline(stream.video.path, self.timeline_prefix)
|
||||||
self.stream_aspect = stream.info['video'][0]['width']/stream.info['video'][0]['height']
|
self.stream_aspect = stream.info['video'][0]['width']/stream.info['video'][0]['height']
|
||||||
self.metadata['cuts'] = extract.cuts(self.timeline_prefix)
|
self.data['cuts'] = extract.cuts(self.timeline_prefix)
|
||||||
self.metadata['average_color'] = extract.average_color(self.timeline_prefix)
|
self.data['average_color'] = extract.average_color(self.timeline_prefix)
|
||||||
#extract.timeline_strip(self, self.metadata['cuts'], stream.info, self.timeline_prefix[:-8])
|
#extract.timeline_strip(self, self.data['cuts'], stream.info, self.timeline_prefix[:-8])
|
||||||
|
|
||||||
stream.extract_derivatives()
|
stream.extract_derivatives()
|
||||||
#something with poster
|
#something with poster
|
||||||
|
@ -683,7 +872,7 @@ class Facet(models.Model):
|
||||||
|
|
||||||
def getPersonSort(name):
|
def getPersonSort(name):
|
||||||
person, created = Person.objects.get_or_create(name=name)
|
person, created = Person.objects.get_or_create(name=name)
|
||||||
name_sort = person.name_sort.replace(u'\xc5k', 'A')
|
name_sort = unicodedata.normalize('NFKD', person.name_sort)
|
||||||
return name_sort
|
return name_sort
|
||||||
|
|
||||||
class Person(models.Model):
|
class Person(models.Model):
|
||||||
|
|
Loading…
Reference in a new issue