store clip values in clip db, cleanup if all annotations are gone, add additionalSort
This commit is contained in:
parent
10a1239df7
commit
16cc495fb5
10 changed files with 109 additions and 99 deletions
|
@ -4,6 +4,11 @@
|
||||||
You can edit this file.
|
You can edit this file.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
|
"additionalSort": [
|
||||||
|
{"key": "director", "operator": "+"},
|
||||||
|
{"key": "year", "operator": "-"},
|
||||||
|
{"key": "title", "operator": "+"}
|
||||||
|
],
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"showUsers": true
|
"showUsers": true
|
||||||
},
|
},
|
||||||
|
@ -47,6 +52,12 @@
|
||||||
{"id": "lightness", "title": "Lightness", "type": "float"},
|
{"id": "lightness", "title": "Lightness", "type": "float"},
|
||||||
{"id": "volume", "title": "Volume", "type": "float"}
|
{"id": "volume", "title": "Volume", "type": "float"}
|
||||||
],
|
],
|
||||||
|
/*
|
||||||
|
clipLayers is the ordered list of public layers that will appear as the
|
||||||
|
text of clips. Excluding a layer from this list means it will not be
|
||||||
|
included in find annotations.
|
||||||
|
*/
|
||||||
|
"clipLayers": ["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": "director", "title": "Director", "type": "string"},
|
{"id": "director", "title": "Director", "type": "string"},
|
||||||
|
@ -93,6 +104,7 @@
|
||||||
"id": "title",
|
"id": "title",
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"additionalSort": [{"key": "year", "operator": "-"}, {"key": "director", "operator": "+"}],
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"autocompleteSortKey": "votes",
|
"autocompleteSortKey": "votes",
|
||||||
"columnRequired": true,
|
"columnRequired": true,
|
||||||
|
@ -104,6 +116,7 @@
|
||||||
"id": "director",
|
"id": "director",
|
||||||
"title": "Director",
|
"title": "Director",
|
||||||
"type": ["string"],
|
"type": ["string"],
|
||||||
|
"additionalSort": [{"key": "year", "operator": "-"}, {"key": "title", "operator": "-"}],
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"columnRequired": true,
|
"columnRequired": true,
|
||||||
"columnWidth": 180,
|
"columnWidth": 180,
|
||||||
|
@ -124,6 +137,7 @@
|
||||||
"id": "year",
|
"id": "year",
|
||||||
"title": "Year",
|
"title": "Year",
|
||||||
"type": "year",
|
"type": "year",
|
||||||
|
"additionalSort": [{"key": "director", "operator": "+"}, {"key": "title", "operator": "+"}],
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"columnWidth": 60,
|
"columnWidth": 60,
|
||||||
"filter": true,
|
"filter": true,
|
||||||
|
|
|
@ -133,10 +133,11 @@ class Annotation(models.Model):
|
||||||
self.sortvalue = None
|
self.sortvalue = None
|
||||||
|
|
||||||
#no clip or update clip
|
#no clip or update clip
|
||||||
private = layer.get('private', False)
|
if self.layer in settings.CONFIG['clipLayers']:
|
||||||
if not private:
|
|
||||||
if not self.clip or self.start != self.clip.start or self.end != self.clip.end:
|
if not self.clip or self.start != self.clip.start or self.end != self.clip.end:
|
||||||
self.clip, created = Clip.get_or_create(self.item, self.start, self.end)
|
self.clip, created = Clip.get_or_create(self.item, self.start, self.end)
|
||||||
|
elif self.clip:
|
||||||
|
self.clip = None
|
||||||
|
|
||||||
super(Annotation, self).save(*args, **kwargs)
|
super(Annotation, self).save(*args, **kwargs)
|
||||||
if set_public_id:
|
if set_public_id:
|
||||||
|
@ -147,6 +148,8 @@ class Annotation(models.Model):
|
||||||
'id': self.clip.id,
|
'id': self.clip.id,
|
||||||
self.layer: False
|
self.layer: False
|
||||||
}).update(**{self.layer: True})
|
}).update(**{self.layer: True})
|
||||||
|
#update clip.findvalue
|
||||||
|
self.clip.save()
|
||||||
|
|
||||||
if filter(lambda l: l['type'] == 'place' or l.get('hasPlaces'),
|
if filter(lambda l: l['type'] == 'place' or l.get('hasPlaces'),
|
||||||
settings.CONFIG['layers']):
|
settings.CONFIG['layers']):
|
||||||
|
|
|
@ -165,6 +165,8 @@ def removeAnnotation(request):
|
||||||
a = get_object_or_404_json(models.Annotation, public_id=data['id'])
|
a = get_object_or_404_json(models.Annotation, public_id=data['id'])
|
||||||
if a.editable(request.user):
|
if a.editable(request.user):
|
||||||
a.delete()
|
a.delete()
|
||||||
|
if a.clip.annotations.count() == 0:
|
||||||
|
a.clip.delete()
|
||||||
else:
|
else:
|
||||||
response = json_response(status=403, text='permission denied')
|
response = json_response(status=403, text='permission denied')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
|
|
|
@ -27,8 +27,8 @@ def parseCondition(condition, user):
|
||||||
'in': 'start',
|
'in': 'start',
|
||||||
'out': 'end',
|
'out': 'end',
|
||||||
'place': 'annotations__places__id',
|
'place': 'annotations__places__id',
|
||||||
'text': 'annotations__findvalue',
|
'text': 'findvalue',
|
||||||
'annotations': 'annotations__findvalue',
|
'annotations': 'findvalue',
|
||||||
'user': 'annotations__user__username',
|
'user': 'annotations__user__username',
|
||||||
}.get(k, k)
|
}.get(k, k)
|
||||||
if not k:
|
if not k:
|
||||||
|
@ -37,10 +37,7 @@ def parseCondition(condition, user):
|
||||||
op = condition.get('operator')
|
op = condition.get('operator')
|
||||||
if not op:
|
if not op:
|
||||||
op = ''
|
op = ''
|
||||||
public_layers = [l['id']
|
if k in settings.CONFIG['clipLayers']:
|
||||||
for l in filter(lambda l: not l.get('private', False),
|
|
||||||
settings.CONFIG['layers'])]
|
|
||||||
if k in public_layers:
|
|
||||||
return parseCondition({'key': 'annotations__findvalue',
|
return parseCondition({'key': 'annotations__findvalue',
|
||||||
'value': v,
|
'value': v,
|
||||||
'operator': op}, user) \
|
'operator': op}, user) \
|
||||||
|
@ -141,10 +138,7 @@ class ClipManager(Manager):
|
||||||
return QuerySet(self.model)
|
return QuerySet(self.model)
|
||||||
|
|
||||||
def filter_annotations(self, data, user):
|
def filter_annotations(self, data, user):
|
||||||
public_layers = [l['id']
|
keys = settings.CONFIG['clipLayers'] + ['annotations', 'text', '*']
|
||||||
for l in filter(lambda l: not l.get('private', False),
|
|
||||||
settings.CONFIG['layers'])]
|
|
||||||
keys = public_layers + ['annotations', 'text', '*']
|
|
||||||
conditions = data.get('query', {}).get('conditions', [])
|
conditions = data.get('query', {}).get('conditions', [])
|
||||||
conditions = filter(lambda c: c['key'] in keys, conditions)
|
conditions = filter(lambda c: c['key'] in keys, conditions)
|
||||||
operator = data.get('query', {}).get('operator', '&')
|
operator = data.get('query', {}).get('operator', '&')
|
||||||
|
@ -160,7 +154,7 @@ class ClipManager(Manager):
|
||||||
'$': '__iendswith',
|
'$': '__iendswith',
|
||||||
}.get(condition.get('opterator', ''), '__icontains'))
|
}.get(condition.get('opterator', ''), '__icontains'))
|
||||||
q = Q(**{key: condition['value']})
|
q = Q(**{key: condition['value']})
|
||||||
if condition['key'] in public_layers:
|
if condition['key'] in settings.CONFIG['clipLayers']:
|
||||||
q = q & Q(layer=condition['key'])
|
q = q & Q(layer=condition['key'])
|
||||||
return q
|
return q
|
||||||
conditions = map(parse, conditions)
|
conditions = map(parse, conditions)
|
||||||
|
@ -205,6 +199,6 @@ class ClipManager(Manager):
|
||||||
if conditions:
|
if conditions:
|
||||||
qs = qs.filter(conditions)
|
qs = qs.filter(conditions)
|
||||||
if 'keys' in data:
|
if 'keys' in data:
|
||||||
for l in filter(lambda k: k in self.model.layers, data['keys']):
|
for l in filter(lambda k: k in settings.CONFIG['clipLayers'], data['keys']):
|
||||||
qs = qs.filter(**{l: True})
|
qs = qs.filter(**{l: True})
|
||||||
return qs
|
return qs
|
||||||
|
|
|
@ -35,8 +35,19 @@ class MetaClip:
|
||||||
streams = self.item.streams()
|
streams = self.item.streams()
|
||||||
if streams:
|
if streams:
|
||||||
self.aspect_ratio = streams[0].aspect_ratio
|
self.aspect_ratio = streams[0].aspect_ratio
|
||||||
|
sortvalue = ''
|
||||||
|
findvalue = ''
|
||||||
|
for l in settings.CONFIG['clipLayers']:
|
||||||
|
sortvalue += ''.join(filter(lambda s: s,
|
||||||
|
[a.sortvalue
|
||||||
|
for a in self.annotations.filter(layer=l).order_by('sortvalue')]))
|
||||||
|
if sortvalue:
|
||||||
|
self.sortvalue = sortvalue[:1000]
|
||||||
|
else:
|
||||||
|
self.sortvalue = None
|
||||||
|
self.findvalue = '\n'.join([a.findvalue for a in self.annotations.all()])
|
||||||
if self.id:
|
if self.id:
|
||||||
for l in self.layers:
|
for l in settings.CONFIG['clipLayers']:
|
||||||
setattr(self, l, self.annotations.filter(layer=l).count()>0)
|
setattr(self, l, self.annotations.filter(layer=l).count()>0)
|
||||||
models.Model.save(self, *args, **kwargs)
|
models.Model.save(self, *args, **kwargs)
|
||||||
|
|
||||||
|
@ -60,7 +71,7 @@ class MetaClip:
|
||||||
del j[key]
|
del j[key]
|
||||||
#needed here to make item find with clips work
|
#needed here to make item find with clips work
|
||||||
if 'annotations' in keys:
|
if 'annotations' in keys:
|
||||||
annotations = self.annotations.filter(layer__in=self.layers)
|
annotations = self.annotations.filter(layer__in=settings.CONFIG['clipLayers'])
|
||||||
if qs:
|
if qs:
|
||||||
annotations = annotations.filter(qs)
|
annotations = annotations.filter(qs)
|
||||||
j['annotations'] = [a.json(keys=['value', 'id', 'layer'])
|
j['annotations'] = [a.json(keys=['value', 'id', 'layer'])
|
||||||
|
@ -118,13 +129,11 @@ attrs = {
|
||||||
|
|
||||||
'director': models.CharField(max_length=1000, null=True, db_index=True),
|
'director': models.CharField(max_length=1000, null=True, db_index=True),
|
||||||
'title': models.CharField(max_length=1000, db_index=True),
|
'title': models.CharField(max_length=1000, db_index=True),
|
||||||
|
'sortvalue': models.CharField(max_length=1000, null=True, db_index=True),
|
||||||
|
'findvalue': models.TextField(),
|
||||||
}
|
}
|
||||||
public_layers = [l['id']
|
for name in settings.CONFIG['clipLayers']:
|
||||||
for l in filter(lambda l: not l.get('private', False),
|
|
||||||
settings.CONFIG['layers'])]
|
|
||||||
for name in public_layers:
|
|
||||||
attrs[name] = models.BooleanField(default=False, db_index=True)
|
attrs[name] = models.BooleanField(default=False, db_index=True)
|
||||||
|
|
||||||
Clip = type('Clip', (MetaClip,models.Model), attrs)
|
Clip = type('Clip', (MetaClip,models.Model), attrs)
|
||||||
Clip.layers = public_layers
|
|
||||||
|
|
||||||
|
|
|
@ -36,20 +36,20 @@ def order_query(qs, sort):
|
||||||
if operator != '-':
|
if operator != '-':
|
||||||
operator = ''
|
operator = ''
|
||||||
clip_keys = ('public_id', 'start', 'end', 'hue', 'saturation', 'lightness', 'volume',
|
clip_keys = ('public_id', 'start', 'end', 'hue', 'saturation', 'lightness', 'volume',
|
||||||
'duration', 'annotations__sortvalue', 'videoRatio',
|
'duration', 'sortvalue', 'videoRatio',
|
||||||
'director', 'title')
|
'director', 'title')
|
||||||
key = {
|
key = {
|
||||||
'id': 'public_id',
|
'id': 'public_id',
|
||||||
'in': 'start',
|
'in': 'start',
|
||||||
'out': 'end',
|
'out': 'end',
|
||||||
'position': 'start',
|
'position': 'start',
|
||||||
'text': 'annotations__sortvalue',
|
'text': 'sortvalue',
|
||||||
'videoRatio': 'aspect_ratio',
|
'videoRatio': 'aspect_ratio',
|
||||||
}.get(e['key'], e['key'])
|
}.get(e['key'], e['key'])
|
||||||
if key.startswith('clip:'):
|
if key.startswith('clip:'):
|
||||||
key = e['key'][len('clip:'):]
|
key = e['key'][len('clip:'):]
|
||||||
key = {
|
key = {
|
||||||
'text': 'annotations__sortvalue',
|
'text': 'sortvalue',
|
||||||
'position': 'start',
|
'position': 'start',
|
||||||
}.get(key, key)
|
}.get(key, key)
|
||||||
elif key not in clip_keys:
|
elif key not in clip_keys:
|
||||||
|
@ -85,7 +85,8 @@ def findClips(request):
|
||||||
qs = qs[query['range'][0]:query['range'][1]]
|
qs = qs[query['range'][0]:query['range'][1]]
|
||||||
|
|
||||||
ids = []
|
ids = []
|
||||||
keys = filter(lambda k: k not in models.Clip.layers + ['annotations'], data['keys'])
|
keys = filter(lambda k: k not in settings.CONFIG['clipLayers'] + ['annotations'],
|
||||||
|
data['keys'])
|
||||||
if filter(lambda k: k not in models.Clip.clip_keys, keys):
|
if filter(lambda k: k not in models.Clip.clip_keys, keys):
|
||||||
qs = qs.select_related('item__sort')
|
qs = qs.select_related('item__sort')
|
||||||
|
|
||||||
|
@ -116,9 +117,9 @@ def findClips(request):
|
||||||
if response['data']['items']:
|
if response['data']['items']:
|
||||||
if 'annotations' in keys:
|
if 'annotations' in keys:
|
||||||
add_annotations('annotations',
|
add_annotations('annotations',
|
||||||
Annotation.objects.filter(layer__in=models.Clip.layers, clip__in=ids),
|
Annotation.objects.filter(layer__in=settings.CONFIG['clipLayers'],
|
||||||
True)
|
clip__in=ids), True)
|
||||||
for layer in filter(lambda l: l in keys, models.Clip.layers):
|
for layer in filter(lambda l: l in keys, settings.CONFIG['clipLayers']):
|
||||||
add_annotations(layer,
|
add_annotations(layer,
|
||||||
Annotation.objects.filter(layer=layer, clip__in=ids))
|
Annotation.objects.filter(layer=layer, clip__in=ids))
|
||||||
elif 'position' in query:
|
elif 'position' in query:
|
||||||
|
|
|
@ -40,7 +40,6 @@ import archive.models
|
||||||
from person.models import get_name_sort
|
from person.models import get_name_sort
|
||||||
from title.models import get_title_sort
|
from title.models import get_title_sort
|
||||||
|
|
||||||
|
|
||||||
def get_id(info):
|
def get_id(info):
|
||||||
q = Item.objects.all()
|
q = Item.objects.all()
|
||||||
for key in ('title', 'director', 'year'):
|
for key in ('title', 'director', 'year'):
|
||||||
|
@ -325,9 +324,6 @@ class Item(models.Model):
|
||||||
if self.poster_frame == -1 and self.sort.duration:
|
if self.poster_frame == -1 and self.sort.duration:
|
||||||
self.poster_frame = self.sort.duration/2
|
self.poster_frame = self.sort.duration/2
|
||||||
update_poster = True
|
update_poster = True
|
||||||
if not self.get('runtime') and self.sort.duration:
|
|
||||||
self.data['runtime'] = self.sort.duration
|
|
||||||
self.update_sort()
|
|
||||||
self.json = self.get_json()
|
self.json = self.get_json()
|
||||||
super(Item, self).save(*args, **kwargs)
|
super(Item, self).save(*args, **kwargs)
|
||||||
if update_ids:
|
if update_ids:
|
||||||
|
@ -1143,7 +1139,7 @@ class Item(models.Model):
|
||||||
return icon
|
return icon
|
||||||
|
|
||||||
def load_subtitles(self):
|
def load_subtitles(self):
|
||||||
if not filter(lambda l: l['id'] == 'subtitles', settings.CONFIG['layers']):
|
if not utils.get_by_id(settings.CONFIG['layers'], 'subtitles'):
|
||||||
return
|
return
|
||||||
with transaction.commit_on_success():
|
with transaction.commit_on_success():
|
||||||
layer = 'subtitles'
|
layer = 'subtitles'
|
||||||
|
@ -1220,7 +1216,8 @@ pre_delete.connect(delete_item, sender=Item)
|
||||||
|
|
||||||
Item.facet_keys = []
|
Item.facet_keys = []
|
||||||
for key in settings.CONFIG['itemKeys']:
|
for key in settings.CONFIG['itemKeys']:
|
||||||
if 'autocomplete' in key and not 'autocompleteSortKey' in key:
|
if 'autocomplete' in key and not 'autocompleteSortKey' in key or \
|
||||||
|
key.get('filter'):
|
||||||
Item.facet_keys.append(key['id'])
|
Item.facet_keys.append(key['id'])
|
||||||
|
|
||||||
Item.person_keys = []
|
Item.person_keys = []
|
||||||
|
|
|
@ -78,3 +78,7 @@ def get_positions(ids, pos):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return positions
|
return positions
|
||||||
|
|
||||||
|
def get_by_id(objects, id):
|
||||||
|
obj = filter(lambda o: o['id'] == id, objects)
|
||||||
|
return obj and obj[0] or None
|
||||||
|
|
|
@ -33,23 +33,15 @@ from clip.models import Clip
|
||||||
|
|
||||||
from ox.django.api import actions
|
from ox.django.api import actions
|
||||||
|
|
||||||
|
import utils
|
||||||
|
|
||||||
|
|
||||||
def _order_query(qs, sort, prefix='sort__'):
|
def _order_query(qs, sort, prefix='sort__'):
|
||||||
order_by = []
|
order_by = []
|
||||||
if len(sort) == 1:
|
if len(sort) == 1:
|
||||||
if sort[0]['key'] == 'title':
|
key = utils.get_by_id(settings.CONFIG['itemKeys'], sort[0]['key'])
|
||||||
sort.append({'operator': '-', 'key': 'year'})
|
for s in key.get('additionalSort', settings.CONFIG.get('additionalSort', [])):
|
||||||
sort.append({'operator': '+', 'key': 'director'})
|
sort.append(s)
|
||||||
elif sort[0]['key'] == 'director':
|
|
||||||
sort.append({'operator': '-', 'key': 'year'})
|
|
||||||
sort.append({'operator': '-', 'key': 'title'})
|
|
||||||
elif sort[0]['key'] == 'year':
|
|
||||||
sort.append({'operator': '+', 'key': 'director'})
|
|
||||||
sort.append({'operator': '+', 'key': 'title'})
|
|
||||||
elif not sort[0]['key'] in ('value', 'sortvalue'):
|
|
||||||
sort.append({'operator': '+', 'key': 'director'})
|
|
||||||
sort.append({'operator': '-', 'key': 'year'})
|
|
||||||
sort.append({'operator': '+', 'key': 'title'})
|
|
||||||
for e in sort:
|
for e in sort:
|
||||||
operator = e['operator']
|
operator = e['operator']
|
||||||
if operator != '-':
|
if operator != '-':
|
||||||
|
@ -273,14 +265,21 @@ Positions
|
||||||
Sum('pixels'),
|
Sum('pixels'),
|
||||||
Sum('size')
|
Sum('size')
|
||||||
)
|
)
|
||||||
response['data']['duration'] = r['duration__sum']
|
totals = [i['id'] for i in settings.CONFIG['totals']]
|
||||||
response['data']['files'] = files.count()
|
if 'duration' in totals:
|
||||||
response['data']['items'] = items.count()
|
response['data']['duration'] = r['duration__sum']
|
||||||
response['data']['pixels'] = r['pixels__sum']
|
if 'files' in totals:
|
||||||
response['data']['runtime'] = items.aggregate(Sum('sort__runtime'))['sort__runtime__sum']
|
response['data']['files'] = files.count()
|
||||||
response['data']['size'] = r['size__sum']
|
if 'items' in totals:
|
||||||
|
response['data']['items'] = items.count()
|
||||||
|
if 'pixels' in totals:
|
||||||
|
response['data']['pixels'] = r['pixels__sum']
|
||||||
|
if 'runtime' in totals:
|
||||||
|
response['data']['runtime'] = items.aggregate(Sum('sort__runtime'))['sort__runtime__sum'] or 0
|
||||||
|
if 'size' in totals:
|
||||||
|
response['data']['size'] = r['size__sum']
|
||||||
for key in ('runtime', 'duration', 'pixels', 'size'):
|
for key in ('runtime', 'duration', 'pixels', 'size'):
|
||||||
if response['data'][key] == None:
|
if key in totals and response['data'][key] == None:
|
||||||
response['data'][key] = 0
|
response['data'][key] = 0
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(find)
|
actions.register(find)
|
||||||
|
@ -769,8 +768,8 @@ def video(request, id, resolution, format, index=None):
|
||||||
response = HttpResponse(extract.chop(path, t[0], t[1]), content_type=content_type)
|
response = HttpResponse(extract.chop(path, t[0], t[1]), content_type=content_type)
|
||||||
filename = "Clip of %s - %s-%s - %s %s%s" % (
|
filename = "Clip of %s - %s-%s - %s %s%s" % (
|
||||||
item.get('title'),
|
item.get('title'),
|
||||||
ox.formatDuration(t[0] * 1000),
|
ox.formatDuration(t[0] * 1000).replace(':', '.')[:-4],
|
||||||
ox.formatDuration(t[1] * 1000),
|
ox.formatDuration(t[1] * 1000).replace(':', '.')[:-4],
|
||||||
settings.SITENAME,
|
settings.SITENAME,
|
||||||
item.itemId,
|
item.itemId,
|
||||||
ext
|
ext
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
You can edit this file.
|
You can edit this file.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
|
"additionalSort": [
|
||||||
|
{"key": "title", "operator": "+"}
|
||||||
|
],
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"showUsers": true
|
"showUsers": true
|
||||||
},
|
},
|
||||||
|
@ -47,20 +50,23 @@
|
||||||
{"id": "lightness", "title": "Lightness", "type": "float"},
|
{"id": "lightness", "title": "Lightness", "type": "float"},
|
||||||
{"id": "volume", "title": "Volume", "type": "float"}
|
{"id": "volume", "title": "Volume", "type": "float"}
|
||||||
],
|
],
|
||||||
|
/*
|
||||||
|
clipLayers is the ordered list of public layers that will appear as the
|
||||||
|
text of clips. Excluding a layer from this list means it will not be
|
||||||
|
included in find annotations.
|
||||||
|
*/
|
||||||
|
"clipLayers": ["transcripts", "keywords", "places", "events", "descriptions"],
|
||||||
// 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": "source", "title": "Sources", "type": "string"},
|
||||||
{"id": "project", "title": "Projects", "type": "string"},
|
{"id": "project", "title": "Projects", "type": "string"},
|
||||||
{"id": "topic", "title": "Topics", "type": "string"},
|
{"id": "topic", "title": "Topics", "type": "string"},
|
||||||
{"id": "name", "title": "People", "type": "string"},
|
{"id": "name", "title": "People", "type": "string"},
|
||||||
{"id": "keywords", "title": "Keywords", "type": "string"},
|
|
||||||
{"id": "language", "title": "Languages", "type": "string"},
|
{"id": "language", "title": "Languages", "type": "string"},
|
||||||
|
{"id": "license", "title": "License", "type": "string"},
|
||||||
{"id": "places", "title": "Places", "type": "string"},
|
{"id": "places", "title": "Places", "type": "string"},
|
||||||
//{"id": "year", "title": "Years", "type": "integer"},
|
{"id": "events", "title": "Events", "type": "string"},
|
||||||
{"id": "features", "title": "Features", "type": "string"},
|
{"id": "keywords", "title": "Keywords", "type": "string"}
|
||||||
{"id": "director", "title": "Directors", "type": "string"},
|
|
||||||
{"id": "cinematographer", "title": "Cinematographers", "type": "string"},
|
|
||||||
{"id": "license", "title": "License", "type": "string"}
|
|
||||||
],
|
],
|
||||||
/*
|
/*
|
||||||
An itemKey must have the following properties:
|
An itemKey must have the following properties:
|
||||||
|
@ -137,12 +143,6 @@
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"find": true
|
"find": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "annotations",
|
|
||||||
"title": "Annotation",
|
|
||||||
"type": "string",
|
|
||||||
"find": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "keywords",
|
"id": "keywords",
|
||||||
"title": "Keywords",
|
"title": "Keywords",
|
||||||
|
@ -155,7 +155,6 @@
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"columnRequired": true,
|
"columnRequired": true,
|
||||||
"columnWidth": 180,
|
"columnWidth": 180,
|
||||||
"filter": true,
|
|
||||||
"sort": "person"
|
"sort": "person"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -164,12 +163,11 @@
|
||||||
"type": ["string"],
|
"type": ["string"],
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"columnWidth": 180,
|
"columnWidth": 180,
|
||||||
"filter": true,
|
|
||||||
"sort": "person"
|
"sort": "person"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "features",
|
"id": "featuring",
|
||||||
"title": "Features",
|
"title": "Featuring",
|
||||||
"type": ["string"],
|
"type": ["string"],
|
||||||
"autocomplete": true,
|
"autocomplete": true,
|
||||||
"columnRequired": true,
|
"columnRequired": true,
|
||||||
|
@ -177,15 +175,6 @@
|
||||||
"filter": true,
|
"filter": true,
|
||||||
"sort": "person"
|
"sort": "person"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "year",
|
|
||||||
"title": "Year",
|
|
||||||
"type": "year",
|
|
||||||
"autocomplete": true,
|
|
||||||
"columnWidth": 60,
|
|
||||||
"filter": true
|
|
||||||
//"find": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "language",
|
"id": "language",
|
||||||
"title": "Language",
|
"title": "Language",
|
||||||
|
@ -195,13 +184,6 @@
|
||||||
"filter": true,
|
"filter": true,
|
||||||
"find": true
|
"find": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "runtime",
|
|
||||||
"title": "Runtime",
|
|
||||||
"type": "time",
|
|
||||||
"columnWidth": 60,
|
|
||||||
"format": {"type": "duration", "args": [0, "medium"]}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "location",
|
"id": "location",
|
||||||
"title": "Location",
|
"title": "Location",
|
||||||
|
@ -211,19 +193,19 @@
|
||||||
"filter": true,
|
"filter": true,
|
||||||
"find": true
|
"find": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "date",
|
||||||
|
"title": "Date",
|
||||||
|
"type": "string",
|
||||||
|
"columnWidth": 120
|
||||||
|
//"format": {"type": "date", "args": ["%a, %b %e, %Y"]}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "description",
|
"id": "description",
|
||||||
"title": "Description",
|
"title": "Description",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"find": true
|
"find": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "wordsinsummary",
|
|
||||||
"title": "Words in Summary",
|
|
||||||
"type": "integer",
|
|
||||||
"columnWidth": 60,
|
|
||||||
"value": {"key": "description", "type": "words"}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "created",
|
"id": "created",
|
||||||
"title": "Date Created",
|
"title": "Date Created",
|
||||||
|
@ -237,6 +219,12 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"columnWidth": 90
|
"columnWidth": 90
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "annotations",
|
||||||
|
"title": "Annotation",
|
||||||
|
"type": "string",
|
||||||
|
"find": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "places",
|
"id": "places",
|
||||||
"title": "Places",
|
"title": "Places",
|
||||||
|
@ -268,7 +256,8 @@
|
||||||
"id": "resolution",
|
"id": "resolution",
|
||||||
"title": "Resolution",
|
"title": "Resolution",
|
||||||
"type": ["integer"],
|
"type": ["integer"],
|
||||||
"columnWidth": 90
|
"columnWidth": 90,
|
||||||
|
"format": {"type": "resolution", "args": ["px"]}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "aspectratio",
|
"id": "aspectratio",
|
||||||
|
@ -392,7 +381,6 @@
|
||||||
"title": "License",
|
"title": "License",
|
||||||
"type": ["string"],
|
"type": ["string"],
|
||||||
"columnWidth": 120,
|
"columnWidth": 120,
|
||||||
"autocomplete": true,
|
|
||||||
"filter": true
|
"filter": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -517,7 +505,6 @@
|
||||||
],
|
],
|
||||||
"totals": [
|
"totals": [
|
||||||
{"id": "items"},
|
{"id": "items"},
|
||||||
{"id": "runtime"},
|
|
||||||
{"id": "files", "admin": true},
|
{"id": "files", "admin": true},
|
||||||
{"id": "duration", "admin": true},
|
{"id": "duration", "admin": true},
|
||||||
{"id": "size", "admin": true},
|
{"id": "size", "admin": true},
|
||||||
|
@ -558,7 +545,7 @@
|
||||||
"itemFind": {"conditions": [], "operator": "&"},
|
"itemFind": {"conditions": [], "operator": "&"},
|
||||||
"itemSort": [{"key": "position", "operator": "+"}],
|
"itemSort": [{"key": "position", "operator": "+"}],
|
||||||
"itemView": "info",
|
"itemView": "info",
|
||||||
"listColumns": ["title", "source", "project", "director", "language", "duration"],
|
"listColumns": ["title", "source", "project", "topics", "language", "duration"],
|
||||||
"listColumnWidth": {},
|
"listColumnWidth": {},
|
||||||
"listSelection": [],
|
"listSelection": [],
|
||||||
"listSort": [{"key": "title", "operator": "+"}],
|
"listSort": [{"key": "title", "operator": "+"}],
|
||||||
|
|
Loading…
Reference in a new issue