cleanup imports and syntax warnings
This commit is contained in:
parent
7fdae917cf
commit
2d5f924891
46 changed files with 452 additions and 517 deletions
|
@ -2,49 +2,32 @@
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division, with_statement
|
from __future__ import division, with_statement
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import os.path
|
|
||||||
import math
|
|
||||||
import random
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
import unicodedata
|
|
||||||
from glob import glob
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.files.base import ContentFile
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.django import fields
|
|
||||||
import ox
|
|
||||||
from ox.utils import json
|
|
||||||
from ox import stripTags
|
|
||||||
from ox.normalize import canonicalTitle, canonicalName
|
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
|
|
||||||
class Layer(models.Model):
|
class Layer(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('position', )
|
ordering = ('position', )
|
||||||
|
|
||||||
name = models.CharField(null=True, max_length=255, unique=True)
|
name = models.CharField(null=True, max_length=255, unique=True)
|
||||||
title = models.CharField(null=True, max_length=255)
|
title = models.CharField(null=True, max_length=255)
|
||||||
#text, string, string from list(fixme), event, place, person
|
#text, string, string from list(fixme), event, place, person
|
||||||
type = models.CharField(null=True, max_length=255)
|
type = models.CharField(null=True, max_length=255)
|
||||||
position = models.IntegerField(default=0)
|
position = models.IntegerField(default=0)
|
||||||
|
|
||||||
overlapping = models.BooleanField(default=True)
|
overlapping = models.BooleanField(default=True)
|
||||||
enabled = models.BooleanField(default=True)
|
enabled = models.BooleanField(default=True)
|
||||||
|
|
||||||
enabled = models.BooleanField(default=True)
|
enabled = models.BooleanField(default=True)
|
||||||
public = models.BooleanField(default=True) #false=users only see there own bins
|
public = models.BooleanField(default=True) #false=users only see there own bins
|
||||||
subtitle = models.BooleanField(default=True) #bis can be displayed as subtitle, only one bin
|
subtitle = models.BooleanField(default=True) #bis can be displayed as subtitle, only one bin
|
||||||
|
|
||||||
find = models.BooleanField(default=True)
|
find = models.BooleanField(default=True)
|
||||||
#words / item duration(wpm), total words, cuts per minute, cuts, number of annotations, number of annotations/duration
|
#words / item duration(wpm), total words, cuts per minute, cuts, number of annotations, number of annotations/duration
|
||||||
sort = models.CharField(null=True, max_length=255)
|
sort = models.CharField(null=True, max_length=255)
|
||||||
|
|
||||||
def properties(self):
|
def properties(self):
|
||||||
|
@ -61,7 +44,9 @@ class Layer(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
class Annotation(models.Model):
|
class Annotation(models.Model):
|
||||||
|
|
||||||
#FIXME: here having a item,start index would be good
|
#FIXME: here having a item,start index would be good
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
@ -77,9 +62,9 @@ class Annotation(models.Model):
|
||||||
|
|
||||||
def editable(self, user):
|
def editable(self, user):
|
||||||
if user.is_authenticated():
|
if user.is_authenticated():
|
||||||
if obj.user == user.id or user.has_perm('0x.admin'):
|
if self.user == user or user.has_perm('0x.admin'):
|
||||||
return True
|
return True
|
||||||
if user.groups.filter(id__in=obj.groups.all()).count() > 0:
|
if user.groups.filter(id__in=self.groups.all()).count() > 0:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -102,4 +87,3 @@ class Annotation(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s/%s-%s" %(self.item, self.start, self.stop)
|
return "%s/%s-%s" %(self.item, self.start, self.stop)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
|
@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# ci:si:et:sw=4:sts=4:ts=4
|
# ci:si:et:sw=4:sts=4:ts=4
|
||||||
|
import re
|
||||||
|
import ox
|
||||||
|
|
||||||
|
|
||||||
def html_parser(text, nofollow=True):
|
def html_parser(text, nofollow=True):
|
||||||
text = text.replace('<i>', '__i__').replace('</i>', '__/i__')
|
text = text.replace('<i>', '__i__').replace('</i>', '__/i__')
|
||||||
text = text.replace('<b>', '__b__').replace('</b>', '__/b__')
|
text = text.replace('<b>', '__b__').replace('</b>', '__/b__')
|
||||||
#truns links into wiki links, make sure to only take http links
|
#truns links into wiki links, make sure to only take http links
|
||||||
text = re.sub('<a .*?href="(http.*?)".*?>(.*?)</a>', '[\\1 \\2]', text)
|
text = re.sub('<a .*?href="(http.*?)".*?>(.*?)</a>', '[\\1 \\2]', text)
|
||||||
text = escape(text)
|
text = ox.escape(text)
|
||||||
text = text.replace('__i__', '<i>').replace('__/i__', '</i>')
|
text = text.replace('__i__', '<i>').replace('__/i__', '</i>')
|
||||||
text = text.replace('__b__', '<b>').replace('__/b__', '</b>')
|
text = text.replace('__b__', '<b>').replace('__/b__', '</b>')
|
||||||
if nofollow:
|
if nofollow:
|
||||||
nofollow_rel = ' rel="nofollow"'
|
nofollow_rel = ' rel="nofollow"'
|
||||||
else:
|
else:
|
||||||
nofollow_rel = ''
|
nofollow_rel = ''
|
||||||
|
|
||||||
links = re.compile('(\[(http.*?) (.*?)\])').findall(text)
|
links = re.compile('(\[(http.*?) (.*?)\])').findall(text)
|
||||||
for t, link, txt in links:
|
for t, link, txt in links:
|
||||||
link = link.replace('http', '__LINK__').replace('.', '__DOT__')
|
link = link.replace('http', '__LINK__').replace('.', '__DOT__')
|
||||||
|
@ -24,8 +27,8 @@ def html_parser(text, nofollow=True):
|
||||||
link = link.replace('http', '__LINK__').replace('.', '__DOT__')
|
link = link.replace('http', '__LINK__').replace('.', '__DOT__')
|
||||||
ll = '<a href="%s"%s>%s</a>' % (link, nofollow_rel, link)
|
ll = '<a href="%s"%s>%s</a>' % (link, nofollow_rel, link)
|
||||||
text = text.replace(t, ll)
|
text = text.replace(t, ll)
|
||||||
|
|
||||||
text = urlize(text, nofollow=nofollow)
|
text = ox.urlize(text, nofollow=nofollow)
|
||||||
|
|
||||||
#inpage links
|
#inpage links
|
||||||
text = re.sub('\[(/.+?) (.+?)\]', '<a href="\\1">\\2</a>', text)
|
text = re.sub('\[(/.+?) (.+?)\]', '<a href="\\1">\\2</a>', text)
|
||||||
|
@ -33,4 +36,3 @@ def html_parser(text, nofollow=True):
|
||||||
text = text.replace('__LINK__', 'http').replace('__DOT__', '.')
|
text = text.replace('__LINK__', 'http').replace('__DOT__', '.')
|
||||||
text = text.replace("\n", '<br />')
|
text = text.replace("\n", '<br />')
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
import os.path
|
|
||||||
import re
|
|
||||||
from datetime import datetime
|
|
||||||
from urllib2 import unquote
|
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db.models import Q, Avg, Count, Sum
|
|
||||||
from django.http import HttpResponse, Http404
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.utils import json
|
||||||
from ox.django.decorators import login_required_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.shortcuts import render_to_json_response, get_object_or_404_json, json_response
|
||||||
from ox.django.http import HttpFileResponse
|
|
||||||
import ox
|
|
||||||
|
|
||||||
import models
|
import models
|
||||||
from api.actions import actions
|
from api.actions import actions
|
||||||
|
@ -48,6 +31,7 @@ def findAnnotation(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(findAnnotation)
|
actions.register(findAnnotation)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def addAnnotation(request):
|
def addAnnotation(request):
|
||||||
'''
|
'''
|
||||||
|
@ -67,18 +51,18 @@ def addAnnotation(request):
|
||||||
data = json.loads(request.POST['data'])
|
data = json.loads(request.POST['data'])
|
||||||
for key in ('item', 'layer', 'start', 'end', 'value'):
|
for key in ('item', 'layer', 'start', 'end', 'value'):
|
||||||
if key not in data:
|
if key not in data:
|
||||||
return render_to_json_response(json_response(status=400, text='invalid data'))
|
return render_to_json_response(json_response(status=400,
|
||||||
|
text='invalid data'))
|
||||||
|
|
||||||
item = get_object_or_404_json(models.Item, itemId=data['item'])
|
item = get_object_or_404_json(models.Item, itemId=data['item'])
|
||||||
layer = get_object_or_404_json(models.Layer, layerId=data['layer'])
|
layer = get_object_or_404_json(models.Layer, layerId=data['layer'])
|
||||||
|
|
||||||
annotation = models.Annotation(
|
annotation = models.Annotation(
|
||||||
item=item,
|
item=item,
|
||||||
layer=layer,
|
layer=layer,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
start=float(data['start']), end=float(data['end']),
|
start=float(data['start']), end=float(data['end']),
|
||||||
value=data['value']
|
value=data['value'])
|
||||||
)
|
|
||||||
annotation.save()
|
annotation.save()
|
||||||
response = json_response()
|
response = json_response()
|
||||||
response['data']['annotation'] = annotation.json()
|
response['data']['annotation'] = annotation.json()
|
||||||
|
@ -88,6 +72,7 @@ def addAnnotation(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(addAnnotation)
|
actions.register(addAnnotation)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def removeAnnotation(request):
|
def removeAnnotation(request):
|
||||||
'''
|
'''
|
||||||
|
@ -103,6 +88,7 @@ def removeAnnotation(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(removeAnnotation)
|
actions.register(removeAnnotation)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def editAnnotation(request):
|
def editAnnotation(request):
|
||||||
'''
|
'''
|
||||||
|
@ -129,4 +115,3 @@ def editAnnotation(request):
|
||||||
response = json_response(status=501, text='not implemented')
|
response = json_response(status=501, text='not implemented')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(editAnnotation)
|
actions.register(editAnnotation)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ def autodiscover():
|
||||||
import_module('%s.views'%app)
|
import_module('%s.views'%app)
|
||||||
except:
|
except:
|
||||||
if module_has_submodule(mod, 'views'):
|
if module_has_submodule(mod, 'views'):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def trim(docstring):
|
def trim(docstring):
|
||||||
|
@ -46,8 +46,11 @@ def trim(docstring):
|
||||||
# Return a single string:
|
# Return a single string:
|
||||||
return '\n'.join(trimmed)
|
return '\n'.join(trimmed)
|
||||||
|
|
||||||
|
|
||||||
class ApiActions(dict):
|
class ApiActions(dict):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
def api(request):
|
def api(request):
|
||||||
'''
|
'''
|
||||||
returns list of all known api action
|
returns list of all known api action
|
||||||
|
@ -56,7 +59,8 @@ class ApiActions(dict):
|
||||||
'''
|
'''
|
||||||
actions = self.keys()
|
actions = self.keys()
|
||||||
actions.sort()
|
actions.sort()
|
||||||
return render_to_json_response(json_response({'actions': actions}))
|
response = json_response({'actions': actions})
|
||||||
|
return render_to_json_response(response)
|
||||||
self['api'] = api
|
self['api'] = api
|
||||||
|
|
||||||
def apidoc(request):
|
def apidoc(request):
|
||||||
|
|
|
@ -1,54 +1,32 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
import os.path
|
|
||||||
import re
|
|
||||||
from datetime import datetime
|
|
||||||
from urllib2 import unquote
|
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from django import forms
|
from django.shortcuts import render_to_response
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db.models import Q, Avg, Count, Sum
|
|
||||||
from django.http import HttpResponse, Http404
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.django.shortcuts import render_to_json_response, json_response
|
||||||
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 ox
|
|
||||||
|
|
||||||
import models
|
|
||||||
|
|
||||||
from pandora.user.models import get_user_json
|
from pandora.user.models import get_user_json
|
||||||
|
|
||||||
from pandora.archive.models import File
|
|
||||||
from pandora.archive import extract
|
|
||||||
|
|
||||||
|
|
||||||
from actions import actions
|
from actions import actions
|
||||||
|
|
||||||
|
|
||||||
def api(request):
|
def api(request):
|
||||||
if request.META['REQUEST_METHOD'] == "OPTIONS":
|
if request.META['REQUEST_METHOD'] == "OPTIONS":
|
||||||
response = HttpResponse('')
|
response = render_to_json_response({'status': {'code': 200,
|
||||||
response = render_to_json_response({'status': {'code': 200, 'text': 'use POST'}})
|
'text': 'use POST'}})
|
||||||
response['Access-Control-Allow-Origin'] = '*'
|
response['Access-Control-Allow-Origin'] = '*'
|
||||||
return response
|
return response
|
||||||
if not 'action' in request.POST:
|
if not 'action' in request.POST:
|
||||||
methods = actions.keys()
|
methods = actions.keys()
|
||||||
api = []
|
api = []
|
||||||
for f in sorted(methods):
|
for f in sorted(methods):
|
||||||
api.append({
|
api.append({'name': f,
|
||||||
'name': f,
|
'doc': actions.doc(f).replace('\n', '<br>\n')})
|
||||||
'doc': actions.doc(f).replace('\n', '<br>\n')
|
|
||||||
})
|
|
||||||
context = RequestContext(request, {'api': api,
|
context = RequestContext(request, {'api': api,
|
||||||
'sitename': settings.SITENAME,})
|
'sitename': settings.SITENAME})
|
||||||
return render_to_response('api.html', context)
|
return render_to_response('api.html', context)
|
||||||
function = request.POST['action']
|
function = request.POST['action']
|
||||||
#FIXME: possible to do this in f
|
#FIXME: possible to do this in f
|
||||||
|
@ -63,6 +41,7 @@ def api(request):
|
||||||
response['Access-Control-Allow-Origin'] = '*'
|
response['Access-Control-Allow-Origin'] = '*'
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def hello(request):
|
def hello(request):
|
||||||
'''
|
'''
|
||||||
return {'status': {'code': int, 'text': string},
|
return {'status': {'code': int, 'text': string},
|
||||||
|
@ -73,15 +52,17 @@ def hello(request):
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
response['data']['user'] = get_user_json(request.user)
|
response['data']['user'] = get_user_json(request.user)
|
||||||
else:
|
else:
|
||||||
response['data']['user'] = {'name': 'Guest', 'group': 'guest', 'preferences': {}}
|
response['data']['user'] = {'name': 'Guest',
|
||||||
|
'group': 'guest',
|
||||||
|
'preferences': {}}
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(hello)
|
actions.register(hello)
|
||||||
|
|
||||||
|
|
||||||
def error(request):
|
def error(request):
|
||||||
'''
|
'''
|
||||||
this action is used to test api error codes, it should return a 503 error
|
this action is used to test api error codes, it should return a 503 error
|
||||||
'''
|
'''
|
||||||
success = error_is_success
|
success = error_is_success
|
||||||
return render_to_json_response({})
|
return render_to_json_response({})
|
||||||
actions.register(error)
|
actions.register(error)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.contrib import admin
|
||||||
|
|
||||||
import models
|
import models
|
||||||
|
|
||||||
|
|
||||||
class PageAdmin(admin.ModelAdmin):
|
class PageAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name', 'body']
|
search_fields = ['name', 'body']
|
||||||
|
|
||||||
|
@ -15,4 +16,3 @@ class SiteSettingsAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['key', 'value']
|
search_fields = ['key', 'value']
|
||||||
|
|
||||||
admin.site.register(models.SiteSettings, SiteSettingsAdmin)
|
admin.site.register(models.SiteSettings, SiteSettingsAdmin)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
class Page(models.Model):
|
class Page(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
@ -11,10 +12,10 @@ class Page(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class SiteSettings(models.Model):
|
class SiteSettings(models.Model):
|
||||||
key = models.CharField(max_length=1024, unique=True)
|
key = models.CharField(max_length=1024, unique=True)
|
||||||
value = models.TextField(blank=True)
|
value = models.TextField(blank=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.key
|
return self.key
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
|
@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,32 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
|
from django.shortcuts import render_to_response
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from ox.django.shortcuts import json_response, render_to_json_response, get_object_or_404_json
|
from ox.django.shortcuts import json_response, render_to_json_response, get_object_or_404_json
|
||||||
|
from ox.utils import json
|
||||||
|
|
||||||
import models
|
import models
|
||||||
|
|
||||||
from item.models import siteJson
|
|
||||||
|
|
||||||
from api.actions import actions
|
from api.actions import actions
|
||||||
|
|
||||||
|
|
||||||
def intro(request):
|
def intro(request):
|
||||||
context = RequestContext(request, {'settings':settings})
|
context = RequestContext(request, {'settings': settings})
|
||||||
return render_to_response('intro.html', context)
|
return render_to_response('intro.html', context)
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
context = RequestContext(request, {'settings':settings})
|
context = RequestContext(request, {'settings': settings})
|
||||||
if request.GET.get('_escaped_fragment_', None):
|
|
||||||
return html_snapshot(request)
|
|
||||||
return render_to_response('index.html', context)
|
return render_to_response('index.html', context)
|
||||||
|
|
||||||
|
|
||||||
def timeline(request):
|
def timeline(request):
|
||||||
context = RequestContext(request, {'settings':settings})
|
context = RequestContext(request, {'settings': settings})
|
||||||
return render_to_response('timeline.html', context)
|
return render_to_response('timeline.html', context)
|
||||||
|
|
||||||
|
|
||||||
def getPage(request):
|
def getPage(request):
|
||||||
data = json.loads(request.POST['data'])
|
data = json.loads(request.POST['data'])
|
||||||
name = data['page']
|
name = data['page']
|
||||||
|
@ -34,6 +35,7 @@ def getPage(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(getPage)
|
actions.register(getPage)
|
||||||
|
|
||||||
|
|
||||||
def site_json(request):
|
def site_json(request):
|
||||||
'''
|
'''
|
||||||
return render_to_json_response(siteJson())
|
return render_to_json_response(siteJson())
|
||||||
|
@ -41,6 +43,7 @@ def site_json(request):
|
||||||
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,
|
||||||
return render_to_response('site.json', context, mimetype="application/javascript")
|
'siteSettings': siteSettings})
|
||||||
|
return render_to_response('site.json', context,
|
||||||
|
mimetype="application/javascript")
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.contrib import admin
|
||||||
from forms import FileAdminForm, InstanceAdminForm
|
from forms import FileAdminForm, InstanceAdminForm
|
||||||
import models
|
import models
|
||||||
|
|
||||||
|
|
||||||
class FileAdmin(admin.ModelAdmin):
|
class FileAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name', 'video_codec']
|
search_fields = ['name', 'video_codec']
|
||||||
list_display = ['available', 'is_main', '__unicode__', 'itemId']
|
list_display = ['available', 'is_main', '__unicode__', 'itemId']
|
||||||
|
@ -18,9 +19,9 @@ class FileAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
admin.site.register(models.File, FileAdmin)
|
admin.site.register(models.File, FileAdmin)
|
||||||
|
|
||||||
|
|
||||||
class InstanceAdmin(admin.ModelAdmin):
|
class InstanceAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name', 'folder', 'volume__name']
|
search_fields = ['name', 'folder', 'volume__name']
|
||||||
form = InstanceAdminForm
|
form = InstanceAdminForm
|
||||||
|
|
||||||
admin.site.register(models.Instance, InstanceAdmin)
|
admin.site.register(models.Instance, InstanceAdmin)
|
||||||
|
|
||||||
|
|
|
@ -3,33 +3,31 @@
|
||||||
from __future__ import division, with_statement
|
from __future__ import division, with_statement
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from os.path import abspath, join, dirname, exists
|
from os.path import exists
|
||||||
|
|
||||||
import fractions
|
import fractions
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import shutil
|
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import re
|
|
||||||
import math
|
import math
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import Image
|
import Image
|
||||||
import ox
|
|
||||||
from ox.utils import json
|
|
||||||
|
|
||||||
|
|
||||||
img_extension='jpg'
|
img_extension='jpg'
|
||||||
|
|
||||||
FFMPEG2THEORA = 'ffmpeg2theora'
|
FFMPEG2THEORA = 'ffmpeg2theora'
|
||||||
|
|
||||||
|
|
||||||
class AspectRatio(fractions.Fraction):
|
class AspectRatio(fractions.Fraction):
|
||||||
|
|
||||||
def __new__(cls, numerator, denominator=None):
|
def __new__(cls, numerator, denominator=None):
|
||||||
if not denominator:
|
if not denominator:
|
||||||
ratio = map(int, numerator.split(':'))
|
ratio = map(int, numerator.split(':'))
|
||||||
if len(ratio) == 1: ratio.append(1)
|
if len(ratio) == 1:
|
||||||
|
ratio.append(1)
|
||||||
numerator = ratio[0]
|
numerator = ratio[0]
|
||||||
denominator = ratio[1]
|
denominator = ratio[1]
|
||||||
#if its close enough to the common aspect ratios rather use that
|
#if its close enough to the common aspect ratios rather use that
|
||||||
|
@ -45,6 +43,7 @@ class AspectRatio(fractions.Fraction):
|
||||||
def ratio(self):
|
def ratio(self):
|
||||||
return "%d:%d" % (self.numerator, self.denominator)
|
return "%d:%d" % (self.numerator, self.denominator)
|
||||||
|
|
||||||
|
|
||||||
def stream(video, target, profile, info):
|
def stream(video, target, profile, info):
|
||||||
if not os.path.exists(target):
|
if not os.path.exists(target):
|
||||||
fdir = os.path.dirname(target)
|
fdir = os.path.dirname(target)
|
||||||
|
@ -118,8 +117,8 @@ def stream(video, target, profile, info):
|
||||||
bpp = 0.17
|
bpp = 0.17
|
||||||
fps = AspectRatio(info['video'][0]['framerate'])
|
fps = AspectRatio(info['video'][0]['framerate'])
|
||||||
|
|
||||||
width = int(dar * height)
|
width = int(dar * height)
|
||||||
width += width % 2
|
width += width % 2
|
||||||
|
|
||||||
bitrate = height*width*fps*bpp/1000
|
bitrate = height*width*fps*bpp/1000
|
||||||
aspect = dar.ratio
|
aspect = dar.ratio
|
||||||
|
@ -184,7 +183,7 @@ def stream(video, target, profile, info):
|
||||||
'-me_range', '16',
|
'-me_range', '16',
|
||||||
'-g', '250', #FIXME: should this be related to fps?
|
'-g', '250', #FIXME: should this be related to fps?
|
||||||
'-keyint_min', '25', #FIXME: should this be related to fps?
|
'-keyint_min', '25', #FIXME: should this be related to fps?
|
||||||
'-sc_threshold','40',
|
'-sc_threshold', '40',
|
||||||
'-i_qfactor', '0.71',
|
'-i_qfactor', '0.71',
|
||||||
'-qmin', '10', '-qmax', '51',
|
'-qmin', '10', '-qmax', '51',
|
||||||
'-qdiff', '4'
|
'-qdiff', '4'
|
||||||
|
@ -200,19 +199,20 @@ def stream(video, target, profile, info):
|
||||||
if format == 'mp4':
|
if format == 'mp4':
|
||||||
cmd += ["%s.mp4"%target]
|
cmd += ["%s.mp4"%target]
|
||||||
else:
|
else:
|
||||||
cmd += ['-f','webm', target]
|
cmd += ['-f', 'webm', target]
|
||||||
|
|
||||||
print cmd
|
print cmd
|
||||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT)
|
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT)
|
||||||
p.communicate()
|
p.communicate()
|
||||||
if format == 'mp4':
|
if format == 'mp4':
|
||||||
cmd = ['qt-faststart', "%s.mp4"%target, target]
|
cmd = ['qt-faststart', "%s.mp4"%target, target]
|
||||||
print cmd
|
print cmd
|
||||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT)
|
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT)
|
||||||
p.communicate()
|
p.communicate()
|
||||||
os.unlink("%s.mp4"%target)
|
os.unlink("%s.mp4"%target)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def run_command(cmd, timeout=10):
|
def run_command(cmd, timeout=10):
|
||||||
#print cmd
|
#print cmd
|
||||||
p = subprocess.Popen(cmd, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT)
|
p = subprocess.Popen(cmd, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT)
|
||||||
|
@ -226,6 +226,7 @@ def run_command(cmd, timeout=10):
|
||||||
killedpid, stat = os.waitpid(p.pid, os.WNOHANG)
|
killedpid, stat = os.waitpid(p.pid, os.WNOHANG)
|
||||||
return p.returncode
|
return p.returncode
|
||||||
|
|
||||||
|
|
||||||
def frame(videoFile, frame, position, width=128, redo=False):
|
def frame(videoFile, frame, position, width=128, redo=False):
|
||||||
'''
|
'''
|
||||||
params:
|
params:
|
||||||
|
@ -243,6 +244,7 @@ def frame(videoFile, frame, position, width=128, redo=False):
|
||||||
cmd = ['oxframe', '-i', videoFile, '-o', frame, '-p', str(position), '-x', str(width)]
|
cmd = ['oxframe', '-i', videoFile, '-o', frame, '-p', str(position), '-x', str(width)]
|
||||||
run_command(cmd)
|
run_command(cmd)
|
||||||
|
|
||||||
|
|
||||||
def resize_image(image_source, image_output, width=None, size=None):
|
def resize_image(image_source, image_output, width=None, size=None):
|
||||||
if exists(image_source):
|
if exists(image_source):
|
||||||
source = Image.open(image_source).convert('RGB')
|
source = Image.open(image_source).convert('RGB')
|
||||||
|
@ -257,7 +259,7 @@ def resize_image(image_source, image_output, width=None, size=None):
|
||||||
height = size
|
height = size
|
||||||
width = int(height * (float(source_width) / source_height))
|
width = int(height * (float(source_width) / source_height))
|
||||||
width = width - width % 2
|
width = width - width % 2
|
||||||
|
|
||||||
else:
|
else:
|
||||||
height = int(width / (float(source_width) / source_height))
|
height = int(width / (float(source_width) / source_height))
|
||||||
height = height - height % 2
|
height = height - height % 2
|
||||||
|
@ -269,12 +271,13 @@ def resize_image(image_source, image_output, width=None, size=None):
|
||||||
output = source.resize((width, height), resize_method)
|
output = source.resize((width, height), resize_method)
|
||||||
output.save(image_output)
|
output.save(image_output)
|
||||||
|
|
||||||
|
|
||||||
def timeline(video, prefix):
|
def timeline(video, prefix):
|
||||||
cmd = ['oxtimeline', '-i', video, '-o', prefix]
|
cmd = ['oxtimeline', '-i', video, '-o', prefix]
|
||||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
p.wait()
|
p.wait()
|
||||||
|
|
||||||
#stats based on timeline images
|
|
||||||
def average_color(prefix):
|
def average_color(prefix):
|
||||||
height = 64
|
height = 64
|
||||||
width = 1500
|
width = 1500
|
||||||
|
@ -294,10 +297,12 @@ def average_color(prefix):
|
||||||
color += p
|
color += p
|
||||||
return list(map(float, color))
|
return list(map(float, color))
|
||||||
|
|
||||||
|
|
||||||
def get_distance(rgb0, rgb1):
|
def get_distance(rgb0, rgb1):
|
||||||
dst = math.sqrt(pow(rgb0[0] - rgb1[0], 2) + pow(rgb0[0] - rgb1[0], 2) + pow(rgb0[0] - rgb1[0], 2))
|
dst = math.sqrt(pow(rgb0[0] - rgb1[0], 2) + pow(rgb0[0] - rgb1[0], 2) + pow(rgb0[0] - rgb1[0], 2))
|
||||||
return dst / math.sqrt(3 * pow(255, 2))
|
return dst / math.sqrt(3 * pow(255, 2))
|
||||||
|
|
||||||
|
|
||||||
def cuts(prefix):
|
def cuts(prefix):
|
||||||
cuts = []
|
cuts = []
|
||||||
fps = 25
|
fps = 25
|
||||||
|
@ -324,6 +329,7 @@ def cuts(prefix):
|
||||||
cuts.append(frame / fps)
|
cuts.append(frame / fps)
|
||||||
return cuts
|
return cuts
|
||||||
|
|
||||||
|
|
||||||
def divide(num, by):
|
def divide(num, by):
|
||||||
# >>> divide(100, 3)
|
# >>> divide(100, 3)
|
||||||
# [33, 33, 34]
|
# [33, 33, 34]
|
||||||
|
@ -334,9 +340,10 @@ def divide(num, by):
|
||||||
arr.append(div + (i > by - 1 - mod))
|
arr.append(div + (i > by - 1 - mod))
|
||||||
return arr
|
return arr
|
||||||
|
|
||||||
|
|
||||||
def timeline_strip(item, cuts, info, prefix):
|
def timeline_strip(item, cuts, info, prefix):
|
||||||
_debug = False
|
_debug = False
|
||||||
duration = info['duration']
|
duration = info['duration']
|
||||||
video_height = info['video'][0]['height']
|
video_height = info['video'][0]['height']
|
||||||
video_width = info['video'][0]['width']
|
video_width = info['video'][0]['width']
|
||||||
video_ratio = video_width / video_height
|
video_ratio = video_width / video_height
|
||||||
|
@ -392,6 +399,7 @@ def timeline_strip(item, cuts, info, prefix):
|
||||||
print 'writing', timeline_file
|
print 'writing', timeline_file
|
||||||
timeline_image.save(timeline_file)
|
timeline_image.save(timeline_file)
|
||||||
|
|
||||||
|
|
||||||
def chop(video, start, end):
|
def chop(video, start, end):
|
||||||
t = end - start
|
t = end - start
|
||||||
tmp = tempfile.mkdtemp()
|
tmp = tempfile.mkdtemp()
|
||||||
|
@ -401,7 +409,7 @@ def chop(video, start, end):
|
||||||
'-y',
|
'-y',
|
||||||
'-i', video,
|
'-i', video,
|
||||||
'-ss', '%.3f'%start,
|
'-ss', '%.3f'%start,
|
||||||
'-t','%.3f'%t,
|
'-t', '%.3f'%t,
|
||||||
'-vcodec', 'copy',
|
'-vcodec', 'copy',
|
||||||
'-acodec', 'copy',
|
'-acodec', 'copy',
|
||||||
'-f', 'webm',
|
'-f', 'webm',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from ajax_filtered_fields.forms import AjaxManyToManyField, ForeignKeyByLetter
|
from ajax_filtered_fields.forms import ForeignKeyByLetter
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@ ajax_filtered_js = (
|
||||||
settings.STATIC_URL + 'js/jquery/jquery.js',
|
settings.STATIC_URL + 'js/jquery/jquery.js',
|
||||||
settings.STATIC_URL + 'js/ajax_filtered_fields.js',
|
settings.STATIC_URL + 'js/ajax_filtered_fields.js',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FileAdminForm(forms.ModelForm):
|
class FileAdminForm(forms.ModelForm):
|
||||||
item = ForeignKeyByLetter(models.Item, field_name='itemId')
|
item = ForeignKeyByLetter(models.Item, field_name='itemId')
|
||||||
|
|
||||||
|
@ -28,4 +30,3 @@ class InstanceAdminForm(forms.ModelForm):
|
||||||
|
|
||||||
class Media:
|
class Media:
|
||||||
js = ajax_filtered_js
|
js = ajax_filtered_js
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,23 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from datetime import datetime
|
|
||||||
import os.path
|
import os.path
|
||||||
import random
|
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.files.base import ContentFile
|
|
||||||
from django.utils import simplejson as json
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from ox.django import fields
|
from ox.django import fields
|
||||||
import ox
|
import ox
|
||||||
from ox import stripTags
|
from ox.normalize import canonicalTitle
|
||||||
from ox.normalize import canonicalTitle, canonicalName
|
|
||||||
from firefogg import Firefogg
|
|
||||||
import chardet
|
import chardet
|
||||||
|
|
||||||
from item import utils
|
from item import utils
|
||||||
from item.models import Item
|
from item.models import Item
|
||||||
|
|
||||||
import extract
|
|
||||||
|
|
||||||
|
|
||||||
class File(models.Model):
|
class File(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
@ -37,7 +29,7 @@ class File(models.Model):
|
||||||
item = models.ForeignKey(Item, related_name='files')
|
item = models.ForeignKey(Item, related_name='files')
|
||||||
|
|
||||||
name = models.CharField(max_length=2048, default="") # canoncial path/file
|
name = models.CharField(max_length=2048, default="") # canoncial path/file
|
||||||
sort_name = models.CharField(max_length=2048, default="") # sort path/file name
|
sort_name = models.CharField(max_length=2048, default="") # sort name
|
||||||
|
|
||||||
part = models.CharField(default="", max_length=255)
|
part = models.CharField(default="", max_length=255)
|
||||||
version = models.CharField(default="", max_length=255) # sort path/file name
|
version = models.CharField(default="", max_length=255) # sort path/file name
|
||||||
|
@ -146,13 +138,14 @@ class File(models.Model):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def srt(self):
|
def srt(self):
|
||||||
|
|
||||||
def _detectEncoding(fp):
|
def _detectEncoding(fp):
|
||||||
bomDict={ # bytepattern : name
|
bomDict={ # bytepattern : name
|
||||||
(0x00, 0x00, 0xFE, 0xFF) : "utf_32_be",
|
(0x00, 0x00, 0xFE, 0xFF): "utf_32_be",
|
||||||
(0xFF, 0xFE, 0x00, 0x00) : "utf_32_le",
|
(0xFF, 0xFE, 0x00, 0x00): "utf_32_le",
|
||||||
(0xFE, 0xFF, None, None) : "utf_16_be",
|
(0xFE, 0xFF, None, None): "utf_16_be",
|
||||||
(0xFF, 0xFE, None, None) : "utf_16_le",
|
(0xFF, 0xFE, None, None): "utf_16_le",
|
||||||
(0xEF, 0xBB, 0xBF, None) : "utf_8",
|
(0xEF, 0xBB, 0xBF, None): "utf_8",
|
||||||
}
|
}
|
||||||
|
|
||||||
# go to beginning of file and get the first 4 bytes
|
# go to beginning of file and get the first 4 bytes
|
||||||
|
@ -162,15 +155,15 @@ class File(models.Model):
|
||||||
|
|
||||||
# try bom detection using 4 bytes, 3 bytes, or 2 bytes
|
# try bom detection using 4 bytes, 3 bytes, or 2 bytes
|
||||||
bomDetection = bomDict.get((byte1, byte2, byte3, byte4))
|
bomDetection = bomDict.get((byte1, byte2, byte3, byte4))
|
||||||
if not bomDetection :
|
if not bomDetection:
|
||||||
bomDetection = bomDict.get((byte1, byte2, byte3, None))
|
bomDetection = bomDict.get((byte1, byte2, byte3, None))
|
||||||
if not bomDetection :
|
if not bomDetection:
|
||||||
bomDetection = bomDict.get((byte1, byte2, None, None))
|
bomDetection = bomDict.get((byte1, byte2, None, None))
|
||||||
|
|
||||||
## if BOM detected, we're done :-)
|
## if BOM detected, we're done :-)
|
||||||
fp.seek(oldFP)
|
fp.seek(oldFP)
|
||||||
if bomDetection :
|
if bomDetection:
|
||||||
return bomDetection
|
return bomDetection
|
||||||
|
|
||||||
encoding = 'latin-1'
|
encoding = 'latin-1'
|
||||||
#more character detecting magick using http://chardet.feedparser.org/
|
#more character detecting magick using http://chardet.feedparser.org/
|
||||||
|
@ -221,7 +214,9 @@ class File(models.Model):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Volume(models.Model):
|
class Volume(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("user", "name")
|
unique_together = ("user", "name")
|
||||||
|
|
||||||
|
@ -234,7 +229,9 @@ class Volume(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"%s's %s"% (self.user, self.name)
|
return u"%s's %s"% (self.user, self.name)
|
||||||
|
|
||||||
|
|
||||||
class Instance(models.Model):
|
class Instance(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("name", "folder", "volume")
|
unique_together = ("name", "folder", "volume")
|
||||||
|
|
||||||
|
@ -258,12 +255,15 @@ class Instance(models.Model):
|
||||||
def itemId(self):
|
def itemId(self):
|
||||||
return File.objects.get(oshash=self.oshash).itemId
|
return File.objects.get(oshash=self.oshash).itemId
|
||||||
|
|
||||||
|
|
||||||
def frame_path(frame, name):
|
def frame_path(frame, name):
|
||||||
ext = os.path.splitext(name)[-1]
|
ext = os.path.splitext(name)[-1]
|
||||||
name = "%s%s" % (frame.position, ext)
|
name = "%s%s" % (frame.position, ext)
|
||||||
return frame.file.path(name)
|
return frame.file.path(name)
|
||||||
|
|
||||||
|
|
||||||
class Frame(models.Model):
|
class Frame(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("file", "position")
|
unique_together = ("file", "position")
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
@ -282,5 +282,3 @@ class Frame(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'%s at %s' % (self.file, self.position)
|
return u'%s at %s' % (self.file, self.position)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from datetime import timedelta
|
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
|
|
||||||
from celery.decorators import task, periodic_task
|
from celery.decorators import task
|
||||||
|
|
||||||
from item.utils import oxid, parse_path
|
from item.utils import parse_path
|
||||||
from item.models import get_item
|
from item.models import get_item
|
||||||
import item.tasks
|
|
||||||
|
|
||||||
import models
|
import models
|
||||||
|
|
||||||
|
|
||||||
@task(ignore_resulsts=True, queue='default')
|
@task(ignore_resulsts=True, queue='default')
|
||||||
def update_files(user, volume, files):
|
def update_files(user, volume, files):
|
||||||
user = models.User.objects.get(username=user)
|
user = models.User.objects.get(username=user)
|
||||||
|
@ -33,9 +31,9 @@ def update_files(user, volume, files):
|
||||||
|
|
||||||
same_folder = models.Instance.objects.filter(folder=folder, volume=volume)
|
same_folder = models.Instance.objects.filter(folder=folder, volume=volume)
|
||||||
if same_folder.count() > 0:
|
if same_folder.count() > 0:
|
||||||
item = same_folder[0].file.item
|
i = same_folder[0].file.item
|
||||||
else:
|
else:
|
||||||
item = None
|
i = None
|
||||||
|
|
||||||
path = os.path.join(folder, name)
|
path = os.path.join(folder, name)
|
||||||
|
|
||||||
|
@ -48,7 +46,7 @@ def update_files(user, volume, files):
|
||||||
setattr(instance, key, f[key])
|
setattr(instance, key, f[key])
|
||||||
updated=True
|
updated=True
|
||||||
if updated:
|
if updated:
|
||||||
instance.save()
|
instance.save()
|
||||||
else:
|
else:
|
||||||
#look if oshash is known
|
#look if oshash is known
|
||||||
file_objects = models.File.objects.filter(oshash=oshash)
|
file_objects = models.File.objects.filter(oshash=oshash)
|
||||||
|
@ -56,13 +54,13 @@ def update_files(user, volume, files):
|
||||||
file_object = file_objects[0]
|
file_object = file_objects[0]
|
||||||
#new oshash, add to database
|
#new oshash, add to database
|
||||||
else:
|
else:
|
||||||
if not item:
|
if not i:
|
||||||
item_info = parse_path(folder)
|
item_info = parse_path(folder)
|
||||||
item = get_item(item_info)
|
i = get_item(item_info)
|
||||||
file_object = models.File()
|
file_object = models.File()
|
||||||
file_object.oshash = oshash
|
file_object.oshash = oshash
|
||||||
file_object.name = name
|
file_object.name = name
|
||||||
file_object.item = item
|
file_object.item = i
|
||||||
file_object.save()
|
file_object.save()
|
||||||
instance = models.Instance()
|
instance = models.Instance()
|
||||||
instance.volume = volume
|
instance.volume = volume
|
||||||
|
@ -74,4 +72,3 @@ def update_files(user, volume, files):
|
||||||
#remove deleted files
|
#remove deleted files
|
||||||
#FIXME: can this have any bad consequences? i.e. on the selction of used item files.
|
#FIXME: can this have any bad consequences? i.e. on the selction of used item files.
|
||||||
models.Instance.objects.filter(volume=volume).exclude(file__oshash__in=all_files).delete()
|
models.Instance.objects.filter(volume=volume).exclude(file__oshash__in=all_files).delete()
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
|
@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,18 @@
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from urllib2 import unquote
|
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.paginator import Paginator
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db.models import Q, Avg, Count, Sum
|
|
||||||
from django.http import HttpResponse, Http404
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.utils import json
|
||||||
from ox.django.decorators import login_required_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.shortcuts import render_to_json_response, get_object_or_404_json, json_response
|
||||||
from ox.django.http import HttpFileResponse
|
|
||||||
from ox.django.views import task_status
|
from ox.django.views import task_status
|
||||||
import ox
|
|
||||||
|
|
||||||
from item.utils import oxid, parse_path
|
from item.utils import parse_path
|
||||||
from item.models import get_item
|
from item.models import get_item
|
||||||
import item.tasks
|
import item.tasks
|
||||||
from api.actions import actions
|
from api.actions import actions
|
||||||
|
@ -47,6 +36,7 @@ def removeVolume(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(removeVolume)
|
actions.register(removeVolume)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def update(request):
|
def update(request):
|
||||||
'''
|
'''
|
||||||
|
@ -111,12 +101,14 @@ def update(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(update)
|
actions.register(update)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def encodingProfile(request):
|
def encodingProfile(request):
|
||||||
response = json_response({'profile': settings.VIDEO_PROFILE})
|
response = json_response({'profile': settings.VIDEO_PROFILE})
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(encodingProfile)
|
actions.register(encodingProfile)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def upload(request):
|
def upload(request):
|
||||||
'''
|
'''
|
||||||
|
@ -157,11 +149,13 @@ def upload(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(upload)
|
actions.register(upload)
|
||||||
|
|
||||||
|
|
||||||
class VideoChunkForm(forms.Form):
|
class VideoChunkForm(forms.Form):
|
||||||
chunk = forms.FileField()
|
chunk = forms.FileField()
|
||||||
chunkId = forms.IntegerField(required=False)
|
chunkId = forms.IntegerField(required=False)
|
||||||
done = forms.IntegerField(required=False)
|
done = forms.IntegerField(required=False)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def firefogg_upload(request):
|
def firefogg_upload(request):
|
||||||
profile = request.GET['profile']
|
profile = request.GET['profile']
|
||||||
|
@ -189,7 +183,7 @@ def firefogg_upload(request):
|
||||||
#FIXME: this fails badly if rabbitmq goes down
|
#FIXME: this fails badly if rabbitmq goes down
|
||||||
try:
|
try:
|
||||||
t = item.tasks.update_streams.delay((f.item.itemId))
|
t = item.tasks.update_streams.delay((f.item.itemId))
|
||||||
data['resultUrl'] = t.task_id
|
response['resultUrl'] = t.task_id
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
response['result'] = 1
|
response['result'] = 1
|
||||||
|
@ -213,6 +207,7 @@ def firefogg_upload(request):
|
||||||
response = json_response(status=400, text='this request requires POST')
|
response = json_response(status=400, text='this request requires POST')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def taskStatus(request):
|
def taskStatus(request):
|
||||||
#FIXME: should check if user has permissions to get status
|
#FIXME: should check if user has permissions to get status
|
||||||
|
@ -223,6 +218,7 @@ def taskStatus(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(taskStatus)
|
actions.register(taskStatus)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def editFile(request):
|
def editFile(request):
|
||||||
'''
|
'''
|
||||||
|
@ -257,6 +253,7 @@ def editFile(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(editFile)
|
actions.register(editFile)
|
||||||
|
|
||||||
|
|
||||||
def lookup_file(request, oshash):
|
def lookup_file(request, oshash):
|
||||||
f = get_object_or_404(models.File, oshash=oshash)
|
f = get_object_or_404(models.File, oshash=oshash)
|
||||||
return redirect(f.item.get_absolute_url())
|
return redirect(f.item.get_absolute_url())
|
||||||
|
@ -270,34 +267,34 @@ def fileInfo(request):
|
||||||
'data': {imdbId:string }}
|
'data': {imdbId:string }}
|
||||||
'''
|
'''
|
||||||
if 'data' in request.POST:
|
if 'data' in request.POST:
|
||||||
oshash = json.loads(request.POST['data'])
|
oshash = json.loads(request.POST['data'])
|
||||||
elif 'oshash' in request.GET:
|
elif 'oshash' in request.GET:
|
||||||
oshash = request.GET['oshash']
|
oshash = request.GET['oshash']
|
||||||
f = models.ItemFile.objects.get(oshash=oshash)
|
f = models.ItemFile.objects.get(oshash=oshash)
|
||||||
response = {'data': f.json()}
|
response = {'data': f.json()}
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(fileInfo)
|
actions.register(fileInfo)
|
||||||
|
|
||||||
def subtitles(request):
|
def subtitles(request):
|
||||||
'''
|
'''
|
||||||
param data
|
param data
|
||||||
oshash string
|
oshash string
|
||||||
language string
|
language string
|
||||||
subtitle string
|
subtitle string
|
||||||
return
|
return
|
||||||
if no language is provided:
|
if no language is provided:
|
||||||
{data: {languages: array}}
|
{data: {languages: array}}
|
||||||
if language is set:
|
if language is set:
|
||||||
{data: {subtitle: string}}
|
{data: {subtitle: string}}
|
||||||
if subtitle is set:
|
if subtitle is set:
|
||||||
saves subtitle for given language
|
saves subtitle for given language
|
||||||
'''
|
'''
|
||||||
if 'data' in request.POST:
|
if 'data' in request.POST:
|
||||||
data = json.loads(request.POST['data'])
|
data = json.loads(request.POST['data'])
|
||||||
oshash = data['oshash']
|
oshash = data['oshash']
|
||||||
language = data.get('language', None)
|
language = data.get('language', None)
|
||||||
srt = data.get('subtitle', None)
|
srt = data.get('subtitle', None)
|
||||||
if srt:
|
if srt:
|
||||||
user = request.user
|
user = request.user
|
||||||
sub = models.Subtitles.objects.get_or_create(user, oshash, language)
|
sub = models.Subtitles.objects.get_or_create(user, oshash, language)
|
||||||
sub.srt = srt
|
sub.srt = srt
|
||||||
|
@ -307,8 +304,8 @@ def subtitles(request):
|
||||||
if language:
|
if language:
|
||||||
q = models.Subtitles.objects.filter(item_file__oshash=oshash, language=language)
|
q = models.Subtitles.objects.filter(item_file__oshash=oshash, language=language)
|
||||||
if q.count() > 0:
|
if q.count() > 0:
|
||||||
response['data']['subtitle'] = q[0].srt
|
response['data']['subtitle'] = q[0].srt
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
l = models.Subtitles.objects.filter(item_file__oshash=oshash).values('language')
|
l = models.Subtitles.objects.filter(item_file__oshash=oshash).values('language')
|
||||||
response['data']['languages'] = [f['language'] for f in l]
|
response['data']['languages'] = [f['language'] for f in l]
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
|
|
|
@ -9,4 +9,3 @@ import models
|
||||||
class DateAdmin(admin.ModelAdmin):
|
class DateAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name']
|
search_fields = ['name']
|
||||||
admin.site.register(models.Date, DateAdmin)
|
admin.site.register(models.Date, DateAdmin)
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
import re
|
|
||||||
|
|
||||||
from ox.utils import json
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from django.db.models import Q, Manager
|
from django.db.models import Q, Manager
|
||||||
|
|
||||||
import models
|
|
||||||
|
|
||||||
class DateManager(Manager):
|
class DateManager(Manager):
|
||||||
|
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
return super(DateManager, self).get_query_set()
|
return super(DateManager, self).get_query_set()
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,12 @@
|
||||||
from __future__ import division, with_statement
|
from __future__ import division, with_statement
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.django import fields
|
from ox.django import fields
|
||||||
|
|
||||||
import managers
|
import managers
|
||||||
|
|
||||||
|
|
||||||
class Date(models.Model):
|
class Date(models.Model):
|
||||||
'''
|
'''
|
||||||
Dates are dates in time that can be once or recurring,
|
Dates are dates in time that can be once or recurring,
|
||||||
|
@ -41,4 +40,3 @@ class Date(models.Model):
|
||||||
self.name_sort = self.name
|
self.name_sort = self.name
|
||||||
self.name_find = self.name + '||'.join(self.aliases)
|
self.name_find = self.name + '||'.join(self.aliases)
|
||||||
super(Date, self).save(*args, **kwargs)
|
super(Date, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
|
@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
import os.path
|
|
||||||
import re
|
|
||||||
from datetime import datetime
|
|
||||||
from urllib2 import unquote
|
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db.models import Q, Avg, Count, Sum
|
|
||||||
from django.http import HttpResponse, Http404
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.utils import json
|
||||||
|
|
||||||
from ox.django.decorators import login_required_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.shortcuts import render_to_json_response, get_object_or_404_json, json_response
|
||||||
from ox.django.http import HttpFileResponse
|
|
||||||
import ox
|
|
||||||
|
|
||||||
import models
|
import models
|
||||||
from api.actions import actions
|
from api.actions import actions
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def addDate(request):
|
def addDate(request):
|
||||||
data = json.loads(request.POST['data'])
|
data = json.loads(request.POST['data'])
|
||||||
|
@ -39,6 +22,7 @@ def addDate(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(addDate)
|
actions.register(addDate)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def editDate(request):
|
def editDate(request):
|
||||||
'''
|
'''
|
||||||
|
@ -69,17 +53,19 @@ def editDate(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(editDate)
|
actions.register(editDate)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def removeDate(request):
|
def removeDate(request):
|
||||||
response = json_response(status=501, text='not implemented')
|
response = json_response(status=501, text='not implemented')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(removeDate)
|
actions.register(removeDate)
|
||||||
|
|
||||||
|
|
||||||
def findDate(request):
|
def findDate(request):
|
||||||
'''
|
'''
|
||||||
param data
|
param data
|
||||||
{'query': query, 'sort': array, 'range': array}
|
{'query': query, 'sort': array, 'range': array}
|
||||||
|
|
||||||
query: query object, more on query syntax at
|
query: query object, more on query syntax at
|
||||||
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
||||||
sort: array of key, operator dics
|
sort: array of key, operator dics
|
||||||
|
@ -102,7 +88,7 @@ def findDate(request):
|
||||||
Positions
|
Positions
|
||||||
param data
|
param data
|
||||||
{'query': query, 'ids': []}
|
{'query': query, 'ids': []}
|
||||||
|
|
||||||
query: query object, more on query syntax at
|
query: query object, more on query syntax at
|
||||||
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
||||||
ids: ids of dates for which positions are required
|
ids: ids of dates for which positions are required
|
||||||
|
@ -111,8 +97,7 @@ Positions
|
||||||
response = json_response(status=200, text='ok')
|
response = json_response(status=200, text='ok')
|
||||||
response['data']['places'] = []
|
response['data']['places'] = []
|
||||||
#FIXME: add coordinates to limit search
|
#FIXME: add coordinates to limit search
|
||||||
for p in Dates.objects.find(data['query']):
|
for p in models.Date.objects.find(data['query']):
|
||||||
response['data']['dates'].append(p.json())
|
response['data']['dates'].append(p.json())
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(findDate)
|
actions.register(findDate)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.contrib import admin
|
||||||
|
|
||||||
import models
|
import models
|
||||||
|
|
||||||
|
|
||||||
class ItemAdmin(admin.ModelAdmin):
|
class ItemAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['itemId', 'data', 'external_data']
|
search_fields = ['itemId', 'data', 'external_data']
|
||||||
list_display = ['available', 'itemId', '__unicode__']
|
list_display = ['available', 'itemId', '__unicode__']
|
||||||
|
@ -12,8 +13,7 @@ class ItemAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
admin.site.register(models.Item, ItemAdmin)
|
admin.site.register(models.Item, ItemAdmin)
|
||||||
|
|
||||||
|
|
||||||
class PropertyAdmin(admin.ModelAdmin):
|
class PropertyAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name', 'title']
|
search_fields = ['name', 'title']
|
||||||
admin.site.register(models.Property, PropertyAdmin)
|
admin.site.register(models.Property, PropertyAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
from ajax_filtered_fields.forms import AjaxManyToManyField, ForeignKeyByLetter
|
from ajax_filtered_fields.forms import AjaxManyToManyField, ForeignKeyByLetter
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django import forms
|
|
||||||
|
|
||||||
import models
|
|
||||||
|
|
||||||
ajax_filtered_js = (
|
ajax_filtered_js = (
|
||||||
settings.ADMIN_MEDIA_PREFIX + "js/SelectBox.js",
|
settings.ADMIN_MEDIA_PREFIX + "js/SelectBox.js",
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
import re
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from urllib2 import unquote
|
|
||||||
from ox.utils import json
|
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from django.db.models import Q, Manager
|
from django.db.models import Q, Manager
|
||||||
|
|
||||||
import models
|
import models
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,6 +16,7 @@ def keyType(key):
|
||||||
return "float"
|
return "float"
|
||||||
return "string"
|
return "string"
|
||||||
|
|
||||||
|
|
||||||
def parseCondition(condition):
|
def parseCondition(condition):
|
||||||
'''
|
'''
|
||||||
condition: {
|
condition: {
|
||||||
|
@ -33,13 +29,15 @@ def parseCondition(condition):
|
||||||
operator: "!="
|
operator: "!="
|
||||||
}
|
}
|
||||||
...
|
...
|
||||||
'''
|
'''
|
||||||
k = condition.get('key', 'all')
|
k = condition.get('key', 'all')
|
||||||
k = {'id': 'itemId'}.get(k, k)
|
k = {'id': 'itemId'}.get(k, k)
|
||||||
if not k: k = 'all'
|
if not k:
|
||||||
|
k = 'all'
|
||||||
v = condition['value']
|
v = condition['value']
|
||||||
op = condition.get('operator', None)
|
op = condition.get('operator', None)
|
||||||
if not op: op = '~'
|
if not op:
|
||||||
|
op = '~'
|
||||||
if op.startswith('!'):
|
if op.startswith('!'):
|
||||||
op = op[1:]
|
op = op[1:]
|
||||||
exclude = True
|
exclude = True
|
||||||
|
@ -66,16 +64,17 @@ def parseCondition(condition):
|
||||||
k = str(k)
|
k = str(k)
|
||||||
if exclude:
|
if exclude:
|
||||||
if in_find and not k.startswith('itemId'):
|
if in_find and not k.startswith('itemId'):
|
||||||
q = ~Q(**{'find__key':k, value_key:v})
|
q = ~Q(**{'find__key': k, value_key: v})
|
||||||
else:
|
else:
|
||||||
q = ~Q(**{k:v})
|
q = ~Q(**{k: v})
|
||||||
else:
|
else:
|
||||||
if in_find and not k.startswith('itemId'):
|
if in_find and not k.startswith('itemId'):
|
||||||
q = Q(**{'find__key':k, value_key:v})
|
q = Q(**{'find__key': k, value_key: v})
|
||||||
else:
|
else:
|
||||||
q = Q(**{k:v})
|
q = Q(**{k: v})
|
||||||
return q
|
return q
|
||||||
else: #number or date
|
else: #number or date
|
||||||
|
|
||||||
def parseDate(d):
|
def parseDate(d):
|
||||||
while len(d) < 3:
|
while len(d) < 3:
|
||||||
d.append(1)
|
d.append(1)
|
||||||
|
@ -90,11 +89,11 @@ def parseCondition(condition):
|
||||||
if exclude: #!1960-1970
|
if exclude: #!1960-1970
|
||||||
k1 = 'value__lt'
|
k1 = 'value__lt'
|
||||||
k2 = 'value__gte'
|
k2 = 'value__gte'
|
||||||
return Q(**{'find__key': k, k1:v1})|Q(**{'find__key': k, k2:v2})
|
return Q(**{'find__key': k, k1: v1})|Q(**{'find__key': k, k2: v2})
|
||||||
else: #1960-1970
|
else: #1960-1970
|
||||||
k1 = 'value__gte'
|
k1 = 'value__gte'
|
||||||
k2 = 'value__lt'
|
k2 = 'value__lt'
|
||||||
return Q(**{'find__key': k, k1:v1})&Q(**{'find__key': k, k2:v2})
|
return Q(**{'find__key': k, k1: v1})&Q(**{'find__key': k, k2: v2})
|
||||||
else:
|
else:
|
||||||
if keyType(k) == "date":
|
if keyType(k) == "date":
|
||||||
v = parseDate(v.split('.'))
|
v = parseDate(v.split('.'))
|
||||||
|
@ -113,9 +112,10 @@ def parseCondition(condition):
|
||||||
vk = str(vk)
|
vk = str(vk)
|
||||||
|
|
||||||
if exclude: #!1960
|
if exclude: #!1960
|
||||||
return ~Q(**{'find__key': k, vk:v})
|
return ~Q(**{'find__key': k, vk: v})
|
||||||
else: #1960
|
else: #1960
|
||||||
return Q(**{'find__key': k, vk:v})
|
return Q(**{'find__key': k, vk: v})
|
||||||
|
|
||||||
|
|
||||||
def parseConditions(conditions, operator):
|
def parseConditions(conditions, operator):
|
||||||
'''
|
'''
|
||||||
|
@ -135,16 +135,18 @@ def parseConditions(conditions, operator):
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
operator: "&"
|
operator: "&"
|
||||||
'''
|
'''
|
||||||
conn = []
|
conn = []
|
||||||
for condition in conditions:
|
for condition in conditions:
|
||||||
if 'conditions' in condition:
|
if 'conditions' in condition:
|
||||||
q = parseConditions(condition['conditions'],
|
q = parseConditions(condition['conditions'],
|
||||||
condition.get('operator', '&'))
|
condition.get('operator', '&'))
|
||||||
if q: conn.append(q)
|
if q:
|
||||||
|
conn.append(q)
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if condition.get('value', '') != '' or condition.get('operator', '') == '=':
|
if condition.get('value', '') != '' or \
|
||||||
|
condition.get('operator', '') == '=':
|
||||||
conn.append(parseCondition(condition))
|
conn.append(parseCondition(condition))
|
||||||
if conn:
|
if conn:
|
||||||
q = conn[0]
|
q = conn[0]
|
||||||
|
@ -156,7 +158,9 @@ def parseConditions(conditions, operator):
|
||||||
return q
|
return q
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ItemManager(Manager):
|
class ItemManager(Manager):
|
||||||
|
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
return super(ItemManager, self).get_query_set()
|
return super(ItemManager, self).get_query_set()
|
||||||
|
|
||||||
|
@ -165,13 +169,14 @@ class ItemManager(Manager):
|
||||||
l = l.split(":")
|
l = l.split(":")
|
||||||
only_public = True
|
only_public = True
|
||||||
if not user.is_anonymous():
|
if not user.is_anonymous():
|
||||||
if len(l) == 1: l = [request.user.username] + l
|
if len(l) == 1:
|
||||||
if request.user.username == l[0]:
|
l = [user.username] + l
|
||||||
|
if user.username == l[0]:
|
||||||
only_public = False
|
only_public = False
|
||||||
if len(l) == 2:
|
if len(l) == 2:
|
||||||
lqs = models.List.objects.filter(name=l[1], user__username=l[0])
|
lqs = models.List.objects.filter(name=l[1], user__username=l[0])
|
||||||
if only_public:
|
if only_public:
|
||||||
lqs = qls.filter(public=True)
|
lqs = lqs.filter(public=True)
|
||||||
if lqs.count() == 1:
|
if lqs.count() == 1:
|
||||||
qs = qs.filter(listitem__list__id=lqs[0].id)
|
qs = qs.filter(listitem__list__id=lqs[0].id)
|
||||||
return qs
|
return qs
|
||||||
|
@ -196,7 +201,7 @@ class ItemManager(Manager):
|
||||||
],
|
],
|
||||||
operator: "&"
|
operator: "&"
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
#join query with operator
|
#join query with operator
|
||||||
qs = self.get_query_set()
|
qs = self.get_query_set()
|
||||||
|
@ -212,4 +217,3 @@ class ItemManager(Manager):
|
||||||
l = data.get('list', 'all')
|
l = data.get('list', 'all')
|
||||||
qs = self.filter_list(qs, l, user)
|
qs = self.filter_list(qs, l, user)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
|
@ -4,26 +4,18 @@ from __future__ import division, with_statement
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os.path
|
import os.path
|
||||||
import math
|
|
||||||
import random
|
|
||||||
import re
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import unicodedata
|
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.utils import simplejson as json
|
from django.utils import simplejson as json
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from ox.django import fields
|
|
||||||
import ox
|
import ox
|
||||||
from ox import stripTags
|
from ox.django import fields
|
||||||
|
from ox.normalize import canonicalTitle
|
||||||
import ox.web.imdb
|
import ox.web.imdb
|
||||||
from ox.normalize import canonicalTitle, canonicalName
|
|
||||||
from firefogg import Firefogg
|
|
||||||
|
|
||||||
import managers
|
import managers
|
||||||
import utils
|
import utils
|
||||||
|
@ -31,23 +23,23 @@ import tasks
|
||||||
from archive import extract
|
from archive import extract
|
||||||
|
|
||||||
from annotaion.models import Annotation, Layer
|
from annotaion.models import Annotation, Layer
|
||||||
from person.models import get_name_sort, Person
|
from person.models import get_name_sort
|
||||||
|
|
||||||
|
|
||||||
def siteJson():
|
def siteJson():
|
||||||
r = {}
|
r = {}
|
||||||
r['findKeys'] = [{"id": "all", "title": "All"}]
|
r['findKeys'] = [{"id": "all", "title": "All"}]
|
||||||
for p in Property.objects.all():
|
for p in Property.objects.all():
|
||||||
if p.find:
|
if p.find:
|
||||||
title = p.title
|
title = p.title
|
||||||
if not title:
|
if not title:
|
||||||
title = p.name.capitalize()
|
title = p.name.capitalize()
|
||||||
f = {"id": p.name, "title": title}
|
f = {"id": p.name, "title": title}
|
||||||
f['autocomplete'] = p.autocomplete
|
f['autocomplete'] = p.autocomplete
|
||||||
r['findKeys'].append(f)
|
r['findKeys'].append(f)
|
||||||
|
|
||||||
r['groups'] = [p.name for p in Property.objects.filter(group=True)]
|
r['groups'] = [p.name for p in Property.objects.filter(group=True)]
|
||||||
r['layers'] = [l.json() for l in Layer.objects.all()]
|
r['layers'] = [l.json() for l in Layer.objects.all()]
|
||||||
|
|
||||||
r['itemViews'] = [
|
r['itemViews'] = [
|
||||||
{"id": "info", "title": "Info"},
|
{"id": "info", "title": "Info"},
|
||||||
|
@ -81,28 +73,28 @@ def siteJson():
|
||||||
{"id": "public", "title": "Public Lists"},
|
{"id": "public", "title": "Public Lists"},
|
||||||
{"id": "featured", "title": "Featured Lists"}
|
{"id": "featured", "title": "Featured Lists"}
|
||||||
]
|
]
|
||||||
r['sortKeys'] = []
|
r['sortKeys'] = []
|
||||||
for p in Property.objects.exclude(sort=''):
|
for p in Property.objects.exclude(sort=''):
|
||||||
title = p.title
|
title = p.title
|
||||||
if not title:
|
if not title:
|
||||||
title = p.name.capitalize()
|
title = p.name.capitalize()
|
||||||
|
|
||||||
f = {
|
f = {
|
||||||
"id": p.name,
|
"id": p.name,
|
||||||
"title": title,
|
"title": title,
|
||||||
"operator": p.operator,
|
"operator": p.operator,
|
||||||
"align": p.align,
|
"align": p.align,
|
||||||
"width": p.width,
|
"width": p.width,
|
||||||
}
|
}
|
||||||
if not p.removable:
|
if not p.removable:
|
||||||
f['removable'] = False
|
f['removable'] = False
|
||||||
r['sortKeys'].append(f)
|
r['sortKeys'].append(f)
|
||||||
r['sortKeys'].append([{"id": "id", "title": "ID", "operator": "", "align": "left", "width": 90}])
|
r['sortKeys'].append([{"id": "id", "title": "ID", "operator": "", "align": "left", "width": 90}])
|
||||||
|
|
||||||
r['totals'] = [{"id": "items"}]
|
r['totals'] = [{"id": "items"}]
|
||||||
for p in Property.objects.filter(totals=True):
|
for p in Property.objects.filter(totals=True):
|
||||||
f = {'id': p.name, 'admin': p.admin}
|
f = {'id': p.name, 'admin': p.admin}
|
||||||
r['totals'].append(f)
|
r['totals'].append(f)
|
||||||
|
|
||||||
#FIXME: defaults should also be populated from properties
|
#FIXME: defaults should also be populated from properties
|
||||||
r["user"] = {
|
r["user"] = {
|
||||||
|
@ -127,7 +119,8 @@ def siteJson():
|
||||||
},
|
},
|
||||||
"username": ""
|
"username": ""
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def get_item(info):
|
def get_item(info):
|
||||||
'''
|
'''
|
||||||
|
@ -176,28 +169,30 @@ def get_item(info):
|
||||||
item.save()
|
item.save()
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
class Property(models.Model):
|
class Property(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('position', )
|
ordering = ('position', )
|
||||||
verbose_name_plural = "Properties"
|
verbose_name_plural = "Properties"
|
||||||
|
|
||||||
name = models.CharField(null=True, max_length=255, unique=True)
|
name = models.CharField(null=True, max_length=255, unique=True)
|
||||||
title = models.CharField(null=True, max_length=255, blank=True)
|
title = models.CharField(null=True, max_length=255, blank=True)
|
||||||
#text, string, string from list(fixme), event, place, person
|
#text, string, string from list(fixme), event, place, person
|
||||||
type = models.CharField(null=True, max_length=255)
|
type = models.CharField(null=True, max_length=255)
|
||||||
array = models.BooleanField(default=False)
|
array = models.BooleanField(default=False)
|
||||||
position = models.IntegerField(default=0)
|
position = models.IntegerField(default=0)
|
||||||
width = models.IntegerField(default=180)
|
width = models.IntegerField(default=180)
|
||||||
align = models.CharField(null=True, max_length=255, default='left')
|
align = models.CharField(null=True, max_length=255, default='left')
|
||||||
operator = models.CharField(null=True, max_length=5, default='', blank=True)
|
operator = models.CharField(null=True, max_length=5, default='', blank=True)
|
||||||
default = models.BooleanField('Enabled by default', default=False)
|
default = models.BooleanField('Enabled by default', default=False)
|
||||||
removable = models.BooleanField(default=True)
|
removable = models.BooleanField(default=True)
|
||||||
|
|
||||||
#sort values: title, string, integer, float, date
|
#sort values: title, string, integer, float, date
|
||||||
sort = models.CharField(null=True, max_length=255, blank=True)
|
sort = models.CharField(null=True, max_length=255, blank=True)
|
||||||
find = models.BooleanField(default=False)
|
find = models.BooleanField(default=False)
|
||||||
autocomplete = models.BooleanField(default=False)
|
autocomplete = models.BooleanField(default=False)
|
||||||
group = models.BooleanField(default=False)
|
group = models.BooleanField(default=False)
|
||||||
|
|
||||||
totals = models.BooleanField(default=False)
|
totals = models.BooleanField(default=False)
|
||||||
admin = models.BooleanField(default=False)
|
admin = models.BooleanField(default=False)
|
||||||
|
@ -207,19 +202,20 @@ class Property(models.Model):
|
||||||
return self.title
|
return self.title
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def json(self):
|
def json(self):
|
||||||
j = {}
|
j = {}
|
||||||
for key in ('type', 'sort', 'title', 'array', 'totals', 'admin'):
|
for key in ('type', 'sort', 'title', 'array', 'totals', 'admin'):
|
||||||
value = getattr(self, key)
|
value = getattr(self, key)
|
||||||
if value:
|
if value:
|
||||||
j[key] = value
|
j[key] = value
|
||||||
return j
|
return j
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.title:
|
if not self.title:
|
||||||
self.title = self.name.capitalize()
|
self.title = self.name.capitalize()
|
||||||
super(Property, self).save(*args, **kwargs)
|
super(Property, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Item(models.Model):
|
class Item(models.Model):
|
||||||
person_keys = ('director', 'writer', 'producer', 'editor', 'cinematographer', 'actor', 'character')
|
person_keys = ('director', 'writer', 'producer', 'editor', 'cinematographer', 'actor', 'character')
|
||||||
facet_keys = person_keys + ('country', 'language', 'genre', 'keyword')
|
facet_keys = person_keys + ('country', 'language', 'genre', 'keyword')
|
||||||
|
@ -228,7 +224,7 @@ class Item(models.Model):
|
||||||
published = models.DateTimeField(default=datetime.now, editable=False)
|
published = models.DateTimeField(default=datetime.now, editable=False)
|
||||||
|
|
||||||
#only items that have data 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)
|
||||||
itemId = models.CharField(max_length=128, unique=True, blank=True)
|
itemId = models.CharField(max_length=128, unique=True, blank=True)
|
||||||
oxdbId = models.CharField(max_length=42, unique=True, blank=True)
|
oxdbId = models.CharField(max_length=42, unique=True, blank=True)
|
||||||
|
@ -258,9 +254,9 @@ class Item(models.Model):
|
||||||
|
|
||||||
def edit(self, data):
|
def edit(self, data):
|
||||||
#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.data, key, data[key])
|
setattr(self.data, key, data[key])
|
||||||
self.oxdb.save()
|
self.oxdb.save()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
@ -339,11 +335,11 @@ class Item(models.Model):
|
||||||
#FIXME: this should not be used
|
#FIXME: this should not be used
|
||||||
_public_fields = {
|
_public_fields = {
|
||||||
'itemId': 'id',
|
'itemId': 'id',
|
||||||
'title': 'title',
|
'title': 'title',
|
||||||
'year': 'year',
|
'year': 'year',
|
||||||
|
|
||||||
'runtime': 'runtime',
|
'runtime': 'runtime',
|
||||||
'release_date': 'release_date',
|
'release_date': 'release_date',
|
||||||
|
|
||||||
'countries': 'country',
|
'countries': 'country',
|
||||||
'directors': 'director',
|
'directors': 'director',
|
||||||
|
@ -402,7 +398,7 @@ class Item(models.Model):
|
||||||
s = self.streams.all()[0]
|
s = self.streams.all()[0]
|
||||||
if s.video and s.info:
|
if s.video and s.info:
|
||||||
stream['duration'] = s.info['duration']
|
stream['duration'] = s.info['duration']
|
||||||
if 'video' in s.info and s.info['video']:
|
if 'video' in s.info and s.info['video']:
|
||||||
stream['aspectRatio'] = s.info['video'][0]['width'] / s.info['video'][0]['height']
|
stream['aspectRatio'] = s.info['video'][0]['width'] / s.info['video'][0]['height']
|
||||||
if settings.XSENDFILE or settings.XACCELREDIRECT:
|
if settings.XSENDFILE or settings.XACCELREDIRECT:
|
||||||
stream['baseUrl'] = '/%s' % self.itemId
|
stream['baseUrl'] = '/%s' % self.itemId
|
||||||
|
@ -414,7 +410,7 @@ class Item(models.Model):
|
||||||
def get_layers(self):
|
def get_layers(self):
|
||||||
layers = {}
|
layers = {}
|
||||||
layers['cuts'] = self.data.get('cuts', {})
|
layers['cuts'] = self.data.get('cuts', {})
|
||||||
|
|
||||||
layers['subtitles'] = {}
|
layers['subtitles'] = {}
|
||||||
#FIXME: subtitles should be stored in Annotation
|
#FIXME: subtitles should be stored in Annotation
|
||||||
qs = self.files.filter(is_subtitle=True, is_main=True, available=True)
|
qs = self.files.filter(is_subtitle=True, is_main=True, available=True)
|
||||||
|
@ -468,7 +464,9 @@ class Item(models.Model):
|
||||||
'''
|
'''
|
||||||
Search related functions
|
Search related functions
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def update_find(self):
|
def update_find(self):
|
||||||
|
|
||||||
def save(key, value):
|
def save(key, value):
|
||||||
f, created = ItemFind.objects.get_or_create(item=self, key=key)
|
f, created = ItemFind.objects.get_or_create(item=self, key=key)
|
||||||
if value not in ('', '||'):
|
if value not in ('', '||'):
|
||||||
|
@ -478,7 +476,7 @@ class Item(models.Model):
|
||||||
f.delete()
|
f.delete()
|
||||||
|
|
||||||
save('title', '\n'.join([self.get('title'), self.get('original_title', '')]))
|
save('title', '\n'.join([self.get('title'), self.get('original_title', '')]))
|
||||||
|
|
||||||
#FIXME: filter us/int title
|
#FIXME: filter us/int title
|
||||||
#f.title += ' '.join([t.title for t in self.alternative_titles()])
|
#f.title += ' '.join([t.title for t in self.alternative_titles()])
|
||||||
|
|
||||||
|
@ -537,17 +535,17 @@ class Item(models.Model):
|
||||||
|
|
||||||
for key in ('keywords', 'genres', 'cast', 'summary', 'trivia', 'connections'):
|
for key in ('keywords', 'genres', 'cast', 'summary', 'trivia', 'connections'):
|
||||||
setattr(s, key, len(self.get(key, '')))
|
setattr(s, key, len(self.get(key, '')))
|
||||||
|
|
||||||
s.itemId = self.itemId.replace('0x', 'xx')
|
s.itemId = self.itemId.replace('0x', 'xx')
|
||||||
s.rating = self.get('rating', -1)
|
s.rating = self.get('rating', -1)
|
||||||
s.votes = self.get('votes', -1)
|
s.votes = self.get('votes', -1)
|
||||||
|
|
||||||
# data from related subtitles
|
# data from related subtitles
|
||||||
s.scenes = 0 #FIXME
|
s.scenes = 0 #FIXME
|
||||||
s.dialog = 0 #FIXME
|
s.dialog = 0 #FIXME
|
||||||
s.words = 0 #FIXME
|
s.words = 0 #FIXME
|
||||||
s.wpm = 0 #FIXME
|
s.wpm = 0 #FIXME
|
||||||
s.risk = 0 #FIXME
|
s.risk = 0 #FIXME
|
||||||
# data from related files
|
# data from related files
|
||||||
videos = self.main_videos()
|
videos = self.main_videos()
|
||||||
if len(videos) > 0:
|
if len(videos) > 0:
|
||||||
|
@ -574,7 +572,7 @@ class Item(models.Model):
|
||||||
s.color = int(sum(self.data.get('color', [])))
|
s.color = int(sum(self.data.get('color', [])))
|
||||||
s.saturation = 0 #FIXME
|
s.saturation = 0 #FIXME
|
||||||
s.brightness = 0 #FIXME
|
s.brightness = 0 #FIXME
|
||||||
|
|
||||||
s.cuts = len(self.data.get('cuts', []))
|
s.cuts = len(self.data.get('cuts', []))
|
||||||
if s.duration:
|
if s.duration:
|
||||||
s.cutsperminute = s.cuts / (s.duration/60)
|
s.cutsperminute = s.cuts / (s.duration/60)
|
||||||
|
@ -585,13 +583,13 @@ class Item(models.Model):
|
||||||
if not getattr(s, key):
|
if not getattr(s, key):
|
||||||
setattr(s, key, u'zzzzzzzzzzzzzzzzzzzzzzzzz')
|
setattr(s, key, u'zzzzzzzzzzzzzzzzzzzzzzzzz')
|
||||||
if not s.year:
|
if not s.year:
|
||||||
s.year_desc = '';
|
s.year_desc = ''
|
||||||
s.year = '9999';
|
s.year = '9999'
|
||||||
#FIXME: also deal with number based rows like genre, keywords etc
|
#FIXME: also deal with number based rows like genre, keywords etc
|
||||||
s.save()
|
s.save()
|
||||||
|
|
||||||
def update_facets(self):
|
def update_facets(self):
|
||||||
#FIXME: what to do with Unkown Director, Year, Country etc.
|
#FIXME: what to do with Unkown Director, Year, Country etc.
|
||||||
for key in self.facet_keys:
|
for key in self.facet_keys:
|
||||||
if key == 'actor':
|
if key == 'actor':
|
||||||
current_values = [i[0] for i in self.get('actor', [])]
|
current_values = [i[0] for i in self.get('actor', [])]
|
||||||
|
@ -616,7 +614,7 @@ class Item(models.Model):
|
||||||
f, created = Facet.objects.get_or_create(key='year', value=year, value_sort=year, item=self)
|
f, created = Facet.objects.get_or_create(key='year', value=year, value_sort=year, item=self)
|
||||||
else:
|
else:
|
||||||
Facet.objects.filter(item=self, key='year').delete()
|
Facet.objects.filter(item=self, key='year').delete()
|
||||||
|
|
||||||
def path(self, name=''):
|
def path(self, name=''):
|
||||||
h = self.itemId
|
h = self.itemId
|
||||||
return os.path.join('items', h[:2], h[2:4], h[4:6], h[6:], name)
|
return os.path.join('items', h[:2], h[2:4], h[4:6], h[6:], name)
|
||||||
|
@ -624,6 +622,7 @@ class Item(models.Model):
|
||||||
'''
|
'''
|
||||||
Video related functions
|
Video related functions
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def frame(self, position, width=128):
|
def frame(self, position, width=128):
|
||||||
stream = self.streams.filter(profile=settings.VIDEO_PROFILE+'.webm')[0]
|
stream = self.streams.filter(profile=settings.VIDEO_PROFILE+'.webm')[0]
|
||||||
path = os.path.join(settings.MEDIA_ROOT, self.path(), 'frames', "%d"%width, "%s.jpg"%position)
|
path = os.path.join(settings.MEDIA_ROOT, self.path(), 'frames', "%d"%width, "%s.jpg"%position)
|
||||||
|
@ -647,14 +646,14 @@ class Item(models.Model):
|
||||||
first.width == v.width and first.height == v.height:
|
first.width == v.width and first.height == v.height:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
videos = filter(check, videos)
|
videos = filter(check, videos)
|
||||||
return videos
|
return videos
|
||||||
|
|
||||||
def update_streams(self):
|
def update_streams(self):
|
||||||
files = {}
|
files = {}
|
||||||
for f in self.main_videos():
|
for f in self.main_videos():
|
||||||
files[utils.sort_title(f.name)] = f.video.path
|
files[utils.sort_title(f.name)] = f.video.path
|
||||||
|
|
||||||
#FIXME: how to detect if something changed?
|
#FIXME: how to detect if something changed?
|
||||||
if files:
|
if files:
|
||||||
stream, created = Stream.objects.get_or_create(item=self, profile='%s.webm' % settings.VIDEO_PROFILE)
|
stream, created = Stream.objects.get_or_create(item=self, profile='%s.webm' % settings.VIDEO_PROFILE)
|
||||||
|
@ -693,6 +692,7 @@ class Item(models.Model):
|
||||||
'''
|
'''
|
||||||
Poster related functions
|
Poster related functions
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def update_poster_urls(self):
|
def update_poster_urls(self):
|
||||||
_current = {}
|
_current = {}
|
||||||
for s in settings.POSTER_SERVICES:
|
for s in settings.POSTER_SERVICES:
|
||||||
|
@ -781,12 +781,14 @@ class Item(models.Model):
|
||||||
p.wait()
|
p.wait()
|
||||||
return posters.keys()
|
return posters.keys()
|
||||||
|
|
||||||
|
|
||||||
class ItemFind(models.Model):
|
class ItemFind(models.Model):
|
||||||
"""
|
"""
|
||||||
used to find items,
|
used to find items,
|
||||||
item.update_find populates this table
|
item.update_find populates this table
|
||||||
its used in manager.ItemManager
|
its used in manager.ItemManager
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("item", "key")
|
unique_together = ("item", "key")
|
||||||
|
|
||||||
|
@ -794,8 +796,9 @@ class ItemFind(models.Model):
|
||||||
key = models.CharField(max_length=200, db_index=True)
|
key = models.CharField(max_length=200, db_index=True)
|
||||||
value = models.TextField(blank=True)
|
value = models.TextField(blank=True)
|
||||||
|
|
||||||
#FIXME: make sort based on site.json
|
|
||||||
class ItemSort(models.Model):
|
class ItemSort(models.Model):
|
||||||
|
#FIXME: make sort based on site.json
|
||||||
"""
|
"""
|
||||||
used to sort items, all sort values are in here
|
used to sort items, all sort values are in here
|
||||||
"""
|
"""
|
||||||
|
@ -872,6 +875,7 @@ class ItemSort(models.Model):
|
||||||
return tuple(fields)
|
return tuple(fields)
|
||||||
fields = classmethod(fields)
|
fields = classmethod(fields)
|
||||||
|
|
||||||
|
|
||||||
class Facet(models.Model):
|
class Facet(models.Model):
|
||||||
item = models.ForeignKey('Item', related_name='facets')
|
item = models.ForeignKey('Item', related_name='facets')
|
||||||
key = models.CharField(max_length=200, db_index=True)
|
key = models.CharField(max_length=200, db_index=True)
|
||||||
|
@ -883,7 +887,9 @@ class Facet(models.Model):
|
||||||
self.value_sort = self.value
|
self.value_sort = self.value
|
||||||
super(Facet, self).save(*args, **kwargs)
|
super(Facet, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Stream(models.Model):
|
class Stream(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("item", "profile")
|
unique_together = ("item", "profile")
|
||||||
|
|
||||||
|
@ -899,7 +905,7 @@ class Stream(models.Model):
|
||||||
|
|
||||||
def path(self):
|
def path(self):
|
||||||
return self.item.path(self.profile)
|
return self.item.path(self.profile)
|
||||||
|
|
||||||
def extract_derivatives(self):
|
def extract_derivatives(self):
|
||||||
if settings.VIDEO_H264:
|
if settings.VIDEO_H264:
|
||||||
profile = self.profile.replace('.webm', '.mp4')
|
profile = self.profile.replace('.webm', '.mp4')
|
||||||
|
@ -945,7 +951,9 @@ class Stream(models.Model):
|
||||||
self.info = ox.avinfo(self.video.path)
|
self.info = ox.avinfo(self.video.path)
|
||||||
super(Stream, self).save(*args, **kwargs)
|
super(Stream, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class PosterUrl(models.Model):
|
class PosterUrl(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("item", "service", "url")
|
unique_together = ("item", "service", "url")
|
||||||
ordering = ('-height', )
|
ordering = ('-height', )
|
||||||
|
@ -958,4 +966,3 @@ class PosterUrl(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'%s %s %dx%d' % (unicode(self.item), self.service, self.width, self.height)
|
return u'%s %s %dx%d' % (unicode(self.item), self.service, self.width, self.height)
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,19 @@ import models
|
||||||
def cronjob(**kwargs):
|
def cronjob(**kwargs):
|
||||||
print "do some cleanup stuff once a day"
|
print "do some cleanup stuff once a day"
|
||||||
|
|
||||||
|
|
||||||
@task(ignore_resulsts=True, queue='default')
|
@task(ignore_resulsts=True, queue='default')
|
||||||
def update_poster(itemId):
|
def update_poster(itemId):
|
||||||
item = models.Item.objects.get(itemId=itemId)
|
item = models.Item.objects.get(itemId=itemId)
|
||||||
item.make_poster(True)
|
item.make_poster(True)
|
||||||
|
|
||||||
|
|
||||||
@task(ignore_resulsts=True, queue='default')
|
@task(ignore_resulsts=True, queue='default')
|
||||||
def update_imdb(itemId):
|
def update_imdb(itemId):
|
||||||
item = models.Item.objects.get(itemId=itemId)
|
item = models.Item.objects.get(itemId=itemId)
|
||||||
item.update_imdb()
|
item.update_imdb()
|
||||||
|
|
||||||
|
|
||||||
@task(queue="encoding")
|
@task(queue="encoding")
|
||||||
def update_streams(itemId):
|
def update_streams(itemId):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
|
@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
|
|
@ -13,4 +13,3 @@ urlpatterns = patterns("item.views",
|
||||||
(r'^(?P<id>[A-Z0-9].*)/poster\.jpg$', 'poster'),
|
(r'^(?P<id>[A-Z0-9].*)/poster\.jpg$', 'poster'),
|
||||||
(r'^(?P<id>[A-Z0-9].*)/timelines/(?P<timeline>.+)\.(?P<size>\d+)\.(?P<position>\d+)\.png$', 'timeline'),
|
(r'^(?P<id>[A-Z0-9].*)/timelines/(?P<timeline>.+)\.(?P<size>\d+)\.(?P<position>\d+)\.png$', 'timeline'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
#
|
#
|
||||||
import errno
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import re
|
import re
|
||||||
import hashlib
|
import hashlib
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
import ox
|
import ox
|
||||||
import ox.iso
|
import ox.iso
|
||||||
from ox.normalize import normalizeName, normalizeTitle, canonicalTitle
|
from ox.normalize import normalizeName, normalizeTitle
|
||||||
|
|
||||||
|
|
||||||
def parse_decimal(string):
|
def parse_decimal(string):
|
||||||
|
@ -22,11 +20,13 @@ def parse_decimal(string):
|
||||||
d = string.split('/')
|
d = string.split('/')
|
||||||
return Decimal(d[0]) / Decimal(d[1])
|
return Decimal(d[0]) / Decimal(d[1])
|
||||||
|
|
||||||
|
|
||||||
def plural_key(term):
|
def plural_key(term):
|
||||||
return {
|
return {
|
||||||
'country': 'countries',
|
'country': 'countries',
|
||||||
}.get(term, term + 's')
|
}.get(term, term + 's')
|
||||||
|
|
||||||
|
|
||||||
def oxid(title, directors, year='', seriesTitle='', episodeTitle='', season=0, episode=0):
|
def oxid(title, directors, year='', seriesTitle='', episodeTitle='', season=0, episode=0):
|
||||||
director = ', '.join(directors)
|
director = ', '.join(directors)
|
||||||
oxid_value = u"\n".join([title, director, year])
|
oxid_value = u"\n".join([title, director, year])
|
||||||
|
@ -38,6 +38,7 @@ def oxid(title, directors, year='', seriesTitle='', episodeTitle='', season=0, e
|
||||||
oxid += hashlib.sha1(oxid_value.encode('utf-8')).hexdigest()[:20]
|
oxid += hashlib.sha1(oxid_value.encode('utf-8')).hexdigest()[:20]
|
||||||
return u"0x" + oxid
|
return u"0x" + oxid
|
||||||
|
|
||||||
|
|
||||||
def oxdb_id(title, directors=[], year='', season='', episode='', episode_title='', episode_directors=[], episode_year=''):
|
def oxdb_id(title, directors=[], year='', season='', episode='', episode_title='', episode_directors=[], episode_year=''):
|
||||||
# new id function, will replace oxid()
|
# new id function, will replace oxid()
|
||||||
def get_hash(string):
|
def get_hash(string):
|
||||||
|
@ -51,11 +52,13 @@ def oxdb_id(title, directors=[], year='', season='', episode='', episode_title='
|
||||||
get_hash('\n'.join([str(episode), episode_director, episode_title, str(episode_year)]))[:8]
|
get_hash('\n'.join([str(episode), episode_director, episode_title, str(episode_year)]))[:8]
|
||||||
return u'0x' + oxdb_id
|
return u'0x' + oxdb_id
|
||||||
|
|
||||||
|
|
||||||
def oxdb_directors(director):
|
def oxdb_directors(director):
|
||||||
director = os.path.basename(os.path.dirname(director))
|
director = os.path.basename(os.path.dirname(director))
|
||||||
if director.endswith('_'):
|
if director.endswith('_'):
|
||||||
director = "%s." % director[:-1]
|
director = "%s." % director[:-1]
|
||||||
directors = [normalizeName(d) for d in director.split('; ')]
|
directors = [normalizeName(d) for d in director.split('; ')]
|
||||||
|
|
||||||
def cleanup(director):
|
def cleanup(director):
|
||||||
director = director.strip()
|
director = director.strip()
|
||||||
director = director.replace('Series', '')
|
director = director.replace('Series', '')
|
||||||
|
@ -65,6 +68,7 @@ def oxdb_directors(director):
|
||||||
directors = filter(None, [cleanup(d) for d in directors])
|
directors = filter(None, [cleanup(d) for d in directors])
|
||||||
return directors
|
return directors
|
||||||
|
|
||||||
|
|
||||||
def oxdb_title(_title, searchTitle = False):
|
def oxdb_title(_title, searchTitle = False):
|
||||||
'''
|
'''
|
||||||
normalize filename to get item title
|
normalize filename to get item title
|
||||||
|
@ -83,7 +87,7 @@ def oxdb_title(_title, searchTitle = False):
|
||||||
else:
|
else:
|
||||||
stitle = _title.split('.')[-2]
|
stitle = _title.split('.')[-2]
|
||||||
if stitle.startswith('Episode '):
|
if stitle.startswith('Episode '):
|
||||||
stitle = ''
|
stitle = ''
|
||||||
if searchTitle:
|
if searchTitle:
|
||||||
title = '"%s" %s' % (title, stitle)
|
title = '"%s" %s' % (title, stitle)
|
||||||
else:
|
else:
|
||||||
|
@ -98,9 +102,11 @@ def oxdb_title(_title, searchTitle = False):
|
||||||
title = normalizeTitle(title)
|
title = normalizeTitle(title)
|
||||||
return title
|
return title
|
||||||
|
|
||||||
|
|
||||||
def oxdb_year(data):
|
def oxdb_year(data):
|
||||||
return ox.findRe(data, '\.(\d{4})\.')
|
return ox.findRe(data, '\.(\d{4})\.')
|
||||||
|
|
||||||
|
|
||||||
def oxdb_series_title(path):
|
def oxdb_series_title(path):
|
||||||
seriesTitle = u''
|
seriesTitle = u''
|
||||||
if path.startswith('Series'):
|
if path.startswith('Series'):
|
||||||
|
@ -111,6 +117,7 @@ def oxdb_series_title(path):
|
||||||
seriesTitle = t.split(" (S")[0]
|
seriesTitle = t.split(" (S")[0]
|
||||||
return seriesTitle
|
return seriesTitle
|
||||||
|
|
||||||
|
|
||||||
def oxdb_episode_title(path):
|
def oxdb_episode_title(path):
|
||||||
episodeTitle = u''
|
episodeTitle = u''
|
||||||
ep = re.compile('.Episode \d+?\.(.*?)\.[a-zA-Z]').findall(path)
|
ep = re.compile('.Episode \d+?\.(.*?)\.[a-zA-Z]').findall(path)
|
||||||
|
@ -118,6 +125,7 @@ def oxdb_episode_title(path):
|
||||||
episodeTitle = ep[0]
|
episodeTitle = ep[0]
|
||||||
return episodeTitle
|
return episodeTitle
|
||||||
|
|
||||||
|
|
||||||
def oxdb_season_episode(path):
|
def oxdb_season_episode(path):
|
||||||
season = 0
|
season = 0
|
||||||
episode = 0
|
episode = 0
|
||||||
|
@ -137,6 +145,7 @@ def oxdb_season_episode(path):
|
||||||
episode = int(se[0][1])
|
episode = int(se[0][1])
|
||||||
return (season, episode)
|
return (season, episode)
|
||||||
|
|
||||||
|
|
||||||
def oxdb_part(path):
|
def oxdb_part(path):
|
||||||
part = 1
|
part = 1
|
||||||
path = path.lower()
|
path = path.lower()
|
||||||
|
@ -149,6 +158,7 @@ def oxdb_part(path):
|
||||||
part = p[0]
|
part = p[0]
|
||||||
return part
|
return part
|
||||||
|
|
||||||
|
|
||||||
def parse_path(path):
|
def parse_path(path):
|
||||||
'''
|
'''
|
||||||
expects path in the form
|
expects path in the form
|
||||||
|
@ -178,6 +188,7 @@ def parse_path(path):
|
||||||
episode_year='')
|
episode_year='')
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def sort_title(title):
|
def sort_title(title):
|
||||||
#title
|
#title
|
||||||
title = re.sub(u'[\'!¿¡,\.;\-"\:\*\[\]]', '', title)
|
title = re.sub(u'[\'!¿¡,\.;\-"\:\*\[\]]', '', title)
|
||||||
|
@ -185,9 +196,8 @@ def sort_title(title):
|
||||||
#title = title.replace(u'Æ', 'Ae')
|
#title = title.replace(u'Æ', 'Ae')
|
||||||
if isinstance(title, str):
|
if isinstance(title, str):
|
||||||
title = unicode(title)
|
title = unicode(title)
|
||||||
title = unicodedata.normalize('NFKD',title)
|
title = unicodedata.normalize('NFKD', title)
|
||||||
|
|
||||||
#pad numbered titles
|
#pad numbered titles
|
||||||
title = re.sub('(\d+)', lambda x: '%010d' % int(x.group(0)), title)
|
title = re.sub('(\d+)', lambda x: '%010d' % int(x.group(0)), title)
|
||||||
return title.strip()
|
return title.strip()
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,10 @@
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
|
||||||
from datetime import datetime
|
|
||||||
from urllib2 import unquote
|
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from django import forms
|
from django.db.models import Count, Sum
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db.models import Q, Avg, Count, Sum
|
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.template import RequestContext
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.utils import json
|
||||||
|
@ -28,13 +19,13 @@ import models
|
||||||
import utils
|
import utils
|
||||||
import tasks
|
import tasks
|
||||||
|
|
||||||
from user.models import get_user_json
|
|
||||||
|
|
||||||
from archive.models import File
|
from archive.models import File
|
||||||
from archive import extract
|
from archive import extract
|
||||||
|
|
||||||
from api.actions import actions
|
from api.actions import actions
|
||||||
|
|
||||||
|
|
||||||
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:
|
||||||
|
@ -44,7 +35,8 @@ def _order_query(qs, sort, prefix='sort__'):
|
||||||
sort.append({'operator': '+', 'key': 'director'})
|
sort.append({'operator': '+', 'key': 'director'})
|
||||||
for e in sort:
|
for e in sort:
|
||||||
operator = e['operator']
|
operator = e['operator']
|
||||||
if operator != '-': operator = ''
|
if operator != '-':
|
||||||
|
operator = ''
|
||||||
key = {'id': 'itemId'}.get(e['key'], e['key'])
|
key = {'id': 'itemId'}.get(e['key'], e['key'])
|
||||||
#FIXME: this should be a property of models.ItemSort!!!
|
#FIXME: this should be a property of models.ItemSort!!!
|
||||||
if operator=='-' and key in ('title', 'director', 'writer', 'producer', 'editor', 'cinematographer', 'language', 'country', 'year'):
|
if operator=='-' and key in ('title', 'director', 'writer', 'producer', 'editor', 'cinematographer', 'language', 'country', 'year'):
|
||||||
|
@ -82,7 +74,7 @@ def find(request):
|
||||||
'sort': array,
|
'sort': array,
|
||||||
'range': array
|
'range': array
|
||||||
}
|
}
|
||||||
|
|
||||||
query: query object, more on query syntax at
|
query: query object, more on query syntax at
|
||||||
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
||||||
sort: array of key, operator dics
|
sort: array of key, operator dics
|
||||||
|
@ -111,7 +103,7 @@ Groups
|
||||||
'group': string,
|
'group': string,
|
||||||
'range': array
|
'range': array
|
||||||
}
|
}
|
||||||
|
|
||||||
query: query object, more on query syntax at
|
query: query object, more on query syntax at
|
||||||
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
||||||
range: result range, array [from, to]
|
range: result range, array [from, to]
|
||||||
|
@ -134,7 +126,7 @@ Positions
|
||||||
'query': query,
|
'query': query,
|
||||||
'ids': []
|
'ids': []
|
||||||
}
|
}
|
||||||
|
|
||||||
query: query object, more on query syntax at
|
query: query object, more on query syntax at
|
||||||
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
||||||
ids: ids of items for which positions are required
|
ids: ids of items for which positions are required
|
||||||
|
@ -143,7 +135,7 @@ Positions
|
||||||
if settings.JSON_DEBUG:
|
if settings.JSON_DEBUG:
|
||||||
print json.dumps(data, indent=2)
|
print json.dumps(data, indent=2)
|
||||||
query = _parse_query(data, request.user)
|
query = _parse_query(data, request.user)
|
||||||
|
|
||||||
response = json_response({})
|
response = json_response({})
|
||||||
if 'group' in query:
|
if 'group' in query:
|
||||||
if 'sort' in query:
|
if 'sort' in query:
|
||||||
|
@ -183,7 +175,7 @@ Positions
|
||||||
elif 'ids' in query:
|
elif 'ids' in query:
|
||||||
#FIXME: this does not scale for larger results
|
#FIXME: this does not scale for larger results
|
||||||
qs = _order_query(query['qs'], query['sort'])
|
qs = _order_query(query['qs'], query['sort'])
|
||||||
|
|
||||||
response['data']['positions'] = {}
|
response['data']['positions'] = {}
|
||||||
ids = [j['itemId'] for j in qs.values('itemId')]
|
ids = [j['itemId'] for j in qs.values('itemId')]
|
||||||
response['data']['positions'] = _get_positions(ids, query['ids'])
|
response['data']['positions'] = _get_positions(ids, query['ids'])
|
||||||
|
@ -371,7 +363,8 @@ def getImdbId(request):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
imdbId = ox.web.imdb.guess(search_title, r['director'], timeout=-1)
|
data = json.loads(request.POST['data'])
|
||||||
|
imdbId = ox.web.imdb.getImdbId(data['title'], data['director'], timeout=-1)
|
||||||
if imdbId:
|
if imdbId:
|
||||||
response = json_response({'imdbId': imdbId})
|
response = json_response({'imdbId': imdbId})
|
||||||
else:
|
else:
|
||||||
|
@ -406,7 +399,8 @@ def poster(request, id, size=None):
|
||||||
else:
|
else:
|
||||||
poster_path = item.poster.path
|
poster_path = item.poster.path
|
||||||
else:
|
else:
|
||||||
if not size: size='large'
|
if not size:
|
||||||
|
size='large'
|
||||||
return redirect('http://0xdb.org/%s/poster.%s.jpg' % (item.itemId, size))
|
return redirect('http://0xdb.org/%s/poster.%s.jpg' % (item.itemId, size))
|
||||||
poster_path = os.path.join(settings.STATIC_ROOT, 'png/posterDark.48.png')
|
poster_path = os.path.join(settings.STATIC_ROOT, 'png/posterDark.48.png')
|
||||||
return HttpFileResponse(poster_path, content_type='image/jpeg')
|
return HttpFileResponse(poster_path, content_type='image/jpeg')
|
||||||
|
|
|
@ -2,29 +2,12 @@
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division, with_statement
|
from __future__ import division, with_statement
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import os.path
|
|
||||||
import math
|
|
||||||
import random
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
import unicodedata
|
|
||||||
from glob import glob
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.files.base import ContentFile
|
|
||||||
from django.utils import simplejson as json
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.django import fields
|
|
||||||
import ox
|
|
||||||
from ox import stripTags
|
|
||||||
from ox.normalize import canonicalTitle, canonicalName
|
|
||||||
|
|
||||||
|
|
||||||
class List(models.Model):
|
class List(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("user", "name")
|
unique_together = ("user", "name")
|
||||||
|
|
||||||
|
@ -33,7 +16,8 @@ class List(models.Model):
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
public = models.BooleanField(default=False)
|
public = models.BooleanField(default=False)
|
||||||
items = models.ManyToManyField('item.Item', related_name='lists', through='ListItem')
|
items = models.ManyToManyField('item.Item', related_name='lists',
|
||||||
|
through='ListItem')
|
||||||
|
|
||||||
def add(self, item):
|
def add(self, item):
|
||||||
q = self.items.filter(id=item.id)
|
q = self.items.filter(id=item.id)
|
||||||
|
@ -55,6 +39,7 @@ class List(models.Model):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class ListItem(models.Model):
|
class ListItem(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
@ -63,4 +48,3 @@ class ListItem(models.Model):
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'%s in %s' % (self.item, self.list)
|
return u'%s in %s' % (self.item, self.list)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
|
@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
import os.path
|
|
||||||
import re
|
|
||||||
from datetime import datetime
|
|
||||||
from urllib2 import unquote
|
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db.models import Q, Avg, Count, Sum
|
|
||||||
from django.http import HttpResponse, Http404
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.utils import json
|
||||||
from ox.django.decorators import login_required_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.shortcuts import render_to_json_response, get_object_or_404_json, json_response
|
||||||
from ox.django.http import HttpFileResponse
|
|
||||||
import ox
|
|
||||||
|
|
||||||
|
import models
|
||||||
from api.actions import actions
|
from api.actions import actions
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,12 +32,13 @@ def addListItem(request):
|
||||||
response = json_response(status=403, text='not allowed')
|
response = json_response(status=403, text='not allowed')
|
||||||
elif 'query' in data:
|
elif 'query' in data:
|
||||||
response = json_response(status=501, text='not implemented')
|
response = json_response(status=501, text='not implemented')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
response = json_response(status=501, text='not implemented')
|
response = json_response(status=501, text='not implemented')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(addListItem)
|
actions.register(addListItem)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def removeListItem(request):
|
def removeListItem(request):
|
||||||
'''
|
'''
|
||||||
|
@ -76,12 +61,13 @@ def removeListItem(request):
|
||||||
response = json_response(status=403, text='not allowed')
|
response = json_response(status=403, text='not allowed')
|
||||||
elif 'query' in data:
|
elif 'query' in data:
|
||||||
response = json_response(status=501, text='not implemented')
|
response = json_response(status=501, text='not implemented')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
response = json_response(status=501, text='not implemented')
|
response = json_response(status=501, text='not implemented')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(removeListItem)
|
actions.register(removeListItem)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def addList(request):
|
def addList(request):
|
||||||
'''
|
'''
|
||||||
|
@ -97,12 +83,11 @@ def addList(request):
|
||||||
response = json_response(status=200, text='created')
|
response = json_response(status=200, text='created')
|
||||||
else:
|
else:
|
||||||
response = json_response(status=200, text='list already exists')
|
response = json_response(status=200, text='list already exists')
|
||||||
response['data']['errors'] = {
|
response['data']['errors'] = {'name': 'List already exists'}
|
||||||
'name': 'List already exists'
|
|
||||||
}
|
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(addList)
|
actions.register(addList)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def editList(request):
|
def editList(request):
|
||||||
'''
|
'''
|
||||||
|
@ -124,6 +109,8 @@ def editList(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(editList)
|
actions.register(editList)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required_json
|
||||||
def removeList(request):
|
def removeList(request):
|
||||||
'''
|
'''
|
||||||
param data
|
param data
|
||||||
|
@ -139,4 +126,3 @@ def removeList(request):
|
||||||
response = json_response(status=403, text='not allowed')
|
response = json_response(status=403, text='not allowed')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(removeList)
|
actions.register(removeList)
|
||||||
|
|
||||||
|
|
|
@ -2,26 +2,12 @@
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division, with_statement
|
from __future__ import division, with_statement
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import os.path
|
|
||||||
import math
|
|
||||||
import random
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
from glob import glob
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.files.base import ContentFile
|
|
||||||
from django.utils import simplejson as json
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.django import fields
|
from ox.django import fields
|
||||||
import ox
|
import ox
|
||||||
from ox import stripTags
|
|
||||||
from ox.normalize import canonicalTitle, canonicalName
|
|
||||||
|
|
||||||
|
|
||||||
def get_name_sort(name):
|
def get_name_sort(name):
|
||||||
|
@ -29,6 +15,7 @@ def get_name_sort(name):
|
||||||
name_sort = unicodedata.normalize('NFKD', person.name_sort)
|
name_sort = unicodedata.normalize('NFKD', person.name_sort)
|
||||||
return name_sort
|
return name_sort
|
||||||
|
|
||||||
|
|
||||||
class Person(models.Model):
|
class Person(models.Model):
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
name_sort = models.CharField(max_length=200)
|
name_sort = models.CharField(max_length=200)
|
||||||
|
@ -67,4 +54,3 @@ class Person(models.Model):
|
||||||
|
|
||||||
def json(self):
|
def json(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
|
@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
|
|
@ -9,5 +9,3 @@ import models
|
||||||
class PlaceAdmin(admin.ModelAdmin):
|
class PlaceAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name']
|
search_fields = ['name']
|
||||||
admin.site.register(models.Place, PlaceAdmin)
|
admin.site.register(models.Place, PlaceAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,23 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
import re
|
|
||||||
|
|
||||||
from ox.utils import json
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from django.db.models import Q, Manager
|
from django.db.models import Q, Manager
|
||||||
|
|
||||||
import models
|
|
||||||
|
|
||||||
class PlaceManager(Manager):
|
class PlaceManager(Manager):
|
||||||
|
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
return super(PlaceManager, self).get_query_set()
|
return super(PlaceManager, self).get_query_set()
|
||||||
|
|
||||||
def find(self, q='', f="globe", sw_lat=-180.0, sw_lng=-180.0, ne_lat=180.0, ne_lng=180.0):
|
def find(self, q='', f="globe", sw_lat=-180.0, sw_lng=-180.0, ne_lat=180.0, ne_lng=180.0):
|
||||||
qs = self.get_query_set()
|
qs = self.get_query_set()
|
||||||
qs = qs.filter(Q(
|
qs = qs.filter(Q(
|
||||||
Q(Q(sw_lat__gt=sw_lat)|Q(sw_lat__lt=ne_lat)|Q(sw_lng__gt=sw_lng)|Q(sw_lng__lt=ne_lng)) &
|
Q(Q(sw_lat__gt=sw_lat)|Q(sw_lat__lt=ne_lat)|Q(sw_lng__gt=sw_lng)|Q(sw_lng__lt=ne_lng)) &
|
||||||
Q(Q(sw_lat__gt=sw_lat)|Q(sw_lat__lt=ne_lat)|Q(sw_lng__lt=ne_lng)|Q(ne_lng__gt=ne_lng)) &
|
Q(Q(sw_lat__gt=sw_lat)|Q(sw_lat__lt=ne_lat)|Q(sw_lng__lt=ne_lng)|Q(ne_lng__gt=ne_lng)) &
|
||||||
Q(Q(ne_lat__gt=sw_lat)|Q(ne_lat__lt=ne_lat)|Q(sw_lng__gt=sw_lng)|Q(sw_lng__lt=ne_lng)) &
|
Q(Q(ne_lat__gt=sw_lat)|Q(ne_lat__lt=ne_lat)|Q(sw_lng__gt=sw_lng)|Q(sw_lng__lt=ne_lng)) &
|
||||||
Q(Q(ne_lat__gt=sw_lat)|Q(ne_lat__lt=ne_lat)|Q(ne_lng__gt=sw_lng)|Q(ne_lng__lt=ne_lng))
|
Q(Q(ne_lat__gt=sw_lat)|Q(ne_lat__lt=ne_lat)|Q(ne_lng__gt=sw_lng)|Q(ne_lng__lt=ne_lng))
|
||||||
))
|
))
|
||||||
if q:
|
if q:
|
||||||
qs = qs.filter(name_find__icontains, q)
|
qs = qs.filter(name_find__icontains=q)
|
||||||
return qs
|
return qs
|
||||||
'''
|
'''
|
||||||
#only return locations that have layers of videos visible to current user
|
#only return locations that have layers of videos visible to current user
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
from __future__ import division, with_statement
|
from __future__ import division, with_statement
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
import ox
|
||||||
from ox.django import fields
|
from ox.django import fields
|
||||||
|
|
||||||
import managers
|
import managers
|
||||||
|
|
||||||
|
|
||||||
class Place(models.Model):
|
class Place(models.Model):
|
||||||
'''
|
'''
|
||||||
Places are named locations, they should have geographical information attached to them.
|
Places are named locations, they should have geographical information attached to them.
|
||||||
|
@ -60,7 +60,6 @@ class Place(models.Model):
|
||||||
self.lng_center = ox.location.center(self.lng_sw, self.lng_ne)
|
self.lng_center = ox.location.center(self.lng_sw, self.lng_ne)
|
||||||
|
|
||||||
#update area
|
#update area
|
||||||
self.area = location.area(self.lat_sw, self.lng_sw, self.lat_ne, self.lng_ne)
|
self.area = ox.location.area(self.lat_sw, self.lng_sw, self.lat_ne, self.lng_ne)
|
||||||
|
|
||||||
super(Place, self).save(*args, **kwargs)
|
super(Place, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ Replace these with more appropriate tests for your application.
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
|
|
||||||
def test_basic_addition(self):
|
def test_basic_addition(self):
|
||||||
"""
|
"""
|
||||||
Tests that 1 + 1 always equals 2.
|
Tests that 1 + 1 always equals 2.
|
||||||
|
@ -20,4 +22,3 @@ Another way to test that 1 + 1 is equal to 2.
|
||||||
>>> 1 + 1 == 2
|
>>> 1 + 1 == 2
|
||||||
True
|
True
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
|
|
@ -1,37 +1,19 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
import os.path
|
|
||||||
import re
|
|
||||||
from datetime import datetime
|
|
||||||
from urllib2 import unquote
|
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db.models import Q, Avg, Count, Sum
|
|
||||||
from django.http import HttpResponse, Http404
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.utils import json
|
||||||
|
|
||||||
from ox.django.decorators import login_required_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.shortcuts import render_to_json_response, get_object_or_404_json, json_response
|
||||||
from ox.django.http import HttpFileResponse
|
|
||||||
import ox
|
|
||||||
|
|
||||||
import models
|
import models
|
||||||
from api.actions import actions
|
from api.actions import actions
|
||||||
|
|
||||||
'''
|
|
||||||
fixme, require admin
|
|
||||||
'''
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def addPlace(request):
|
def addPlace(request):
|
||||||
|
#FIXME: require admin
|
||||||
'''
|
'''
|
||||||
param data
|
param data
|
||||||
{
|
{
|
||||||
|
@ -56,6 +38,7 @@ def addPlace(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(addPlace)
|
actions.register(addPlace)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def editPlace(request):
|
def editPlace(request):
|
||||||
'''
|
'''
|
||||||
|
@ -86,17 +69,19 @@ def editPlace(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(editPlace)
|
actions.register(editPlace)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def removePlace(request):
|
def removePlace(request):
|
||||||
response = json_response(status=501, text='not implemented')
|
response = json_response(status=501, text='not implemented')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(removePlace)
|
actions.register(removePlace)
|
||||||
|
|
||||||
|
|
||||||
def findPlace(request):
|
def findPlace(request):
|
||||||
'''
|
'''
|
||||||
param data
|
param data
|
||||||
{'query': query, 'sort': array, 'range': array, 'area': array}
|
{'query': query, 'sort': array, 'range': array, 'area': array}
|
||||||
|
|
||||||
query: query object, more on query syntax at
|
query: query object, more on query syntax at
|
||||||
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
||||||
sort: array of key, operator dics
|
sort: array of key, operator dics
|
||||||
|
@ -120,7 +105,7 @@ def findPlace(request):
|
||||||
Positions
|
Positions
|
||||||
param data
|
param data
|
||||||
{'query': query, 'ids': []}
|
{'query': query, 'ids': []}
|
||||||
|
|
||||||
query: query object, more on query syntax at
|
query: query object, more on query syntax at
|
||||||
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
|
||||||
ids: ids of places for which positions are required
|
ids: ids of places for which positions are required
|
||||||
|
@ -129,8 +114,7 @@ Positions
|
||||||
response = json_response(status=200, text='ok')
|
response = json_response(status=200, text='ok')
|
||||||
response['data']['places'] = []
|
response['data']['places'] = []
|
||||||
#FIXME: add coordinates to limit search
|
#FIXME: add coordinates to limit search
|
||||||
for p in Places.objects.find(data['query']):
|
for p in models.Place.objects.find(data['query']):
|
||||||
response['data']['places'].append(p.json())
|
response['data']['places'].append(p.json())
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(findPlace)
|
actions.register(findPlace)
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,6 @@ from datetime import datetime
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
import ox
|
|
||||||
from ox.django import fields
|
|
||||||
from ox.utils import json
|
|
||||||
|
|
||||||
|
|
||||||
class News(models.Model):
|
class News(models.Model):
|
||||||
|
@ -29,6 +24,7 @@ class News(models.Model):
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return '/text/%s' % self.slug
|
return '/text/%s' % self.slug
|
||||||
|
|
||||||
|
|
||||||
class Text(models.Model):
|
class Text(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
@ -46,6 +42,7 @@ class Text(models.Model):
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return '/text/%s' % self.slug
|
return '/text/%s' % self.slug
|
||||||
|
|
||||||
|
|
||||||
class Image(models.Model):
|
class Image(models.Model):
|
||||||
image = models.ImageField(upload_to='text/image')
|
image = models.ImageField(upload_to='text/image')
|
||||||
caption = models.CharField(max_length=255, default="")
|
caption = models.CharField(max_length=255, default="")
|
||||||
|
@ -53,10 +50,10 @@ class Image(models.Model):
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return self.image.url
|
return self.image.url
|
||||||
|
|
||||||
|
|
||||||
class Attachment(models.Model):
|
class Attachment(models.Model):
|
||||||
file = models.FileField(upload_to='text/attachment')
|
file = models.FileField(upload_to='text/attachment')
|
||||||
caption = models.CharField(max_length=255, default="")
|
caption = models.CharField(max_length=255, default="")
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return self.file.url
|
return self.file.url
|
||||||
|
|
||||||
|
|
|
@ -2,23 +2,15 @@
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db.models import Q, Avg, Count, Sum
|
|
||||||
from django.http import HttpResponse, Http404
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
|
||||||
from django.template import RequestContext
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.utils import json
|
||||||
from ox.django.decorators import login_required_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.shortcuts import render_to_json_response, get_object_or_404_json, json_response
|
||||||
from ox.django.http import HttpFileResponse
|
|
||||||
import ox
|
|
||||||
|
|
||||||
import models
|
import models
|
||||||
from api.actions import actions
|
from api.actions import actions
|
||||||
|
|
||||||
|
|
||||||
def getNews(request):
|
def getNews(request):
|
||||||
'''
|
'''
|
||||||
param data
|
param data
|
||||||
|
@ -33,6 +25,23 @@ def getNews(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(getNews)
|
actions.register(getNews)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required_json
|
||||||
|
def editNews(request):
|
||||||
|
'''
|
||||||
|
param data
|
||||||
|
string id
|
||||||
|
|
||||||
|
return page
|
||||||
|
'''
|
||||||
|
response = json_response({})
|
||||||
|
itemId = json.loads(request.POST['data'])
|
||||||
|
item = get_object_or_404_json(models.Text, pk=itemId)
|
||||||
|
response['data']['page'] = item.html()
|
||||||
|
return render_to_json_response(response)
|
||||||
|
actions.register(editNews)
|
||||||
|
|
||||||
|
|
||||||
def findNews(request):
|
def findNews(request):
|
||||||
'''
|
'''
|
||||||
'''
|
'''
|
||||||
|
@ -40,6 +49,7 @@ def findNews(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(findNews)
|
actions.register(findNews)
|
||||||
|
|
||||||
|
|
||||||
def getText(request):
|
def getText(request):
|
||||||
'''
|
'''
|
||||||
param data
|
param data
|
||||||
|
@ -54,10 +64,26 @@ def getText(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(getText)
|
actions.register(getText)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required_json
|
||||||
|
def editText(request):
|
||||||
|
'''
|
||||||
|
param data
|
||||||
|
string id
|
||||||
|
|
||||||
|
return page
|
||||||
|
'''
|
||||||
|
response = json_response({})
|
||||||
|
itemId = json.loads(request.POST['data'])
|
||||||
|
item = get_object_or_404_json(models.Text, pk=itemId)
|
||||||
|
response['data']['page'] = item.html()
|
||||||
|
return render_to_json_response(response)
|
||||||
|
actions.register(editText)
|
||||||
|
|
||||||
|
|
||||||
def findText(request):
|
def findText(request):
|
||||||
'''
|
'''
|
||||||
'''
|
'''
|
||||||
response = json_response({})
|
response = json_response({})
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(findText)
|
actions.register(findText)
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,14 @@ from django.conf import settings
|
||||||
import ox.torrent
|
import ox.torrent
|
||||||
import transmissionrpc
|
import transmissionrpc
|
||||||
|
|
||||||
|
|
||||||
def connect():
|
def connect():
|
||||||
return transmissionrpc.Client(settings.TRANSMISSON_HOST,
|
return transmissionrpc.Client(settings.TRANSMISSON_HOST,
|
||||||
port=settings.TRANSMISSON_PORT,
|
port=settings.TRANSMISSON_PORT,
|
||||||
user=settings.TRANSMISSON_USER,
|
user=settings.TRANSMISSON_USER,
|
||||||
password=settings.TRANSMISSON_PASSWORD)
|
password=settings.TRANSMISSON_PASSWORD)
|
||||||
|
|
||||||
|
|
||||||
def remove(info_hash):
|
def remove(info_hash):
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
print 'remove', info_hash
|
print 'remove', info_hash
|
||||||
|
@ -24,10 +26,11 @@ def remove(info_hash):
|
||||||
tc = connect()
|
tc = connect()
|
||||||
tc.remove(info_hash.lower())
|
tc.remove(info_hash.lower())
|
||||||
except:
|
except:
|
||||||
if DEBUG:
|
if settings.DEBUG:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def add(torrent_file):
|
def add(torrent_file):
|
||||||
download_dir = os.path.dirname(torrent_file)
|
download_dir = os.path.dirname(torrent_file)
|
||||||
with open(torrent_file) as f:
|
with open(torrent_file) as f:
|
||||||
|
@ -42,6 +45,7 @@ def add(torrent_file):
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def is_seeding(info_hash):
|
def is_seeding(info_hash):
|
||||||
info_hash = info_hash.lower()
|
info_hash = info_hash.lower()
|
||||||
try:
|
try:
|
||||||
|
@ -56,6 +60,7 @@ def is_seeding(info_hash):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def start_daemon():
|
def start_daemon():
|
||||||
try:
|
try:
|
||||||
tc = connect()
|
tc = connect()
|
||||||
|
@ -71,4 +76,3 @@ def start_daemon():
|
||||||
'-w', settings.MEDIA_ROOT,
|
'-w', settings.MEDIA_ROOT,
|
||||||
])
|
])
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
|
@ -5,24 +5,25 @@ from datetime import datetime
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import signals
|
|
||||||
from django.dispatch import dispatcher
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from ox.utils import json
|
from ox.utils import json
|
||||||
|
|
||||||
|
|
||||||
class UserProfile(models.Model):
|
class UserProfile(models.Model):
|
||||||
reset_token = models.TextField(blank=True, null=True, unique=True)
|
reset_token = models.TextField(blank=True, null=True, unique=True)
|
||||||
user = models.ForeignKey(User, unique=True)
|
user = models.ForeignKey(User, unique=True)
|
||||||
|
|
||||||
files_updated = models.DateTimeField(default=datetime.now)
|
files_updated = models.DateTimeField(default=datetime.now)
|
||||||
newsletter = models.BooleanField(default=True)
|
newsletter = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
|
||||||
def user_post_save(sender, instance, **kwargs):
|
def user_post_save(sender, instance, **kwargs):
|
||||||
profile, new = UserProfile.objects.get_or_create(user=instance)
|
profile, new = UserProfile.objects.get_or_create(user=instance)
|
||||||
|
|
||||||
models.signals.post_save.connect(user_post_save, sender=User)
|
models.signals.post_save.connect(user_post_save, sender=User)
|
||||||
|
|
||||||
|
|
||||||
class Preference(models.Model):
|
class Preference(models.Model):
|
||||||
user = models.ForeignKey(User, related_name='preferences')
|
user = models.ForeignKey(User, related_name='preferences')
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
@ -33,18 +34,20 @@ class Preference(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"%s/%s=%s" % (self.user, self.key, self.value)
|
return u"%s/%s=%s" % (self.user, self.key, self.value)
|
||||||
|
|
||||||
|
|
||||||
def get_user_json(user):
|
def get_user_json(user):
|
||||||
json = {}
|
result = {}
|
||||||
for key in ('username', ):
|
for key in ('username', ):
|
||||||
json[key] = getattr(user, key)
|
result[key] = getattr(user, key)
|
||||||
json['group'] = 'user'
|
result['group'] = 'user'
|
||||||
if user.is_staff:
|
if user.is_staff:
|
||||||
json['group'] = 'admin'
|
result['group'] = 'admin'
|
||||||
elif user.has_perm('0x.vip'): #FIXME: permissions
|
elif user.has_perm('0x.vip'): #FIXME: permissions
|
||||||
json['group'] = 'vip'
|
result['group'] = 'vip'
|
||||||
json['preferences'] = get_preferences(user)
|
result['preferences'] = get_preferences(user)
|
||||||
json['ui'] = get_ui(user)
|
result['ui'] = get_ui(user)
|
||||||
return json
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_ui(user):
|
def get_ui(user):
|
||||||
with open(os.path.join(settings.PROJECT_ROOT, 'templates', 'site.json')) as f:
|
with open(os.path.join(settings.PROJECT_ROOT, 'templates', 'site.json')) as f:
|
||||||
|
@ -70,6 +73,7 @@ def get_ui(user):
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def get_preferences(user):
|
def get_preferences(user):
|
||||||
prefs = {}
|
prefs = {}
|
||||||
for p in Preference.objects.filter(user=user):
|
for p in Preference.objects.filter(user=user):
|
||||||
|
@ -77,6 +81,7 @@ def get_preferences(user):
|
||||||
prefs['email'] = user.email
|
prefs['email'] = user.email
|
||||||
return prefs
|
return prefs
|
||||||
|
|
||||||
|
|
||||||
def get_preference(user, key, value=None):
|
def get_preference(user, key, value=None):
|
||||||
if key in ('email', ):
|
if key in ('email', ):
|
||||||
value = getattr(user, key)
|
value = getattr(user, key)
|
||||||
|
@ -86,6 +91,7 @@ def get_preference(user, key, value=None):
|
||||||
value = json.loads(q[0].value)
|
value = json.loads(q[0].value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def set_preference(user, key, value):
|
def set_preference(user, key, value):
|
||||||
if key in ('email', ):
|
if key in ('email', ):
|
||||||
setattr(user, key, value)
|
setattr(user, key, value)
|
||||||
|
|
|
@ -7,8 +7,7 @@ random.seed()
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth import authenticate, login, logout
|
from django.contrib.auth import authenticate, login, logout
|
||||||
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
|
from django.template import RequestContext, loader
|
||||||
from django.template import RequestContext, loader, Context
|
|
||||||
from django.utils import simplejson as json
|
from django.utils import simplejson as json
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import send_mail, BadHeaderError
|
from django.core.mail import send_mail, BadHeaderError
|
||||||
|
@ -26,13 +25,14 @@ class LoginForm(forms.Form):
|
||||||
username = forms.TextInput()
|
username = forms.TextInput()
|
||||||
password = forms.TextInput()
|
password = forms.TextInput()
|
||||||
|
|
||||||
|
|
||||||
def api_login(request):
|
def api_login(request):
|
||||||
'''
|
'''
|
||||||
param data {
|
param data {
|
||||||
username: 'username',
|
username: 'username',
|
||||||
password: 'password'
|
password: 'password'
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: {'code': 200, 'text': 'ok'}
|
status: {'code': 200, 'text': 'ok'}
|
||||||
data: {
|
data: {
|
||||||
|
@ -81,11 +81,12 @@ def api_login(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(api_login, 'login')
|
actions.register(api_login, 'login')
|
||||||
|
|
||||||
|
|
||||||
def api_logout(request):
|
def api_logout(request):
|
||||||
'''
|
'''
|
||||||
param data {
|
param data {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: {'code': int, 'text': string}
|
status: {'code': int, 'text': string}
|
||||||
data: {
|
data: {
|
||||||
|
@ -105,11 +106,13 @@ def api_logout(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(api_logout, 'logout')
|
actions.register(api_logout, 'logout')
|
||||||
|
|
||||||
|
|
||||||
class RegisterForm(forms.Form):
|
class RegisterForm(forms.Form):
|
||||||
username = forms.TextInput()
|
username = forms.TextInput()
|
||||||
password = forms.TextInput()
|
password = forms.TextInput()
|
||||||
email = forms.TextInput()
|
email = forms.TextInput()
|
||||||
|
|
||||||
|
|
||||||
def register(request):
|
def register(request):
|
||||||
'''
|
'''
|
||||||
param data {
|
param data {
|
||||||
|
@ -117,7 +120,7 @@ def register(request):
|
||||||
password: 'password',
|
password: 'password',
|
||||||
email: 'emailaddress'
|
email: 'emailaddress'
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: {'code': int, 'text': string}
|
status: {'code': int, 'text': string}
|
||||||
data: {
|
data: {
|
||||||
|
@ -172,13 +175,14 @@ def register(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(register)
|
actions.register(register)
|
||||||
|
|
||||||
|
|
||||||
def resetPassword(request):
|
def resetPassword(request):
|
||||||
'''
|
'''
|
||||||
param data {
|
param data {
|
||||||
token: reset token
|
token: reset token
|
||||||
password: new password
|
password: new password
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: {'code': int, 'text': string}
|
status: {'code': int, 'text': string}
|
||||||
data: {
|
data: {
|
||||||
|
@ -226,13 +230,14 @@ def resetPassword(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(resetPassword)
|
actions.register(resetPassword)
|
||||||
|
|
||||||
|
|
||||||
def requestToken(request):
|
def requestToken(request):
|
||||||
'''
|
'''
|
||||||
param data {
|
param data {
|
||||||
username: username,
|
username: username,
|
||||||
email: email
|
email: email
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: {'code': int, 'text': string}
|
status: {'code': int, 'text': string}
|
||||||
data: {
|
data: {
|
||||||
|
@ -291,13 +296,14 @@ def requestToken(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(requestToken)
|
actions.register(requestToken)
|
||||||
|
|
||||||
|
|
||||||
def findUser(request):
|
def findUser(request):
|
||||||
'''
|
'''
|
||||||
param data {
|
param data {
|
||||||
key: "username",
|
key: "username",
|
||||||
value: "foo", operator: "="
|
value: "foo", operator: "="
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'status': {'code': int, 'text': string}
|
'status': {'code': int, 'text': string}
|
||||||
'data': {
|
'data': {
|
||||||
|
@ -315,18 +321,20 @@ def findUser(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(findUser)
|
actions.register(findUser)
|
||||||
|
|
||||||
|
|
||||||
class ContactForm(forms.Form):
|
class ContactForm(forms.Form):
|
||||||
email = forms.EmailField()
|
email = forms.EmailField()
|
||||||
subject = forms.TextInput()
|
subject = forms.TextInput()
|
||||||
message = forms.TextInput()
|
message = forms.TextInput()
|
||||||
|
|
||||||
|
|
||||||
def contact(request):
|
def contact(request):
|
||||||
'''
|
'''
|
||||||
param data {
|
param data {
|
||||||
'email': string,
|
'email': string,
|
||||||
'message': string
|
'message': string
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'status': {'code': int, 'text': string}
|
'status': {'code': int, 'text': string}
|
||||||
}
|
}
|
||||||
|
@ -353,6 +361,7 @@ def contact(request):
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(contact)
|
actions.register(contact)
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
def preferences(request):
|
def preferences(request):
|
||||||
'''
|
'''
|
||||||
|
@ -391,4 +400,3 @@ def preferences(request):
|
||||||
models.set_preference(request.user, key, data[key])
|
models.set_preference(request.user, key, data[key])
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
actions.register(preferences)
|
actions.register(preferences)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue