forked from 0x2620/pandora
better demo config and info view
always pass oxdbId to poster script use 0xdb like poster script for demo
This commit is contained in:
parent
e4d0660074
commit
70892dd463
9 changed files with 183 additions and 316 deletions
|
@ -62,7 +62,7 @@ def reloader_thread():
|
||||||
load_config()
|
load_config()
|
||||||
_config_mtime = mtime
|
_config_mtime = mtime
|
||||||
except:
|
except:
|
||||||
print "reloading config failed"
|
sys.stderr.write("reloading config failed\n")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
def update_static():
|
def update_static():
|
||||||
|
|
|
@ -112,7 +112,7 @@ def getPage(request):
|
||||||
name = data['name']
|
name = data['name']
|
||||||
page, created = models.Page.objects.get_or_create(name=name)
|
page, created = models.Page.objects.get_or_create(name=name)
|
||||||
if created:
|
if created:
|
||||||
page.text= 'Insert text here'
|
page.text= ''
|
||||||
page.save()
|
page.save()
|
||||||
response = json_response({'name': page.name, 'text': page.text})
|
response = json_response({'name': page.name, 'text': page.text})
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
{"key": "title", "operator": "+"}
|
{"key": "title", "operator": "+"}
|
||||||
],
|
],
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"showUsers": true
|
"showUsers": false
|
||||||
},
|
},
|
||||||
"cantPlay": {
|
"cantPlay": {
|
||||||
"icon": "",
|
"icon": "",
|
||||||
|
@ -66,17 +66,14 @@
|
||||||
text of clips. Excluding a layer from this list means it will not be
|
text of clips. Excluding a layer from this list means it will not be
|
||||||
included in find annotations. // FIXME: the last bit is not implemented.
|
included in find annotations. // FIXME: the last bit is not implemented.
|
||||||
*/
|
*/
|
||||||
"clipLayers": ["transcripts", "keywords", "places", "events", "descriptions"],
|
"clipLayers": ["publicnotes", "keywords", "subtitles"],
|
||||||
// fixme: either this, or filter: true in itemKeys, but not both
|
// fixme: either this, or filter: true in itemKeys, but not both
|
||||||
"filters": [
|
"filters": [
|
||||||
{"id": "source", "title": "Sources", "type": "string"},
|
{"id": "director", "title": "Director", "type": "string"},
|
||||||
{"id": "project", "title": "Projects", "type": "string"},
|
{"id": "country", "title": "Country", "type": "string"},
|
||||||
{"id": "topic", "title": "Topics", "type": "string"},
|
{"id": "year", "title": "Year", "type": "integer"},
|
||||||
{"id": "name", "title": "People", "type": "string"},
|
|
||||||
{"id": "language", "title": "Languages", "type": "string"},
|
{"id": "language", "title": "Languages", "type": "string"},
|
||||||
{"id": "license", "title": "License", "type": "string"},
|
{"id": "featuring", "title": "Featuring", "type": "string"},
|
||||||
{"id": "places", "title": "Places", "type": "string"},
|
|
||||||
{"id": "events", "title": "Events", "type": "string"},
|
|
||||||
{"id": "keywords", "title": "Keywords", "type": "string"}
|
{"id": "keywords", "title": "Keywords", "type": "string"}
|
||||||
],
|
],
|
||||||
/*
|
/*
|
||||||
|
@ -120,41 +117,9 @@
|
||||||
"sort": true,
|
"sort": true,
|
||||||
"sortType": "title"
|
"sortType": "title"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "source",
|
|
||||||
"title": "Source",
|
|
||||||
"type": "string",
|
|
||||||
"autocomplete": true,
|
|
||||||
"description": true,
|
|
||||||
"columnWidth": 180,
|
|
||||||
"filter": true,
|
|
||||||
"find": true,
|
|
||||||
"sort": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "project",
|
|
||||||
"title": "Project",
|
|
||||||
"type": "string",
|
|
||||||
"autocomplete": true,
|
|
||||||
"description": true,
|
|
||||||
"columnWidth": 120,
|
|
||||||
"filter": true,
|
|
||||||
"find": true,
|
|
||||||
"sort": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "topic",
|
|
||||||
"title": "Topic",
|
|
||||||
"type": ["string"],
|
|
||||||
"autocomplete": true,
|
|
||||||
"columnWidth": 180,
|
|
||||||
"filter": true,
|
|
||||||
"find": true,
|
|
||||||
"sort": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "name",
|
"id": "name",
|
||||||
"title": "People",
|
"title": "Name",
|
||||||
"type": ["string"],
|
"type": ["string"],
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"find": true
|
"find": true
|
||||||
|
@ -169,15 +134,6 @@
|
||||||
"sort": true,
|
"sort": true,
|
||||||
"sortType": "person"
|
"sortType": "person"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "cinematographer",
|
|
||||||
"title": "Cinematographer",
|
|
||||||
"type": ["string"],
|
|
||||||
"autocomplete": true,
|
|
||||||
"columnWidth": 180,
|
|
||||||
"sort": true,
|
|
||||||
"sortType": "person"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "featuring",
|
"id": "featuring",
|
||||||
"title": "Featuring",
|
"title": "Featuring",
|
||||||
|
@ -200,8 +156,8 @@
|
||||||
"sort": true
|
"sort": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "location",
|
"id": "country",
|
||||||
"title": "Location",
|
"title": "Contry",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"columnWidth": 180,
|
"columnWidth": 180,
|
||||||
|
@ -210,11 +166,14 @@
|
||||||
"sort": true
|
"sort": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "date",
|
"id": "year",
|
||||||
"title": "Date",
|
"title": "Year",
|
||||||
"type": "string",
|
"type": "year",
|
||||||
"columnWidth": 120,
|
"additionalSort": [{"key": "director", "operator": "+"}, {"key": "title", "operator": "+"}],
|
||||||
//"format": {"type": "date", "args": ["%a, %b %e, %Y"]},
|
"autocomplete": true,
|
||||||
|
"columnWidth": 60,
|
||||||
|
"filter": true,
|
||||||
|
"find": true,
|
||||||
"sort": true
|
"sort": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -230,24 +189,6 @@
|
||||||
"columnWidth": 90,
|
"columnWidth": 90,
|
||||||
"sort": true
|
"sort": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "annotations",
|
|
||||||
"title": "Annotations",
|
|
||||||
"type": "string",
|
|
||||||
"find": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "places",
|
|
||||||
"title": "Places",
|
|
||||||
"type": "layer",
|
|
||||||
"find": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "events",
|
|
||||||
"title": "Events",
|
|
||||||
"type": "layer",
|
|
||||||
"find": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "keywords",
|
"id": "keywords",
|
||||||
"title": "Keywords",
|
"title": "Keywords",
|
||||||
|
@ -255,14 +196,14 @@
|
||||||
"find": true
|
"find": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "descriptions",
|
"id": "subtitles",
|
||||||
"title": "Descriptions",
|
"title": "Subtitles",
|
||||||
"type": "layer",
|
"type": "layer",
|
||||||
"find": true
|
"find": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "transcripts",
|
"id": "publicnotes",
|
||||||
"title": "Transcripts",
|
"title": "Notes",
|
||||||
"type": "layer",
|
"type": "layer",
|
||||||
"find": true
|
"find": true
|
||||||
},
|
},
|
||||||
|
@ -405,14 +346,7 @@
|
||||||
"title": "User",
|
"title": "User",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"capability": "canSeeFiles",
|
"capability": "canSeeFiles",
|
||||||
"find": true
|
"find": false
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "filename",
|
|
||||||
"title": "Filename",
|
|
||||||
"type": ["string"],
|
|
||||||
"capability": "canSeeFiles",
|
|
||||||
"find": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "created",
|
"id": "created",
|
||||||
|
@ -448,14 +382,6 @@
|
||||||
"format": {"type": "date", "args": ["%Y-%m-%d %H:%M:%S"]},
|
"format": {"type": "date", "args": ["%Y-%m-%d %H:%M:%S"]},
|
||||||
"sort": true
|
"sort": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "license",
|
|
||||||
"title": "License",
|
|
||||||
"type": ["string"],
|
|
||||||
"columnWidth": 120,
|
|
||||||
"filter": true,
|
|
||||||
"sort": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "rightslevel",
|
"id": "rightslevel",
|
||||||
"title": "Rights Level",
|
"title": "Rights Level",
|
||||||
|
@ -492,43 +418,44 @@
|
||||||
],
|
],
|
||||||
"layers": [
|
"layers": [
|
||||||
{
|
{
|
||||||
"id": "places",
|
"id": "privatenotes",
|
||||||
"title": "Places",
|
"title": "Private Notes",
|
||||||
"canAddAnnotations": {"member": true, "staff": true, "admin": true},
|
"canAddAnnotations": {"member": true, "staff": true, "admin": true},
|
||||||
"item": "Place",
|
"item": "Note",
|
||||||
"overlap": true,
|
"overlap": true,
|
||||||
"type": "place"
|
"private": true,
|
||||||
|
"showInfo": true,
|
||||||
|
"type": "text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "events",
|
"id": "publicnotes",
|
||||||
"title": "Events",
|
"title": "Notes",
|
||||||
"canAddAnnotations": {"member": true, "staff": true, "admin": true},
|
"canAddAnnotations": {"member": true, "staff": true, "admin": true},
|
||||||
"item": "Event",
|
"hasEvents": true,
|
||||||
|
"hasPlaces": true,
|
||||||
|
"item": "Note",
|
||||||
"overlap": true,
|
"overlap": true,
|
||||||
"type": "event"
|
"showInfo": true,
|
||||||
|
"type": "text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "keywords",
|
"id": "keywords",
|
||||||
"title": "Keywords",
|
"title": "Keywords",
|
||||||
"canAddAnnotations": {"member": true, "staff": true, "admin": true},
|
"canAddAnnotations": {"member": true, "staff": true, "admin": true},
|
||||||
|
"hasEvents": true,
|
||||||
|
"hasPlaces": true,
|
||||||
"item": "Keyword",
|
"item": "Keyword",
|
||||||
"overlap": true,
|
"overlap": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "descriptions",
|
"id": "subtitles",
|
||||||
"title": "Descriptions",
|
"title": "Subtitles",
|
||||||
"canAddAnnotations": {"member": true, "staff": true, "admin": true},
|
"canAddAnnotations": {"staff": true, "admin": true},
|
||||||
"item": "Description",
|
"hasEvents": true,
|
||||||
"showInfo": true,
|
"hasPlaces": true,
|
||||||
"type": "text"
|
"isSubtitles": true,
|
||||||
},
|
"item": "Subtitle",
|
||||||
{
|
|
||||||
"id": "transcripts",
|
|
||||||
"title": "Transcripts",
|
|
||||||
"canAddAnnotations": {"member": true, "staff": true, "admin": true},
|
|
||||||
"item": "Transcript",
|
|
||||||
"showInfo": true,
|
|
||||||
"type": "text"
|
"type": "text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -570,7 +497,7 @@
|
||||||
"system": "system@pandora.local"
|
"system": "system@pandora.local"
|
||||||
},
|
},
|
||||||
"id": "pandora",
|
"id": "pandora",
|
||||||
"name": "pan.do/ra",
|
"name": "Demo",
|
||||||
"url": "pandora.local",
|
"url": "pandora.local",
|
||||||
"videoprefix": ""
|
"videoprefix": ""
|
||||||
},
|
},
|
||||||
|
@ -605,34 +532,33 @@
|
||||||
"annotationsCalendarSize": 128,
|
"annotationsCalendarSize": 128,
|
||||||
"annotationsFont": "small",
|
"annotationsFont": "small",
|
||||||
"annotationsMapSize": 128,
|
"annotationsMapSize": 128,
|
||||||
"annotationsRange": "position",
|
"annotationsRange": "all",
|
||||||
"annotationsSize": 256,
|
"annotationsSize": 256,
|
||||||
"annotationsSort": "position",
|
"annotationsSort": "position",
|
||||||
"clipsColumns": 2,
|
"clipsColumns": 2,
|
||||||
"columns": {
|
"columns": {
|
||||||
"Colors": {
|
"Colors": {
|
||||||
"columns": ["title", "source", "project", "language", "hue", "saturation", "brightness"],
|
"columns": ["title", "director", "language", "hue", "saturation", "brightness"],
|
||||||
"columnWidth": {}
|
"columnWidth": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"filters": [
|
"filters": [
|
||||||
{"id": "source", "sort": [{"key": "name", "operator": "+"}]},
|
{"id": "director", "sort": [{"key": "items", "operator": "-"}]},
|
||||||
{"id": "project", "sort": [{"key": "name", "operator": "+"}]},
|
{"id": "country", "sort": [{"key": "items", "operator": "-"}]},
|
||||||
{"id": "topic", "sort": [{"key": "items", "operator": "-"}]},
|
{"id": "year", "sort": [{"key": "name", "operator": "+"}]},
|
||||||
{"id": "name", "sort": [{"key": "items", "operator": "-"}]},
|
{"id": "featuring", "sort": [{"key": "items", "operator": "-"}]},
|
||||||
{"id": "keywords", "sort": [{"key": "items", "operator": "-"}]},
|
{"id": "keywords", "sort": [{"key": "items", "operator": "-"}]}
|
||||||
{"id": "places", "sort": [{"key": "items", "operator": "-"}]}
|
|
||||||
],
|
],
|
||||||
"filtersSize": 176,
|
"filtersSize": 176,
|
||||||
"find": {"conditions": [], "operator": "&"},
|
"find": {"conditions": [], "operator": "&"},
|
||||||
"followPlayer": true,
|
"followPlayer": true,
|
||||||
"icons": "frames",
|
"icons": "posters",
|
||||||
"infoIconSize": 256,
|
"infoIconSize": 256,
|
||||||
"item": "",
|
"item": "",
|
||||||
"itemFind": "",
|
"itemFind": "",
|
||||||
"itemSort": [{"key": "position", "operator": "+"}],
|
"itemSort": [{"key": "position", "operator": "+"}],
|
||||||
"itemView": "info",
|
"itemView": "info",
|
||||||
"listColumns": ["title", "source", "project", "topic", "language", "duration"],
|
"listColumns": ["title", "director", "year", "language", "duration"],
|
||||||
"listColumnWidth": {},
|
"listColumnWidth": {},
|
||||||
"listSelection": [],
|
"listSelection": [],
|
||||||
"listSort": [{"key": "title", "operator": "+"}],
|
"listSort": [{"key": "title", "operator": "+"}],
|
||||||
|
@ -655,11 +581,10 @@
|
||||||
"showIconBrowser": false,
|
"showIconBrowser": false,
|
||||||
"showInfo": true,
|
"showInfo": true,
|
||||||
"showLayers": {
|
"showLayers": {
|
||||||
"places": false,
|
|
||||||
"events": false,
|
|
||||||
"keywords": true,
|
"keywords": true,
|
||||||
"descriptions": true,
|
"privatenotes": true,
|
||||||
"transcripts": true
|
"publicnotes": true,
|
||||||
|
"subtitles": true
|
||||||
},
|
},
|
||||||
"showMapControls": false,
|
"showMapControls": false,
|
||||||
"showMapLabels": false,
|
"showMapLabels": false,
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Command(BaseCommand):
|
||||||
for f in models.ItemSort._meta.fields:
|
for f in models.ItemSort._meta.fields:
|
||||||
if not f.primary_key:
|
if not f.primary_key:
|
||||||
name = f.name
|
name = f.name
|
||||||
col_type = f.db_type()
|
col_type = f.db_type(connection)
|
||||||
if name not in db_fields:
|
if name not in db_fields:
|
||||||
sql = 'ALTER TABLE "%s" ADD COLUMN "%s" %s' % (table_name, name, col_type)
|
sql = 'ALTER TABLE "%s" ADD COLUMN "%s" %s' % (table_name, name, col_type)
|
||||||
changes.append(sql)
|
changes.append(sql)
|
||||||
|
|
|
@ -314,7 +314,10 @@ class Item(models.Model):
|
||||||
|
|
||||||
#this does not work if another item without imdbid has the same metadata
|
#this does not work if another item without imdbid has the same metadata
|
||||||
oxdbId = self.oxdb_id()
|
oxdbId = self.oxdb_id()
|
||||||
if oxdbId:
|
if not settings.USE_IMDB:
|
||||||
|
update_poster = self.oxdbId != oxdbId
|
||||||
|
self.oxdbId = oxdbId
|
||||||
|
elif oxdbId:
|
||||||
if self.oxdbId != oxdbId:
|
if self.oxdbId != oxdbId:
|
||||||
q = Item.objects.filter(oxdbId=oxdbId).exclude(id=self.id)
|
q = Item.objects.filter(oxdbId=oxdbId).exclude(id=self.id)
|
||||||
if q.count() != 0:
|
if q.count() != 0:
|
||||||
|
@ -554,10 +557,8 @@ class Item(models.Model):
|
||||||
return i
|
return i
|
||||||
|
|
||||||
def oxdb_id(self):
|
def oxdb_id(self):
|
||||||
if not settings.USE_IMDB:
|
|
||||||
return self.itemId
|
|
||||||
if not self.get('title') and not self.get('director'):
|
if not self.get('title') and not self.get('director'):
|
||||||
return None
|
return self.itemId
|
||||||
return ox.get_oxid(self.get('seriesTitle', self.get('title', '')),
|
return ox.get_oxid(self.get('seriesTitle', self.get('title', '')),
|
||||||
self.get('director', []),
|
self.get('director', []),
|
||||||
self.get('seriesYear', self.get('year', '')),
|
self.get('seriesYear', self.get('year', '')),
|
||||||
|
@ -1128,13 +1129,10 @@ class Item(models.Model):
|
||||||
cmd += [
|
cmd += [
|
||||||
'-l', timeline,
|
'-l', timeline,
|
||||||
]
|
]
|
||||||
if settings.USE_IMDB:
|
cmd += [
|
||||||
if len(self.itemId) == 7:
|
'-i', self.itemId,
|
||||||
cmd += ['-i', self.itemId]
|
'-o', self.oxdbId or self.oxdb_id() or self.itemId
|
||||||
oxdbId = self.oxdbId or self.oxdb_id() or self.itemId
|
]
|
||||||
cmd += ['-o', oxdbId]
|
|
||||||
else:
|
|
||||||
cmd += ['-i', self.itemId]
|
|
||||||
ox.makedirs(os.path.join(settings.MEDIA_ROOT,self.path()))
|
ox.makedirs(os.path.join(settings.MEDIA_ROOT,self.path()))
|
||||||
p = subprocess.Popen(cmd)
|
p = subprocess.Popen(cmd)
|
||||||
p.wait()
|
p.wait()
|
||||||
|
|
|
@ -129,7 +129,7 @@ def render_poster(title, director, year, series, oxdb_id, imdb_id, frame, timeli
|
||||||
def main():
|
def main():
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
parser.add_option('-o', '--oxdbid', dest='oxdb_id', help='0xDB Id')
|
parser.add_option('-o', '--oxdbid', dest='oxdb_id', help='0xDB Id')
|
||||||
parser.add_option('-i', '--id', dest='imdb_id', help='Item Id')
|
parser.add_option('-i', '--id', dest='item_id', help='Item Id')
|
||||||
parser.add_option('-t', '--title', dest='title', help='Title')
|
parser.add_option('-t', '--title', dest='title', help='Title')
|
||||||
parser.add_option('-d', '--director', dest='director', help='Director(s)', default='')
|
parser.add_option('-d', '--director', dest='director', help='Director(s)', default='')
|
||||||
parser.add_option('-y', '--year', dest='year', help='Year')
|
parser.add_option('-y', '--year', dest='year', help='Year')
|
||||||
|
@ -144,7 +144,7 @@ def main():
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
opt = {}
|
opt = {}
|
||||||
for key in ('oxdb_id', 'imdb_id', 'title', 'director', 'year', 'series', 'frame', 'timeline', 'poster'):
|
for key in ('oxdb_id', 'item_id', 'title', 'director', 'year', 'series', 'frame', 'timeline', 'poster'):
|
||||||
opt[key] = getattr(options, key)
|
opt[key] = getattr(options, key)
|
||||||
|
|
||||||
opt['title'] = opt['title'].decode('utf-8')
|
opt['title'] = opt['title'].decode('utf-8')
|
||||||
|
|
|
@ -16,68 +16,140 @@ from optparse import OptionParser
|
||||||
from ox.image import drawText, wrapText
|
from ox.image import drawText, wrapText
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
static_root = os.path.join(os.path.dirname(__file__), 'data')
|
static_root = os.path.join(os.path.dirname(__file__), 'data')
|
||||||
|
|
||||||
def render_poster(id, title, frame, timeline, poster):
|
def render_poster(title, director, year, series, oxdb_id, imdb_id, frame, timeline, poster):
|
||||||
|
def get_oxdb_color(oxdb_id, series=False):
|
||||||
|
i = int(round((int(oxdb_id[2:10], 16) * 762 / pow(2, 32))))
|
||||||
|
if i < 127:
|
||||||
|
color = (127, i, 0)
|
||||||
|
elif i < 254:
|
||||||
|
color = (254 - i, 127, 0)
|
||||||
|
elif i < 381:
|
||||||
|
color = (0, 127, i - 254)
|
||||||
|
elif i < 508:
|
||||||
|
color = (0, 508 - i, 127)
|
||||||
|
elif i < 635:
|
||||||
|
color = (i - 508, 0, 127)
|
||||||
|
else:
|
||||||
|
color = (127, 0, 762 - i)
|
||||||
|
if series:
|
||||||
|
color = tuple(map(lambda x: x + 128, color))
|
||||||
|
return color
|
||||||
|
|
||||||
poster_width = 640
|
poster_width = 640
|
||||||
poster_height = 1024
|
poster_height = 1024
|
||||||
poster_ratio = poster_width / poster_height
|
poster_ratio = poster_width / poster_height
|
||||||
poster_color = (255, 255, 0)
|
|
||||||
poster_image = Image.new('RGB', (poster_width, poster_height))
|
poster_image = Image.new('RGB', (poster_width, poster_height))
|
||||||
|
draw = ImageDraw.Draw(poster_image)
|
||||||
font_file = os.path.join(static_root, 'DejaVuSansCondensedBold.ttf')
|
font_file = os.path.join(static_root, 'DejaVuSansCondensedBold.ttf')
|
||||||
font_size = 48
|
|
||||||
|
font_size = {
|
||||||
|
'small': 28,
|
||||||
|
'large': 42,
|
||||||
|
}
|
||||||
|
|
||||||
|
# frame
|
||||||
|
frame_width = poster_width
|
||||||
|
frame_ratio = 4 / 3
|
||||||
|
frame_height = int(round(frame_width / frame_ratio))
|
||||||
|
if frame:
|
||||||
|
frame_image = Image.open(frame)
|
||||||
|
frame_image_ratio = frame_image.size[0] / frame_image.size[1]
|
||||||
|
if frame_ratio < frame_image_ratio:
|
||||||
|
frame_image = frame_image.resize((int(frame_height * frame_image_ratio), frame_height), Image.ANTIALIAS)
|
||||||
|
left = int((frame_image.size[0] - frame_width) / 2)
|
||||||
|
frame_image = frame_image.crop((left, 0, left + frame_width, frame_height))
|
||||||
|
else:
|
||||||
|
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))
|
||||||
|
poster_image.paste(frame_image, (0, 0))
|
||||||
|
|
||||||
# timeline
|
# timeline
|
||||||
|
timeline_width = poster_width
|
||||||
timeline_height = 64
|
timeline_height = 64
|
||||||
timeline_lines = 16
|
|
||||||
if timeline:
|
if timeline:
|
||||||
timeline_image = Image.open(timeline)
|
timeline_image = Image.open(timeline)
|
||||||
timeline_image = timeline_image.resize((10240, timeline_height), Image.ANTIALIAS)
|
timeline_image = timeline_image.resize((timeline_width, timeline_height), Image.ANTIALIAS)
|
||||||
for i in range(timeline_lines):
|
poster_image.paste(timeline_image, (0, frame_height))
|
||||||
line_image = timeline_image.crop((i * poster_width, 0, (i + 1) * poster_width, 64))
|
|
||||||
poster_image.paste(line_image, (0, i * timeline_height))
|
|
||||||
|
|
||||||
# id
|
# text
|
||||||
text = '' + id
|
|
||||||
text_image = Image.new('RGB', (1, 1))
|
|
||||||
text_size = drawText(text_image, (0, 0), text, font_file, font_size, poster_color)
|
|
||||||
text_width = poster_width
|
text_width = poster_width
|
||||||
text_height = timeline_height
|
text_height = poster_height - frame_height - timeline_height
|
||||||
text_left = int((poster_width - text_width) / 2)
|
text_top = frame_height + timeline_height
|
||||||
text_top = 14 * timeline_height
|
text_bottom = text_top + text_height
|
||||||
for y in range(text_top, text_top + text_height):
|
text_margin = 16
|
||||||
for x in range(text_left, text_left + text_width):
|
text_color = get_oxdb_color(oxdb_id, series)
|
||||||
if y < text_top + 4 or y >= text_top + text_height - 4:
|
font_color = tuple(map(lambda x: x - 128 if series else x + 128, text_color))
|
||||||
poster_image.putpixel((x, y), poster_color)
|
draw.rectangle([(0, text_top), (text_width, text_bottom)], fill=text_color)
|
||||||
|
offset_top = text_top + text_margin
|
||||||
|
if not director:
|
||||||
|
title_max_lines = 7
|
||||||
else:
|
else:
|
||||||
pixel = list(poster_image.getpixel((x, y)))
|
title_max_lines = min(len(wrapText(title, text_width - 2 * text_margin, 0, font_file, font_size['large'])), 6)
|
||||||
for c in range(3):
|
director_max_lines = 9 - int((title_max_lines * 3 - 1) / 2)
|
||||||
pixel[c] = int((pixel[c] + poster_color[c]) / 4)
|
if director:
|
||||||
poster_image.putpixel((x, y), tuple(pixel))
|
lines = wrapText(director, text_width - 2 * text_margin, director_max_lines, font_file, font_size['small'])
|
||||||
drawText(poster_image, ((poster_width - text_size[0]) / 2, text_top + (text_height - text_size[1]) / 2), text, font_file, font_size, poster_color)
|
for i, line in enumerate(lines):
|
||||||
|
size = drawText(poster_image, (text_margin, offset_top), line, font_file, font_size['small'], font_color)
|
||||||
|
offset_top += font_size['small'] + 2
|
||||||
|
offset_top += size[1] - font_size['small'] + text_margin / 2
|
||||||
|
lines = wrapText(title, text_width - 2 * text_margin, title_max_lines, font_file, font_size['large'])
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
size = drawText(poster_image, (text_margin, offset_top + 5), line, font_file, font_size['large'], font_color)
|
||||||
|
offset_top += font_size['large'] + 3
|
||||||
|
offset_top += size[1] - font_size['small'] + text_margin / 2
|
||||||
|
if year:
|
||||||
|
drawText(poster_image, (text_margin, offset_top), year, font_file, font_size['small'], font_color)
|
||||||
|
item_id = imdb_id or oxdb_id
|
||||||
|
drawText(poster_image, (text_margin, text_bottom - text_margin - font_size['large'] + 2), item_id, font_file, font_size['large'], font_color)
|
||||||
|
|
||||||
|
'''
|
||||||
|
# logo
|
||||||
|
logo_height = 32
|
||||||
|
logo_image = Image.open(os.path.join(static_root, '..', '..', 'static', 'png', 'logo.png'))
|
||||||
|
logo_width = int(round(logo_height * logo_image.size[0] / logo_image.size[1]))
|
||||||
|
logo_image = logo_image.resize((logo_width, logo_height), Image.ANTIALIAS)
|
||||||
|
logo_left = text_width - text_margin - logo_width
|
||||||
|
logo_top = text_bottom - text_margin - logo_height
|
||||||
|
for y in range(logo_height):
|
||||||
|
for x in range(logo_width):
|
||||||
|
poster_color = poster_image.getpixel((logo_left + x, logo_top + y))
|
||||||
|
logo_color = logo_image.getpixel((x, y))[0]
|
||||||
|
alpha = logo_image.getpixel((x, y))[3]
|
||||||
|
if series:
|
||||||
|
poster_color = tuple(map(lambda x: int(x - (logo_color - 16) * alpha / 255), poster_color))
|
||||||
|
else:
|
||||||
|
poster_color = tuple(map(lambda x: int(x + (logo_color - 16) * alpha / 255), poster_color))
|
||||||
|
poster_image.putpixel((logo_left + x, logo_top + y), poster_color)
|
||||||
|
i '''
|
||||||
poster_image.save(poster)
|
poster_image.save(poster)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
parser.add_option('-o', '--oxdbid', dest='oxdb_id', help='0xDB Id')
|
parser.add_option('-o', '--oxdbid', dest='oxdb_id', help='0xDB Id')
|
||||||
parser.add_option('-i', '--id', dest='id', help='Item Id')
|
parser.add_option('-i', '--id', dest='imdb_id', help='Item Id')
|
||||||
parser.add_option('-t', '--title', dest='title', help='Title', default='')
|
parser.add_option('-t', '--title', dest='title', help='Title')
|
||||||
parser.add_option('-d', '--director', dest='director', help='Director', default='')
|
parser.add_option('-d', '--director', dest='director', help='Director(s)', default='')
|
||||||
parser.add_option('-y', '--year', dest='year', help='Year', default='')
|
parser.add_option('-y', '--year', dest='year', help='Year')
|
||||||
|
parser.add_option('-s', '--series', dest='series', help='Movie is an episode of a series', action='store_true')
|
||||||
parser.add_option('-f', '--frame', dest='frame', help='Poster frame (image file to be read)')
|
parser.add_option('-f', '--frame', dest='frame', help='Poster frame (image file to be read)')
|
||||||
parser.add_option('-l', '--timeline', dest='timeline', help='Timeline (image file to be read)')
|
parser.add_option('-l', '--timeline', dest='timeline', help='Timeline (image file to be read)')
|
||||||
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
|
parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)')
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
if options.oxdb_id and not options.id:
|
|
||||||
options.id = options.oxdb_id
|
if None in (options.oxdb_id, options.title, options.poster):
|
||||||
if None in (options.id, options.poster):
|
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
opt = {}
|
opt = {}
|
||||||
for key in ('id', 'title', 'frame', 'timeline', 'poster'):
|
for key in ('oxdb_id', 'imdb_id', 'title', 'director', 'year', 'series', 'frame', 'timeline', 'poster'):
|
||||||
opt[key] = getattr(options, key)
|
opt[key] = getattr(options, key)
|
||||||
|
|
||||||
opt['title'] = opt['title'].decode('utf-8')
|
opt['title'] = opt['title'].decode('utf-8')
|
||||||
|
opt['director'] = opt['director'].decode('utf-8')
|
||||||
|
|
||||||
render_poster(**opt)
|
render_poster(**opt)
|
||||||
|
|
||||||
|
|
|
@ -133,77 +133,10 @@ pandora.ui.infoView = function(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var listKeys = [
|
var listKeys = [
|
||||||
'language', 'topic', 'director', 'cinematographer', 'featuring',
|
'country', 'language', 'director', 'featuring',
|
||||||
'groups', 'license'
|
'groups'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Source & Project --------------------------------------------------------
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
['source', 'project'].forEach(function(key) {
|
|
||||||
$div = $('<div>').appendTo($data);
|
|
||||||
if (canEdit || data[key]) {
|
|
||||||
count && $('<br>').appendTo($div);
|
|
||||||
$('<div>')
|
|
||||||
.css({float: 'left'})
|
|
||||||
.html(
|
|
||||||
formatKey({
|
|
||||||
category: 'categories',
|
|
||||||
}[key] || key).replace('</span>', ' </span>')
|
|
||||||
)
|
|
||||||
.appendTo($div);
|
|
||||||
Ox.Editable({
|
|
||||||
clickLink: pandora.clickLink,
|
|
||||||
format: function(value) {
|
|
||||||
return listKeys.indexOf(key) >= 0
|
|
||||||
? formatValue(value.split(', '), {
|
|
||||||
'director': 'name',
|
|
||||||
'cinematographer': 'name',
|
|
||||||
'features': 'name',
|
|
||||||
}[key] || key)
|
|
||||||
: value;
|
|
||||||
},
|
|
||||||
placeholder: formatLight('unknown'),
|
|
||||||
editable: canEdit,
|
|
||||||
tooltip: canEdit ? 'Doubleclick to edit' : '',
|
|
||||||
value: listKeys.indexOf(key) >= 0
|
|
||||||
? (data[key] || []).join(', ')
|
|
||||||
: data[key] || ''
|
|
||||||
})
|
|
||||||
.css({float: 'left'})
|
|
||||||
.bindEvent({
|
|
||||||
submit: function(event) {
|
|
||||||
editMetadata(key, event.value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.appendTo($div);
|
|
||||||
if (canEdit || data[key + 'description']) {
|
|
||||||
$('<br>').css({'clear': 'both'}).appendTo($div);
|
|
||||||
$('<div>')
|
|
||||||
.append(
|
|
||||||
descriptions[key] = Ox.Editable({
|
|
||||||
clickLink: pandora.clickLink,
|
|
||||||
placeholder: formatLight('No ' + Ox.toTitleCase(key) + ' Description'),
|
|
||||||
editable: canEdit,
|
|
||||||
tooltip: canEdit ? 'Doubleclick to edit' : '',
|
|
||||||
type: 'textarea',
|
|
||||||
value: data[key + 'description'] || ''
|
|
||||||
})
|
|
||||||
.bindEvent({
|
|
||||||
submit: function(event) {
|
|
||||||
editMetadata(key + 'description', event.value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.css(css)
|
|
||||||
).css({
|
|
||||||
'margin-top': '8px',
|
|
||||||
})
|
|
||||||
.appendTo($div);
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Title -------------------------------------------------------------------
|
// Title -------------------------------------------------------------------
|
||||||
|
|
||||||
$('<div>')
|
$('<div>')
|
||||||
|
@ -232,11 +165,11 @@ pandora.ui.infoView = function(data) {
|
||||||
)
|
)
|
||||||
.appendTo($center);
|
.appendTo($center);
|
||||||
|
|
||||||
// Location, Date, Language and Duration -----------------------------------
|
// Year, Country, Language and Duration -----------------------------------
|
||||||
|
|
||||||
if (canEdit) {
|
if (canEdit) {
|
||||||
$div = $('<div>').css(css).css({marginTop: '12px'}).appendTo($center);
|
$div = $('<div>').css(css).css({marginTop: '12px'}).appendTo($center);
|
||||||
['location', 'date', 'language', 'duration'].forEach(function(key, i) {
|
['year', 'country', 'language', 'duration'].forEach(function(key, i) {
|
||||||
i && $('<div>').css({float: 'left'}).html('; ').appendTo($div);
|
i && $('<div>').css({float: 'left'}).html('; ').appendTo($div);
|
||||||
$('<div>')
|
$('<div>')
|
||||||
.css({float: 'left'})
|
.css({float: 'left'})
|
||||||
|
@ -266,7 +199,7 @@ pandora.ui.infoView = function(data) {
|
||||||
$('<br>').appendTo($center);
|
$('<br>').appendTo($center);
|
||||||
} else {
|
} else {
|
||||||
html = [];
|
html = [];
|
||||||
['location', 'date', 'language', 'duration'].forEach(function(key) {
|
['year', 'country', 'language', 'duration'].forEach(function(key) {
|
||||||
if (data[key]) {
|
if (data[key]) {
|
||||||
html.push(formatKey(key) + formatValue(data[key], key));
|
html.push(formatKey(key) + formatValue(data[key], key));
|
||||||
}
|
}
|
||||||
|
@ -278,7 +211,7 @@ pandora.ui.infoView = function(data) {
|
||||||
|
|
||||||
if (canEdit) {
|
if (canEdit) {
|
||||||
$div = $('<div>').css(css).css('clear', 'both').appendTo($center);
|
$div = $('<div>').css(css).css('clear', 'both').appendTo($center);
|
||||||
['director', 'cinematographer', 'featuring'].forEach(function(key, i) {
|
['director', 'featuring'].forEach(function(key, i) {
|
||||||
i && $('<div>').css({float: 'left'}).html('; ').appendTo($div);
|
i && $('<div>').css({float: 'left'}).html('; ').appendTo($div);
|
||||||
$('<div>')
|
$('<div>')
|
||||||
.css({float: 'left'})
|
.css({float: 'left'})
|
||||||
|
@ -306,7 +239,7 @@ pandora.ui.infoView = function(data) {
|
||||||
$('<br>').appendTo($center);
|
$('<br>').appendTo($center);
|
||||||
} else if (data.director || data.cinematographer || data.featuring) {
|
} else if (data.director || data.cinematographer || data.featuring) {
|
||||||
html = [];
|
html = [];
|
||||||
['director', 'cinematographer', 'featuring'].forEach(function(key) {
|
['director', 'featuring'].forEach(function(key) {
|
||||||
if (data[key] && data[key].length) {
|
if (data[key] && data[key].length) {
|
||||||
html.push(
|
html.push(
|
||||||
formatKey(key)
|
formatKey(key)
|
||||||
|
@ -317,40 +250,6 @@ pandora.ui.infoView = function(data) {
|
||||||
$('<div>').css(css).html(html.join('; ')).appendTo($center);
|
$('<div>').css(css).html(html.join('; ')).appendTo($center);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Topic -------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (canEdit) {
|
|
||||||
var key = 'topic';
|
|
||||||
$div = $('<div>').css(css).css('clear', 'both').appendTo($center);
|
|
||||||
$('<div>')
|
|
||||||
.css({float: 'left'})
|
|
||||||
.html(formatKey('Topics').replace('</span>', ' </span>'))
|
|
||||||
.appendTo($div);
|
|
||||||
Ox.Editable({
|
|
||||||
clickLink: pandora.clickLink,
|
|
||||||
format: function(value) {
|
|
||||||
return formatValue(value.split(', '), key);
|
|
||||||
},
|
|
||||||
placeholder: formatLight('unknown'),
|
|
||||||
tooltip: 'Doubleclick to edit',
|
|
||||||
value: listKeys.indexOf(key) >= 0
|
|
||||||
? (data[key] || []).join(', ')
|
|
||||||
: data[key] || ''
|
|
||||||
})
|
|
||||||
.css({float: 'left'})
|
|
||||||
.bindEvent({
|
|
||||||
submit: function(event) {
|
|
||||||
editMetadata(key, event.value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.appendTo($div);
|
|
||||||
$('<br>').appendTo($center);
|
|
||||||
|
|
||||||
} else if (data.topic) {
|
|
||||||
html = formatKey('topics') + formatValue(data.topic, 'topic');
|
|
||||||
$('<div>').css(css).html(html).appendTo($center);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Summary -------------------------------------------------------------
|
// Summary -------------------------------------------------------------
|
||||||
|
|
||||||
if (canEdit) {
|
if (canEdit) {
|
||||||
|
@ -379,32 +278,6 @@ pandora.ui.infoView = function(data) {
|
||||||
$('<div>').css(css).html(data.summary).appendTo($center);
|
$('<div>').css(css).html(data.summary).appendTo($center);
|
||||||
}
|
}
|
||||||
|
|
||||||
// License -----------------------------------------------------------------
|
|
||||||
|
|
||||||
$div = $('<div>').css(css).css({marginTop: '16px'}).appendTo($center);
|
|
||||||
if (canEdit) {
|
|
||||||
$('<div>')
|
|
||||||
.css({float: 'left'})
|
|
||||||
.html(formatKey('license').replace('</span>', ' </span>'))
|
|
||||||
.appendTo($div);
|
|
||||||
Ox.Editable({
|
|
||||||
placeholder: formatLight('No License'),
|
|
||||||
tooltip: 'Doubleclick to edit',
|
|
||||||
value: (data.license || []).join(', ')
|
|
||||||
})
|
|
||||||
.bindEvent({
|
|
||||||
submit: function(event) {
|
|
||||||
editMetadata('license', event.value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.appendTo($div);
|
|
||||||
} else if (data.license) {
|
|
||||||
$div.html(
|
|
||||||
formatKey('License')
|
|
||||||
+ (data.license || []).join(', ')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hue, Saturation, Lightness, Volume --------------------------------------
|
// Hue, Saturation, Lightness, Volume --------------------------------------
|
||||||
|
|
||||||
['hue', 'saturation', 'lightness', 'volume'].forEach(function(key) {
|
['hue', 'saturation', 'lightness', 'volume'].forEach(function(key) {
|
||||||
|
|
|
@ -38,7 +38,6 @@ DATABASES = {
|
||||||
}
|
}
|
||||||
BROKER_PASSWORD = "$RABBITPWD"
|
BROKER_PASSWORD = "$RABBITPWD"
|
||||||
XACCELREDIRECT = True
|
XACCELREDIRECT = True
|
||||||
DB_GIN_TRGM = True
|
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
TEMPLATE_DEBUG = DEBUG
|
TEMPLATE_DEBUG = DEBUG
|
||||||
|
@ -49,7 +48,7 @@ cd /srv/pandora/pandora
|
||||||
sudo -u pandora python manage.py syncdb --noinput
|
sudo -u pandora python manage.py syncdb --noinput
|
||||||
sudo -u pandora python manage.py sqlfindindex | sudo -u pandora python manage.py dbshell
|
sudo -u pandora python manage.py sqlfindindex | sudo -u pandora python manage.py dbshell
|
||||||
echo "UPDATE django_site SET domain = '$HOST.local', name = '$HOST.local' WHERE 1=1;" | sudo -u pandora python manage.py dbshell
|
echo "UPDATE django_site SET domain = '$HOST.local', name = '$HOST.local' WHERE 1=1;" | sudo -u pandora python manage.py dbshell
|
||||||
|
echo "DB_GIN_TRGM = True" >> /srv/pandora/pandora/local_settings.py
|
||||||
|
|
||||||
mkdir /srv/pandora/data
|
mkdir /srv/pandora/data
|
||||||
chown -R pandora:pandora /srv/pandora
|
chown -R pandora:pandora /srv/pandora
|
||||||
|
|
Loading…
Reference in a new issue