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