From 9defcd3c9f8a2218fcca3842f45b714ceb3ea54c Mon Sep 17 00:00:00 2001
From: j <0x006A@0x2620.org>
Date: Mon, 12 Jul 2010 16:56:14 +0200
Subject: [PATCH] - simplify metadata db structure - better sort values if
field is empty - switch to python-ox, faster imdb import - move files backend
into own app
---
pandora/archive/__init__.py | 0
pandora/archive/admin.py | 25 +
pandora/archive/migrations/0001_initial.py | 240 ++++++
pandora/archive/migrations/__init__.py | 0
pandora/archive/models.py | 182 +++++
pandora/archive/tests.py | 23 +
pandora/archive/views.py | 164 ++++
pandora/backend/admin.py | 24 +-
pandora/backend/forms.py | 4 +-
pandora/backend/managers.py | 6 +-
pandora/backend/migrations/0003_archive.py | 647 +++++++++++++++
pandora/backend/models.py | 898 ++++-----------------
pandora/backend/tasks.py | 11 +-
pandora/backend/utils.py | 29 +-
pandora/backend/views.py | 153 +---
pandora/settings.py | 1 +
16 files changed, 1493 insertions(+), 914 deletions(-)
create mode 100644 pandora/archive/__init__.py
create mode 100644 pandora/archive/admin.py
create mode 100644 pandora/archive/migrations/0001_initial.py
create mode 100644 pandora/archive/migrations/__init__.py
create mode 100644 pandora/archive/models.py
create mode 100644 pandora/archive/tests.py
create mode 100644 pandora/archive/views.py
create mode 100644 pandora/backend/migrations/0003_archive.py
diff --git a/pandora/archive/__init__.py b/pandora/archive/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pandora/archive/admin.py b/pandora/archive/admin.py
new file mode 100644
index 00000000..1cebf187
--- /dev/null
+++ b/pandora/archive/admin.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+from django.contrib import admin
+
+#from forms import FileAdminForm, MovieAdminForm, ArchiveFileAdminForm
+import models
+
+class FileAdmin(admin.ModelAdmin):
+ search_fields = ['path', 'video_codec']
+
+ #form = FileAdminForm
+
+admin.site.register(models.File, FileAdmin)
+
+class FileInstanceAdmin(admin.ModelAdmin):
+ search_fields = ['path', 'archive__name']
+ #form = ArchiveFileAdminForm
+
+admin.site.register(models.FileInstance, FileInstanceAdmin)
+
+class ArchiveAdmin(admin.ModelAdmin):
+ search_fields = ['name']
+admin.site.register(models.Archive, ArchiveAdmin)
+
diff --git a/pandora/archive/migrations/0001_initial.py b/pandora/archive/migrations/0001_initial.py
new file mode 100644
index 00000000..653749f3
--- /dev/null
+++ b/pandora/archive/migrations/0001_initial.py
@@ -0,0 +1,240 @@
+# -*- coding: utf-8 -*-
+
+from south.db import db
+from django.db import models
+from archive.models import *
+
+class Migration:
+
+ def forwards(self, orm):
+
+ # Adding model 'Volume'
+ db.create_table('archive_volume', (
+ ('id', orm['archive.Volume:id']),
+ ('start', orm['archive.Volume:start']),
+ ('end', orm['archive.Volume:end']),
+ ('name', orm['archive.Volume:name']),
+ ))
+ db.send_create_signal('archive', ['Volume'])
+
+ # Adding model 'Frame'
+ db.create_table('archive_frame', (
+ ('id', orm['archive.Frame:id']),
+ ('created', orm['archive.Frame:created']),
+ ('modified', orm['archive.Frame:modified']),
+ ('file', orm['archive.Frame:file']),
+ ('position', orm['archive.Frame:position']),
+ ('frame', orm['archive.Frame:frame']),
+ ))
+ db.send_create_signal('archive', ['Frame'])
+
+ # Adding model 'Archive'
+ db.create_table('archive_archive', (
+ ('id', orm['archive.Archive:id']),
+ ('created', orm['archive.Archive:created']),
+ ('modified', orm['archive.Archive:modified']),
+ ('published', orm['archive.Archive:published']),
+ ('name', orm['archive.Archive:name']),
+ ('user', orm['archive.Archive:user']),
+ ))
+ db.send_create_signal('archive', ['Archive'])
+
+ # Adding model 'File'
+ db.create_table('archive_file', (
+ ('id', orm['archive.File:id']),
+ ('created', orm['archive.File:created']),
+ ('modified', orm['archive.File:modified']),
+ ('verified', orm['archive.File:verified']),
+ ('oshash', orm['archive.File:oshash']),
+ ('movie', orm['archive.File:movie']),
+ ('name', orm['archive.File:name']),
+ ('sort_name', orm['archive.File:sort_name']),
+ ('part', orm['archive.File:part']),
+ ('version', orm['archive.File:version']),
+ ('language', orm['archive.File:language']),
+ ('season', orm['archive.File:season']),
+ ('episode', orm['archive.File:episode']),
+ ('size', orm['archive.File:size']),
+ ('duration', orm['archive.File:duration']),
+ ('info', orm['archive.File:info']),
+ ('video_codec', orm['archive.File:video_codec']),
+ ('pixel_format', orm['archive.File:pixel_format']),
+ ('display_aspect_ratio', orm['archive.File:display_aspect_ratio']),
+ ('width', orm['archive.File:width']),
+ ('height', orm['archive.File:height']),
+ ('framerate', orm['archive.File:framerate']),
+ ('audio_codec', orm['archive.File:audio_codec']),
+ ('channels', orm['archive.File:channels']),
+ ('samplerate', orm['archive.File:samplerate']),
+ ('bits_per_pixel', orm['archive.File:bits_per_pixel']),
+ ('pixels', orm['archive.File:pixels']),
+ ('is_audio', orm['archive.File:is_audio']),
+ ('is_video', orm['archive.File:is_video']),
+ ('is_extra', orm['archive.File:is_extra']),
+ ('is_main', orm['archive.File:is_main']),
+ ('is_subtitle', orm['archive.File:is_subtitle']),
+ ('is_version', orm['archive.File:is_version']),
+ ))
+ db.send_create_signal('archive', ['File'])
+
+ # Adding model 'FileInstance'
+ db.create_table('archive_fileinstance', (
+ ('id', orm['archive.FileInstance:id']),
+ ('created', orm['archive.FileInstance:created']),
+ ('modified', orm['archive.FileInstance:modified']),
+ ('published', orm['archive.FileInstance:published']),
+ ('accessed', orm['archive.FileInstance:accessed']),
+ ('path', orm['archive.FileInstance:path']),
+ ('folder', orm['archive.FileInstance:folder']),
+ ('file', orm['archive.FileInstance:file']),
+ ('archive', orm['archive.FileInstance:archive']),
+ ))
+ db.send_create_signal('archive', ['FileInstance'])
+
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Volume'
+ db.delete_table('archive_volume')
+
+ # Deleting model 'Frame'
+ db.delete_table('archive_frame')
+
+ # Deleting model 'Archive'
+ db.delete_table('archive_archive')
+
+ # Deleting model 'File'
+ db.delete_table('archive_file')
+
+ # Deleting model 'FileInstance'
+ db.delete_table('archive_fileinstance')
+
+
+
+ models = {
+ 'archive.archive': {
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'published': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'owned_archives'", 'to': "orm['auth.User']"}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False'}),
+ 'volumes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['archive.Volume']", 'symmetrical': 'False'})
+ },
+ 'archive.file': {
+ 'audio_codec': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'bits_per_pixel': ('django.db.models.fields.FloatField', [], {'default': '-1'}),
+ 'channels': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'display_aspect_ratio': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'duration': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
+ 'framerate': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'info': ('fields.DictField', [], {'default': '{}'}),
+ 'is_audio': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_extra': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_main': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_subtitle': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_version': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_video': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '8'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'movie': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'files'", 'to': "orm['backend.Movie']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ 'oshash': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'part': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+ 'pixel_format': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pixels': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'samplerate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'sort_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}),
+ 'verified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+ 'video_codec': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'archive.fileinstance': {
+ 'accessed': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'archive': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'files'", 'to': "orm['archive.Archive']"}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'file': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'instances'", 'to': "orm['archive.File']"}),
+ 'folder': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'path': ('django.db.models.fields.CharField', [], {'max_length': '2048'}),
+ 'published': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+ },
+ 'archive.frame': {
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'file': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'frames'", 'to': "orm['archive.File']"}),
+ 'frame': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'position': ('django.db.models.fields.FloatField', [], {})
+ },
+ 'archive.volume': {
+ 'end': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'start': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'auth.group': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'backend.movie': {
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'imdb': ('fields.DictField', [], {'default': '{}', 'editable': 'False'}),
+ 'json': ('fields.DictField', [], {'default': '{}', 'editable': 'False'}),
+ 'metadata': ('fields.DictField', [], {'default': '{}', 'editable': 'False'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'movieId': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128', 'blank': 'True'}),
+ 'oxdbId': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '42', 'blank': 'True'}),
+ 'poster_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'poster_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'published': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'scene_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'stream_high': ('django.db.models.fields.files.FileField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'}),
+ 'stream_low': ('django.db.models.fields.files.FileField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'}),
+ 'stream_mid': ('django.db.models.fields.files.FileField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['archive']
diff --git a/pandora/archive/migrations/__init__.py b/pandora/archive/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pandora/archive/models.py b/pandora/archive/models.py
new file mode 100644
index 00000000..bba62bb4
--- /dev/null
+++ b/pandora/archive/models.py
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+from datetime import datetime
+import os.path
+import random
+import re
+from decimal import Decimal
+
+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 oxdjango import fields
+import ox
+from ox import stripTags
+from ox.normalize import canonicalTitle, canonicalName
+from firefogg import Firefogg
+
+from backend import utils
+from backend import extract
+from pandora.backend.models import Movie
+
+def parse_decimal(string):
+ string = string.replace(':', '/')
+ if '/' not in string:
+ string = '%s/1' % string
+ d = string.split('/')
+ return Decimal(d[0]) / Decimal(d[1])
+
+#ARCHIVE stuff
+class Volume(models.Model):
+ start = models.CharField(max_length=1)
+ end = models.CharField(max_length=1)
+ name = models.CharField(max_length=255)
+
+class Archive(models.Model):
+ created = models.DateTimeField(auto_now_add=True)
+ modified = models.DateTimeField(auto_now=True)
+ published = models.DateTimeField(default=datetime.now, editable=False)
+
+ name = models.CharField(max_length=255)
+ user = models.ForeignKey(User, related_name='owned_archives')
+
+ users = models.ManyToManyField(User, related_name='archives')
+ volumes = models.ManyToManyField(Volume, related_name='archives')
+
+ def editable(self, user):
+ return self.users.filter(username=user.username).count() > 0
+
+class File(models.Model):
+ created = models.DateTimeField(auto_now_add=True)
+ modified = models.DateTimeField(auto_now=True)
+
+ verified = models.BooleanField(default = False)
+
+ oshash = models.CharField(max_length=16)
+ movie = models.ForeignKey(Movie, 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
+
+ part = models.CharField(default="", max_length=255)
+ version = models.CharField(default="", max_length=255) # sort path/file name
+ language = models.CharField(default="", max_length=8)
+
+ season = models.IntegerField(default = -1)
+ episode = models.IntegerField(default = -1)
+
+ size = models.BigIntegerField(default = 0)
+ duration = models.IntegerField(default = 0)
+
+ info = fields.DictField(default={})
+
+ video_codec = models.CharField(max_length=255)
+ pixel_format = models.CharField(max_length=255)
+ display_aspect_ratio = models.CharField(max_length=255)
+ width = models.IntegerField(default = 0)
+ height = models.IntegerField(default = 0)
+ framerate = models.CharField(max_length=255)
+
+ audio_codec = models.CharField(max_length=255)
+ channels = models.IntegerField(default = 0)
+ samplerate = models.IntegerField(default = 0)
+
+ bits_per_pixel = models.FloatField(default=-1)
+ pixels = models.BigIntegerField(default=0)
+
+ is_audio = models.BooleanField(default = False)
+ is_video = models.BooleanField(default = False)
+ is_extra = models.BooleanField(default = False)
+ is_main = models.BooleanField(default = False)
+ is_subtitle = models.BooleanField(default = False)
+ is_version = models.BooleanField(default = False)
+
+ def __unicode__(self):
+ return self.name
+
+ def save(self, *args, **kwargs):
+ if self.name and not self.sort_name:
+ self.sort_name = canonicalTitle(self.name)
+ if self.info:
+ for key in ('duration', 'size'):
+ setattr(self, key, self.info.get(key, 0))
+
+ if 'video' in self.info and self.info['video']:
+ self.video_codec = self.info['video'][0]['codec']
+ self.width = self.info['video'][0]['width']
+ self.height = self.info['video'][0]['height']
+ self.framerate = self.info['video'][0]['framerate']
+ if 'display_aspect_ratio' in self.info['video'][0]:
+ self.display_aspect_ratio = self.info['video'][0]['display_aspect_ratio']
+ else:
+ self.display_aspect_ratio = "%s:%s" % (self.width, self.height)
+ self.is_video = True
+ self.is_audio = False
+ else:
+ self.is_video = False
+ if 'audio' in self.info and self.info['audio']:
+ self.audio_codec = self.info['audio'][0]['codec']
+ self.samplerate = self.info['audio'][0]['samplerate']
+ self.channels = self.info['audio'][0]['channels']
+
+ if not self.is_video:
+ self.is_audio = True
+ else:
+ self.is_audio = False
+
+ if self.framerate:
+ self.pixels = int(self.width * self.height * float(parse_decimal(self.framerate)) * self.duration)
+
+ if not self.is_audio and not self.is_video and self.name.endswith('.srt'):
+ self.is_subtitle = True
+
+ if self.name and self.name.startswith('Extra/'):
+ self.is_extra = True
+ self.is_main = False
+ else:
+ self.is_extra = False
+ self.is_main = True
+
+ super(File, self).save(*args, **kwargs)
+
+ def json(self):
+ r = {}
+ for k in self:
+ r[k] = unicode(self[k])
+ return r
+
+class FileInstance(models.Model):
+ created = models.DateTimeField(auto_now_add=True)
+ modified = models.DateTimeField(auto_now=True)
+ published = models.DateTimeField(default=datetime.now, editable=False)
+ accessed = models.DateTimeField(default=datetime.now, editable=False)
+
+ path = models.CharField(max_length=2048)
+ folder = models.CharField(max_length=255)
+
+ file = models.ForeignKey(File, related_name='instances')
+ archive = models.ForeignKey(Archive, related_name='files')
+
+ def __unicode__(self):
+ return u'%s <%s> in %s'% (self.path, self.oshash, self.archive.name)
+
+ @property
+ def movieId(self):
+ return File.objects.get(oshash=self.oshash).movieId
+
+class Frame(models.Model):
+ created = models.DateTimeField(auto_now_add=True)
+ modified = models.DateTimeField(auto_now=True)
+ file = models.ForeignKey(File, related_name="frames")
+ position = models.FloatField()
+ frame = models.ImageField(default=None, null=True, upload_to=lambda f, x: frame_path(f))
+
+ #FIXME: frame path should be renamed on save to match current position
+
+ def __unicode__(self):
+ return '%s at %s' % (self.file, self.position)
+
diff --git a/pandora/archive/tests.py b/pandora/archive/tests.py
new file mode 100644
index 00000000..2247054b
--- /dev/null
+++ b/pandora/archive/tests.py
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+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.
+ """
+ self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/pandora/archive/views.py b/pandora/archive/views.py
new file mode 100644
index 00000000..c3d8fd9a
--- /dev/null
+++ b/pandora/archive/views.py
@@ -0,0 +1,164 @@
+# -*- 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
+from django.template import RequestContext
+from django.conf import settings
+
+try:
+ import simplejson as json
+except ImportError:
+ from django.utils import simplejson as json
+
+from oxdjango.decorators import login_required_json
+from oxdjango.shortcuts import render_to_json_response, get_object_or_404_json, json_response
+from oxdjango.http import HttpFileResponse
+import ox
+
+import models
+
+from backend.utils import oxid, parsePath
+import backend.models
+
+
+
+#@login_required_json
+def api_update(request):
+ '''
+ param data
+ {archive: string, files: json}
+ return {'status': {'code': int, 'text': string},
+ 'data': {info: object, rename: object}}
+ '''
+ data = json.loads(request.POST['data'])
+ archive = data['archive']
+ folder = data['folder']
+ files = data['files']
+ needs_data = []
+ rename = []
+ archive, created = models.Archive.objects.get_or_create(name=archive, user=request.user)
+ if archive.editable(request.user):
+ print 'editing'
+ same_folder = models.FileInstance.objects.filter(folder=folder)
+ if same_folder.count() > 0:
+ movie = same_folder[0].file.movie
+ else:
+ movie = None
+ for filename in files:
+ data = files[filename]
+ oshash = data['oshash']
+ path = os.path.join(folder, filename)
+
+ instance = models.FileInstance.objects.filter(file__oshash=oshash)
+ if instance.count()>0:
+ instance = instance[0]
+ if path != instance.path: #file was movied
+ instance.path = path
+ instance.folder = folder
+ f.save()
+ print "file movied, so other shit"
+ else:
+ #look if oshash is known
+ f = models.File.objects.filter(oshash=oshash)
+ if f.count() > 0:
+ f = f[0]
+ instance = models.FileInstance()
+ instance.file = f
+ instance.path=data['path']
+ instance.folder=folder
+ instance.save()
+ movie = f.movie
+ #new oshash, add to database
+ else:
+ if not movie:
+ movie_info = parsePath(folder)
+ movie = backend.models.getMovie(movie_info)
+ f = models.File()
+ f.oshash = oshash
+ f.info = data
+ del f.info['oshash']
+ f.name = filename
+ f.movie = movie
+ f.save()
+ instance = models.FileInstance()
+ instance.archive = archive
+ instance.file = f
+ instance.path = path
+ instance.folder = folder
+ instance.save()
+
+ response = json_response({'info': needs_data, 'rename': rename})
+ else:
+ response = json_response(status=403, text='permission denied')
+ return render_to_json_response(response)
+
+@login_required_json
+def api_addArchive(request):
+ '''
+ ARCHIVE API NEEDS CLEANUP
+ param data
+ {name: string}
+ return {'status': {'code': int, 'text': string},
+ 'data': {}}
+ '''
+ data = json.loads(request.POST['data'])
+ try:
+ archive = models.Archive.objects.get(name=data['name'])
+ response = {'status': {'code': 401, 'text': 'archive with this name exists'}}
+ except models.Archive.DoesNotExist:
+ archive = models.Archive(name=data['name'])
+ archive.user = request.user
+ archive.save()
+ archive.users.add(request.user)
+ response = json_response({})
+ response['status']['text'] = 'archive created'
+ return render_to_json_response(response)
+
+@login_required_json
+def api_editArchive(request):
+ '''
+ ARCHIVE API NEEDS CLEANUP
+ param data
+ {id: string, key: value,..}
+ return {'status': {'code': int, 'text': string},
+ 'data': {}}
+ '''
+ data = json.loads(request.POST['data'])
+ item = get_object_or_404_json(models.Archive, name=data['name'])
+ if item.editable(request.user):
+ response = json_response(status=501, text='not implemented')
+ item.edit(data)
+ else:
+ response = json_response(status=403, text='permission denied')
+ return render_to_json_response(response)
+
+@login_required_json
+def api_removeArchive(request):
+ '''
+ ARCHIVE API NEEDS CLEANUP
+ param data
+ string id
+
+ return {'status': {'code': int, 'text': string}}
+ '''
+ response = json_response({})
+ itemId = json.loads(request.POST['data'])
+ item = get_object_or_404_json(models.Archive, movieId=itemId)
+ if item.editable(request.user):
+ response = json_response(status=501, text='not implemented')
+ else:
+ response = json_response(status=403, text='permission denied')
+ return render_to_json_response(response)
+
diff --git a/pandora/backend/admin.py b/pandora/backend/admin.py
index fa1d2f08..e9193531 100644
--- a/pandora/backend/admin.py
+++ b/pandora/backend/admin.py
@@ -3,41 +3,27 @@
from django.contrib import admin
-from forms import FileAdminForm, MovieAdminForm, ArchiveFileAdminForm
+#from forms import FileAdminForm, MovieAdminForm, ArchiveFileAdminForm
import models
+
+'''
#class MovieImdbAdmin(admin.ModelAdmin):
# search_fields = ['imdbId', 'title']
#admin.site.register(models.MovieImdb, MovieImdbAdmin)
-
class MovieImdbInline(admin.StackedInline):
model = models.MovieImdb
class MovieOxdbInline(admin.StackedInline):
model = models.MovieOxdb
+'''
class MovieAdmin(admin.ModelAdmin):
search_fields = ['movieId', 'imdb__title', 'oxdb__title']
- form = MovieAdminForm
+ #form = MovieAdminForm
#inlines = [MovieImdbInline, MovieOxdbInline]
admin.site.register(models.Movie, MovieAdmin)
-class FileAdmin(admin.ModelAdmin):
- search_fields = ['path', 'video_codec']
-
- form = FileAdminForm
-
-admin.site.register(models.File, FileAdmin)
-
-class ArchiveFileAdmin(admin.ModelAdmin):
- search_fields = ['path', 'archive__name']
- form = ArchiveFileAdminForm
-
-admin.site.register(models.ArchiveFile, ArchiveFileAdmin)
-
-class ArchiveAdmin(admin.ModelAdmin):
- search_fields = ['name']
-admin.site.register(models.Archive, ArchiveAdmin)
diff --git a/pandora/backend/forms.py b/pandora/backend/forms.py
index 15cc3d20..dd2c5509 100644
--- a/pandora/backend/forms.py
+++ b/pandora/backend/forms.py
@@ -10,7 +10,7 @@ ajax_filtered_js = (
settings.STATIC_URL + 'js/jquery/jquery.js',
settings.STATIC_URL + 'js/ajax_filtered_fields.js',
)
-
+"""
class FileAdminForm(forms.ModelForm):
movie = ForeignKeyByLetter(models.Movie, field_name='imdb__title')
@@ -39,4 +39,4 @@ class MovieAdminForm(forms.ModelForm):
class Media:
js = ajax_filtered_js
-
+"""
diff --git a/pandora/backend/managers.py b/pandora/backend/managers.py
index 7dff3d82..bc563701 100644
--- a/pandora/backend/managers.py
+++ b/pandora/backend/managers.py
@@ -46,7 +46,7 @@ class MovieManager(Manager):
query: {
conditions: [
{
- value: "war""
+ value: "war"
}
{
key: "year",
@@ -59,10 +59,10 @@ class MovieManager(Manager):
operator: "^"
}
],
- operator: "&"
+ operator: ","
}
'''
- query_operator = data['query'].get('operator', '&')
+ query_operator = data['query'].get('operator', ',')
conditions = []
for condition in data['query']['conditions']:
k = condition.get('key', 'all')
diff --git a/pandora/backend/migrations/0003_archive.py b/pandora/backend/migrations/0003_archive.py
new file mode 100644
index 00000000..fa9079d5
--- /dev/null
+++ b/pandora/backend/migrations/0003_archive.py
@@ -0,0 +1,647 @@
+# -*- coding: utf-8 -*-
+
+from south.db import db
+from django.db import models
+from backend.models import *
+
+class Migration:
+
+ def forwards(self, orm):
+
+ # Deleting unique_together for [imdb] on movie.
+ db.delete_unique('backend_movie', ['imdb_id'])
+
+ # Adding model 'Facet'
+ db.create_table('backend_facet', (
+ ('id', orm['backend.facet:id']),
+ ('movie', orm['backend.facet:movie']),
+ ('key', orm['backend.facet:key']),
+ ('value', orm['backend.facet:value']),
+ ('value_sort', orm['backend.facet:value_sort']),
+ ))
+ db.send_create_signal('backend', ['Facet'])
+
+ # Adding field 'Movie.metadata'
+ db.add_column('backend_movie', 'metadata', orm['backend.movie:metadata'])
+
+ # Adding field 'MovieSort.director_desc'
+ db.add_column('backend_moviesort', 'director_desc', orm['backend.moviesort:director_desc'])
+
+ # Adding field 'MovieSort.writer_desc'
+ db.add_column('backend_moviesort', 'writer_desc', orm['backend.moviesort:writer_desc'])
+
+ # Adding field 'MovieSort.country_desc'
+ db.add_column('backend_moviesort', 'country_desc', orm['backend.moviesort:country_desc'])
+
+ # Adding field 'MovieFind.location'
+ db.add_column('backend_moviefind', 'location', orm['backend.moviefind:location'])
+
+ # Adding field 'MovieFind.actor'
+ db.add_column('backend_moviefind', 'actor', orm['backend.moviefind:actor'])
+
+ # Adding field 'MovieSort.producer_desc'
+ db.add_column('backend_moviesort', 'producer_desc', orm['backend.moviesort:producer_desc'])
+
+ # Adding field 'MovieSort.cinematographer_desc'
+ db.add_column('backend_moviesort', 'cinematographer_desc', orm['backend.moviesort:cinematographer_desc'])
+
+ # Adding field 'MovieSort.title_desc'
+ db.add_column('backend_moviesort', 'title_desc', orm['backend.moviesort:title_desc'])
+
+ # Adding field 'MovieSort.language_desc'
+ db.add_column('backend_moviesort', 'language_desc', orm['backend.moviesort:language_desc'])
+
+ # Adding field 'MovieSort.year_desc'
+ db.add_column('backend_moviesort', 'year_desc', orm['backend.moviesort:year_desc'])
+
+ # Adding field 'MovieFind.character'
+ db.add_column('backend_moviefind', 'character', orm['backend.moviefind:character'])
+
+ # Adding field 'MovieSort.editor_desc'
+ db.add_column('backend_moviesort', 'editor_desc', orm['backend.moviesort:editor_desc'])
+
+ # Adding field 'MovieFind.keyword'
+ db.add_column('backend_moviefind', 'keyword', orm['backend.moviefind:keyword'])
+
+ # Deleting field 'Movie.extra'
+ db.delete_column('backend_movie', 'extra_id')
+
+ # Deleting field 'MovieFind.cast'
+ db.delete_column('backend_moviefind', 'cast')
+
+ # Dropping ManyToManyField 'Person.movies'
+ db.delete_table('backend_person_movies')
+
+ # Deleting field 'Movie.oxdb'
+ db.delete_column('backend_movie', 'oxdb_id')
+
+ # Deleting field 'MovieFind.keywords'
+ db.delete_column('backend_moviefind', 'keywords')
+
+ # Deleting field 'MovieFind.locations'
+ db.delete_column('backend_moviefind', 'locations')
+
+ # Deleting model 'movieoxdb'
+ db.delete_table('backend_movieoxdb')
+
+ # Deleting model 'review'
+ db.delete_table('backend_review')
+
+ # Deleting model 'archive'
+ db.delete_table('backend_archive')
+
+ # Deleting model 'alternativetitle'
+ db.delete_table('backend_alternativetitle')
+
+ # Deleting model 'moviecountry'
+ db.delete_table('backend_moviecountry')
+
+ # Deleting model 'trivia'
+ db.delete_table('backend_trivia')
+
+ # Deleting model 'connection'
+ db.delete_table('backend_connection')
+
+ # Deleting model 'cast'
+ db.delete_table('backend_cast')
+
+ # Deleting model 'frame'
+ db.delete_table('backend_frame')
+
+ # Deleting model 'movielanguage'
+ db.delete_table('backend_movielanguage')
+
+ # Deleting model 'file'
+ db.delete_table('backend_file')
+
+ # Deleting model 'movieimdb'
+ db.delete_table('backend_movieimdb')
+
+ # Deleting model 'country'
+ db.delete_table('backend_country')
+
+ # Deleting model 'archivefile'
+ db.delete_table('backend_archivefile')
+
+ # Deleting model 'movieextra'
+ db.delete_table('backend_movieextra')
+
+ # Deleting model 'language'
+ db.delete_table('backend_language')
+
+ # Deleting model 'keyword'
+ db.delete_table('backend_keyword')
+
+ # Deleting model 'genre'
+ db.delete_table('backend_genre')
+
+ # Changing field 'Movie.imdb'
+ # (to signature: fields.DictField(default={}, editable=False))
+ db.alter_column('backend_movie', 'imdb', orm['backend.movie:imdb'])
+
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Facet'
+ db.delete_table('backend_facet')
+
+ # Deleting field 'Movie.metadata'
+ db.delete_column('backend_movie', 'metadata')
+
+ # Deleting field 'MovieSort.director_desc'
+ db.delete_column('backend_moviesort', 'director_desc')
+
+ # Deleting field 'MovieSort.writer_desc'
+ db.delete_column('backend_moviesort', 'writer_desc')
+
+ # Deleting field 'MovieSort.country_desc'
+ db.delete_column('backend_moviesort', 'country_desc')
+
+ # Deleting field 'MovieFind.location'
+ db.delete_column('backend_moviefind', 'location')
+
+ # Deleting field 'MovieFind.actor'
+ db.delete_column('backend_moviefind', 'actor')
+
+ # Deleting field 'MovieSort.producer_desc'
+ db.delete_column('backend_moviesort', 'producer_desc')
+
+ # Deleting field 'MovieSort.cinematographer_desc'
+ db.delete_column('backend_moviesort', 'cinematographer_desc')
+
+ # Deleting field 'MovieSort.title_desc'
+ db.delete_column('backend_moviesort', 'title_desc')
+
+ # Deleting field 'MovieSort.language_desc'
+ db.delete_column('backend_moviesort', 'language_desc')
+
+ # Deleting field 'MovieSort.year_desc'
+ db.delete_column('backend_moviesort', 'year_desc')
+
+ # Deleting field 'MovieFind.character'
+ db.delete_column('backend_moviefind', 'character')
+
+ # Deleting field 'MovieSort.editor_desc'
+ db.delete_column('backend_moviesort', 'editor_desc')
+
+ # Deleting field 'MovieFind.keyword'
+ db.delete_column('backend_moviefind', 'keyword')
+
+ # Adding field 'Movie.extra'
+ db.add_column('backend_movie', 'extra', orm['backend.movie:extra'])
+
+ # Adding field 'MovieFind.cast'
+ db.add_column('backend_moviefind', 'cast', orm['backend.moviefind:cast'])
+
+ # Adding ManyToManyField 'Person.movies'
+ db.create_table('backend_person_movies', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('person', models.ForeignKey(orm.Person, null=False)),
+ ('movie', models.ForeignKey(orm.movie, null=False))
+ ))
+
+ # Adding field 'Movie.oxdb'
+ db.add_column('backend_movie', 'oxdb', orm['backend.movie:oxdb'])
+
+ # Adding field 'MovieFind.keywords'
+ db.add_column('backend_moviefind', 'keywords', orm['backend.moviefind:keywords'])
+
+ # Adding field 'MovieFind.locations'
+ db.add_column('backend_moviefind', 'locations', orm['backend.moviefind:locations'])
+
+ # Adding model 'movieoxdb'
+ db.create_table('backend_movieoxdb', (
+ ('series_title', orm['backend.moviefind:series_title']),
+ ('gross', orm['backend.moviefind:gross']),
+ ('votes', orm['backend.moviefind:votes']),
+ ('episode', orm['backend.moviefind:episode']),
+ ('created', orm['backend.moviefind:created']),
+ ('profit', orm['backend.moviefind:profit']),
+ ('season', orm['backend.moviefind:season']),
+ ('plot', orm['backend.moviefind:plot']),
+ ('rating', orm['backend.moviefind:rating']),
+ ('year', orm['backend.moviefind:year']),
+ ('budget', orm['backend.moviefind:budget']),
+ ('modified', orm['backend.moviefind:modified']),
+ ('episode_title', orm['backend.moviefind:episode_title']),
+ ('series_imdb', orm['backend.moviefind:series_imdb']),
+ ('tagline', orm['backend.moviefind:tagline']),
+ ('title', orm['backend.moviefind:title']),
+ ('runtime', orm['backend.moviefind:runtime']),
+ ('release_date', orm['backend.moviefind:release_date']),
+ ('id', orm['backend.moviefind:id']),
+ ('plot_outline', orm['backend.moviefind:plot_outline']),
+ ))
+ db.send_create_signal('backend', ['movieoxdb'])
+
+ # Adding model 'review'
+ db.create_table('backend_review', (
+ ('title', orm['backend.moviefind:title']),
+ ('url', orm['backend.moviefind:url']),
+ ('movie', orm['backend.moviefind:movie']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['review'])
+
+ # Adding model 'archive'
+ db.create_table('backend_archive', (
+ ('users', orm['backend.moviefind:users']),
+ ('created', orm['backend.moviefind:created']),
+ ('modified', orm['backend.moviefind:modified']),
+ ('id', orm['backend.moviefind:id']),
+ ('public', orm['backend.moviefind:public']),
+ ('name', orm['backend.moviefind:name']),
+ ))
+ db.send_create_signal('backend', ['archive'])
+
+ # Adding model 'alternativetitle'
+ db.create_table('backend_alternativetitle', (
+ ('title', orm['backend.moviefind:title']),
+ ('movie', orm['backend.moviefind:movie']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('type', orm['backend.moviefind:type']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['alternativetitle'])
+
+ # Adding model 'moviecountry'
+ db.create_table('backend_moviecountry', (
+ ('country', orm['backend.moviefind:country']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('movie', orm['backend.moviefind:movie']),
+ ('position', orm['backend.moviefind:position']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['moviecountry'])
+
+ # Adding model 'trivia'
+ db.create_table('backend_trivia', (
+ ('movie', orm['backend.moviefind:movie']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('position', orm['backend.moviefind:position']),
+ ('trivia', orm['backend.moviefind:trivia']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['trivia'])
+
+ # Adding model 'connection'
+ db.create_table('backend_connection', (
+ ('object', orm['backend.moviefind:object']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('relation', orm['backend.moviefind:relation']),
+ ('id', orm['backend.moviefind:id']),
+ ('subject', orm['backend.moviefind:subject']),
+ ))
+ db.send_create_signal('backend', ['connection'])
+
+ # Adding model 'cast'
+ db.create_table('backend_cast', (
+ ('character', orm['backend.moviefind:character']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('person', orm['backend.moviefind:person']),
+ ('role', orm['backend.moviefind:role']),
+ ('movie', orm['backend.moviefind:movie']),
+ ('position', orm['backend.moviefind:position']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['cast'])
+
+ # Adding model 'frame'
+ db.create_table('backend_frame', (
+ ('created', orm['backend.moviefind:created']),
+ ('frame', orm['backend.moviefind:frame']),
+ ('modified', orm['backend.moviefind:modified']),
+ ('file', orm['backend.moviefind:file']),
+ ('position', orm['backend.moviefind:position']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['frame'])
+
+ # Adding model 'movielanguage'
+ db.create_table('backend_movielanguage', (
+ ('language', orm['backend.moviefind:language']),
+ ('movie', orm['backend.moviefind:movie']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('position', orm['backend.moviefind:position']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['movielanguage'])
+
+ # Adding model 'file'
+ db.create_table('backend_file', (
+ ('available', orm['backend.moviefind:available']),
+ ('needs_data', orm['backend.moviefind:needs_data']),
+ ('pixel_aspect_ratio', orm['backend.moviefind:pixel_aspect_ratio']),
+ ('stream_high', orm['backend.moviefind:stream_high']),
+ ('pixel_format', orm['backend.moviefind:pixel_format']),
+ ('oshash', orm['backend.moviefind:oshash']),
+ ('stream_low', orm['backend.moviefind:stream_low']),
+ ('height', orm['backend.moviefind:height']),
+ ('channels', orm['backend.moviefind:channels']),
+ ('part', orm['backend.moviefind:part']),
+ ('display_aspect_ratio', orm['backend.moviefind:display_aspect_ratio']),
+ ('audio_codec', orm['backend.moviefind:audio_codec']),
+ ('duration', orm['backend.moviefind:duration']),
+ ('path', orm['backend.moviefind:path']),
+ ('samplerate', orm['backend.moviefind:samplerate']),
+ ('id', orm['backend.moviefind:id']),
+ ('md5', orm['backend.moviefind:md5']),
+ ('info', orm['backend.moviefind:info']),
+ ('sha1', orm['backend.moviefind:sha1']),
+ ('verified', orm['backend.moviefind:verified']),
+ ('created', orm['backend.moviefind:created']),
+ ('movie', orm['backend.moviefind:movie']),
+ ('framerate', orm['backend.moviefind:framerate']),
+ ('modified', orm['backend.moviefind:modified']),
+ ('pixels', orm['backend.moviefind:pixels']),
+ ('bpp', orm['backend.moviefind:bpp']),
+ ('stream_mid', orm['backend.moviefind:stream_mid']),
+ ('published', orm['backend.moviefind:published']),
+ ('video_codec', orm['backend.moviefind:video_codec']),
+ ('size', orm['backend.moviefind:size']),
+ ('type', orm['backend.moviefind:type']),
+ ('width', orm['backend.moviefind:width']),
+ ))
+ db.send_create_signal('backend', ['file'])
+
+ # Adding model 'movieimdb'
+ db.create_table('backend_movieimdb', (
+ ('rating', orm['backend.moviefind:rating']),
+ ('modified', orm['backend.moviefind:modified']),
+ ('year', orm['backend.moviefind:year']),
+ ('id', orm['backend.moviefind:id']),
+ ('gross', orm['backend.moviefind:gross']),
+ ('votes', orm['backend.moviefind:votes']),
+ ('title', orm['backend.moviefind:title']),
+ ('profit', orm['backend.moviefind:profit']),
+ ('tagline', orm['backend.moviefind:tagline']),
+ ('season', orm['backend.moviefind:season']),
+ ('plot', orm['backend.moviefind:plot']),
+ ('imdbId', orm['backend.moviefind:imdbId']),
+ ('series_imdb', orm['backend.moviefind:series_imdb']),
+ ('series_title', orm['backend.moviefind:series_title']),
+ ('episode', orm['backend.moviefind:episode']),
+ ('created', orm['backend.moviefind:created']),
+ ('release_date', orm['backend.moviefind:release_date']),
+ ('budget', orm['backend.moviefind:budget']),
+ ('episode_title', orm['backend.moviefind:episode_title']),
+ ('runtime', orm['backend.moviefind:runtime']),
+ ('plot_outline', orm['backend.moviefind:plot_outline']),
+ ))
+ db.send_create_signal('backend', ['movieimdb'])
+
+ # Adding model 'country'
+ db.create_table('backend_country', (
+ ('movies', orm['backend.moviefind:movies']),
+ ('id', orm['backend.moviefind:id']),
+ ('name', orm['backend.moviefind:name']),
+ ))
+ db.send_create_signal('backend', ['country'])
+
+ # Adding model 'archivefile'
+ db.create_table('backend_archivefile', (
+ ('created', orm['backend.moviefind:created']),
+ ('modified', orm['backend.moviefind:modified']),
+ ('archive', orm['backend.moviefind:archive']),
+ ('file', orm['backend.moviefind:file']),
+ ('path', orm['backend.moviefind:path']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['archivefile'])
+
+ # Adding model 'movieextra'
+ db.create_table('backend_movieextra', (
+ ('rights_level', orm['backend.moviefind:rights_level']),
+ ('description', orm['backend.moviefind:description']),
+ ('created', orm['backend.moviefind:created']),
+ ('title', orm['backend.moviefind:title']),
+ ('modified', orm['backend.moviefind:modified']),
+ ('contributor', orm['backend.moviefind:contributor']),
+ ('id', orm['backend.moviefind:id']),
+ ))
+ db.send_create_signal('backend', ['movieextra'])
+
+ # Adding model 'language'
+ db.create_table('backend_language', (
+ ('movies', orm['backend.moviefind:movies']),
+ ('id', orm['backend.moviefind:id']),
+ ('name', orm['backend.moviefind:name']),
+ ))
+ db.send_create_signal('backend', ['language'])
+
+ # Adding model 'keyword'
+ db.create_table('backend_keyword', (
+ ('movies', orm['backend.moviefind:movies']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('id', orm['backend.moviefind:id']),
+ ('name', orm['backend.moviefind:name']),
+ ))
+ db.send_create_signal('backend', ['keyword'])
+
+ # Adding model 'genre'
+ db.create_table('backend_genre', (
+ ('movies', orm['backend.moviefind:movies']),
+ ('manual', orm['backend.moviefind:manual']),
+ ('id', orm['backend.moviefind:id']),
+ ('name', orm['backend.moviefind:name']),
+ ))
+ db.send_create_signal('backend', ['genre'])
+
+ # Changing field 'Movie.imdb'
+ # (to signature: django.db.models.fields.related.OneToOneField(unique=True, null=True, to=orm['backend.MovieImdb']))
+ db.alter_column('backend_movie', 'imdb', orm['backend.movie:imdb'])
+
+ # Creating unique_together for [imdb] on movie.
+ db.create_unique('backend_movie', ['imdb_id'])
+
+
+
+ models = {
+ 'auth.group': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'backend.collection': {
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'movies': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['backend.Movie']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}),
+ 'subdomain': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '2048'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False'})
+ },
+ 'backend.facet': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'db_index': 'True'}),
+ 'movie': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'facets'", 'to': "orm['backend.Movie']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'value_sort': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'backend.layer': {
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'movie': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['backend.Movie']"}),
+ 'time_in': ('django.db.models.fields.FloatField', [], {'default': '-1'}),
+ 'time_out': ('django.db.models.fields.FloatField', [], {'default': '-1'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'backend.list': {
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'movies': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['backend.Movie']", 'symmetrical': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'backend.listitem': {
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['backend.List']"}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'movie': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['backend.Movie']"})
+ },
+ 'backend.location': {
+ 'area': ('django.db.models.fields.FloatField', [], {'default': '-1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'lat_center': ('django.db.models.fields.FloatField', [], {'default': '0'}),
+ 'lat_ne': ('django.db.models.fields.FloatField', [], {'default': '0'}),
+ 'lat_sw': ('django.db.models.fields.FloatField', [], {'default': '0'}),
+ 'lng_center': ('django.db.models.fields.FloatField', [], {'default': '0'}),
+ 'lng_ne': ('django.db.models.fields.FloatField', [], {'default': '0'}),
+ 'lng_sw': ('django.db.models.fields.FloatField', [], {'default': '0'}),
+ 'manual': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'movies': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['backend.Movie']", 'symmetrical': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
+ },
+ 'backend.movie': {
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'imdb': ('fields.DictField', [], {'default': '{}', 'editable': 'False'}),
+ 'json': ('fields.DictField', [], {'default': '{}', 'editable': 'False'}),
+ 'metadata': ('fields.DictField', [], {'default': '{}', 'editable': 'False'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'movieId': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128', 'blank': 'True'}),
+ 'oxdbId': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '42', 'blank': 'True'}),
+ 'poster_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'poster_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'published': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'scene_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'stream_high': ('django.db.models.fields.files.FileField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'}),
+ 'stream_low': ('django.db.models.fields.files.FileField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'}),
+ 'stream_mid': ('django.db.models.fields.files.FileField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'})
+ },
+ 'backend.moviefind': {
+ 'actor': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'all': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'character': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'cinematographer': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'country': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'director': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'editor': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'filename': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'genre': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'keyword': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'language': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'location': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'movie': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'find'", 'unique': 'True', 'primary_key': 'True', 'to': "orm['backend.Movie']"}),
+ 'producer': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'title': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'trivia': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'writer': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'year': ('django.db.models.fields.CharField', [], {'max_length': '4'})
+ },
+ 'backend.moviesort': {
+ 'aspectratio': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'bitrate': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'cast': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'cinematographer': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'cinematographer_desc': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'connections': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'country': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'country_desc': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'director': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'director_desc': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'duration': ('django.db.models.fields.FloatField', [], {'default': '-1', 'db_index': 'True'}),
+ 'editor': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'editor_desc': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'filename': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'files': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'genre': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'language': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'language_desc': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'movie': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'sort'", 'unique': 'True', 'primary_key': 'True', 'to': "orm['backend.Movie']"}),
+ 'movieId': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '128', 'blank': 'True'}),
+ 'pixels': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'producer': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'producer_desc': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'rating': ('django.db.models.fields.FloatField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'resolution': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'risk': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'runtime': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'scenes': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'summary': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'db_index': 'True'}),
+ 'title_desc': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'db_index': 'True'}),
+ 'trivia': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'votes': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'words': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'wpm': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'writer': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'writer_desc': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'year': ('django.db.models.fields.CharField', [], {'max_length': '4', 'db_index': 'True'}),
+ 'year_desc': ('django.db.models.fields.CharField', [], {'max_length': '4', 'db_index': 'True'})
+ },
+ 'backend.person': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'imdbId': ('django.db.models.fields.CharField', [], {'max_length': '7', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'name_sort': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'backend.reviewwhitelist': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'url': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['backend']
diff --git a/pandora/backend/models.py b/pandora/backend/models.py
index 46b950f7..dd9801fb 100644
--- a/pandora/backend/models.py
+++ b/pandora/backend/models.py
@@ -23,71 +23,6 @@ import load
import utils
import extract
-class MovieImdb(models.Model):
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
-
- imdbId = models.CharField(max_length=7, unique=True)
- title = models.CharField(max_length=1000)
- year = models.CharField(max_length=4)
- runtime = models.IntegerField(null=True, blank=True)
- release_date = models.DateField(null=True, blank=True)
- tagline = models.TextField(blank=True)
- plot = models.TextField(blank=True)
- plot_outline = models.TextField(blank=True)
-
- rating = models.FloatField(null=True, blank=True)
- votes = models.IntegerField(null=True, blank=True)
-
- budget = models.IntegerField(null=True, blank=True)
- gross = models.IntegerField(null=True, blank=True)
- profit = models.IntegerField(null=True, blank=True)
-
- series_imdb = models.CharField(max_length=7, default='')
- series_title = models.CharField(max_length=1000, blank=True, default='')
- episode_title = models.CharField(max_length=1000, blank=True, default='')
- season = models.IntegerField(default=-1)
- episode = models.IntegerField(default=-1)
-
- def __unicode__(self):
- return u"%s (%s)" % (self.title, self.imdbId)
-
-class MovieOxdb(models.Model):
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
-
- title = models.CharField(max_length=1000)
- year = models.CharField(max_length=4)
- runtime = models.IntegerField(null=True, blank=True)
- release_date = models.DateField(null=True, blank=True)
- tagline = models.TextField(blank=True)
- plot = models.TextField(blank=True)
- plot_outline = models.TextField(blank=True)
-
- rating = models.FloatField(null=True, blank=True)
- votes = models.IntegerField(null=True, blank=True)
-
- budget = models.IntegerField(null=True, blank=True)
- gross = models.IntegerField(null=True, blank=True)
- profit = models.IntegerField(null=True, blank=True)
-
- series_imdb = models.CharField(max_length=7, default='')
- series_title = models.TextField(blank=True, default='')
- episode_title = models.TextField(blank=True, default='')
- season = models.IntegerField(default=-1)
- episode = models.IntegerField(default=-1)
-
- def __unicode__(self):
- return u"%s (%s)" % (self.title, self.year)
-
-class MovieExtra(models.Model):
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
-
- title = models.CharField(max_length=1000)
- description = models.TextField(blank=True)
- contributor = models.CharField(max_length=1000)
- rights_level = models.IntegerField(default=-1)
def getMovie(info):
'''
@@ -96,44 +31,42 @@ def getMovie(info):
'''
if 'imdbId' in info and info['imdbId']:
try:
- movie = Movie.byImdbId(info['imdbId'])
+ movie = Movie.objects.get(movieId=info['imdbId'])
except Movie.DoesNotExist:
- movie = load.loadIMDb(info['imdbId'])
+ movie = Movie(movieId=info['imdbId'])
+ if 'title' in info and 'directors' in info:
+ movie.imdb = {
+ 'title': info['title'],
+ 'directors': info['directors'],
+ 'year': info.get('year', '')
+ }
+ #FIXME: this should be done async
+ #movie.save()
+ #tasks.updateImdb.delay(movie.movieId)
+ movie.updateImdb()
else:
- q = Movie.objects.filter(oxdb__title=info['title'])
+ q = Movie.objects.filter(find__title=info['title'])
if q.count() > 1:
- print "FIXME: check more than title here!!"
+ print "FIXME: check more than title here!!?"
movie = q[0]
else:
- print info
- movie = newMovie(info['title'], info['director'], '')
- updated = False
- for key in ('episode_title', 'season', 'year'):
- if key in info:
- setattr(movie.oxdb, key, info[key])
- updated = True
- if updated:
+ try:
+ movie = Movie.objects.get(movieId=info['oxdbId'])
+ except Movie.DoesNotExist:
+ movie = Movie()
+ movie.metadata = {
+ 'title': info['title'],
+ 'directors': info['directors'],
+ 'year': info.get('year', '')
+ }
+ movie.movieId = info['oxdbId']
+
+ for key in ('episode_title', 'series_title', 'season', 'episode'):
+ if key in info:
+ movie.metadata[key] = info[key]
movie.save()
return movie
-def newMovie(title, director, year):
- movie = Movie()
- oxdb = MovieOxdb()
- oxdb.save()
- movie.oxdb = oxdb
- movie.oxdb.title = title
- movie.oxdb.year = str(year)
- movie.oxdb.save()
- movie.oxdbId = "__init__%s" % random.randint(0, 100000)
- movie.save()
- movie.oxdbId = movie.oxid()
- print title, director, year
- print movie.oxdbId
- print movie.movieId
-
- movie.save()
- return movie
-
def movie_path(f, size):
name = "%s.%s" % (size, 'ogv')
url_hash = f.movieId
@@ -144,7 +77,6 @@ def poster_path(f):
url_hash = f.movieId
return os.path.join('poster', url_hash[:2], url_hash[2:4], url_hash[4:6], name)
-
class Movie(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
@@ -157,19 +89,13 @@ class Movie(models.Model):
movieId = models.CharField(max_length=128, unique=True, blank=True)
oxdbId = models.CharField(max_length=42, unique=True, blank=True)
- imdb = models.OneToOneField('MovieImdb', null=True, related_name='movie')
- oxdb = models.OneToOneField('MovieOxdb', null=True, related_name='movie')
- extra = models.OneToOneField('MovieExtra', null=True, related_name='movie')
-
objects = managers.MovieManager()
def get(self, key, default=None):
- if self.extra and getattr(self.extra, key):
- return getattr(self.extra, key)
- if self.oxdb and getattr(self.oxdb, key):
- return getattr(self.oxdb, key)
- if self.imdb:
- return getattr(self.imdb, key)
+ if self.metadata and key in self.metadata:
+ return self.metadata[key]
+ if self.imdb and key in self.imdb:
+ return self.imdb[key]
return default
def editable(self, user):
@@ -180,77 +106,30 @@ class Movie(models.Model):
#FIXME: how to map the keys to the right place to write them to?
for key in data:
if key != 'id':
- setattr(self.oxdb, key, data[key])
+ setattr(self.metadata, key, data[key])
self.oxdb.save()
self.save()
- def _manual(self, qs, f='manual'):
- if qs.filter(**{f:True}).count() > 0:
- return qs.exclude(**{f:False})
- return qs.exclude(**{f:True})
-
- def directors(self):
- qs = self.people.filter(cast__role='directors').order_by('cast__position')
- return self._manual(qs, 'cast__manual')
- def writers(self):
- qs = self.people.filter(cast__role='writers').order_by('cast__position')
- return self._manual(qs, 'cast__manual')
- def editors(self):
- qs = self.people.filter(cast__role='editors').order_by('cast__position')
- return self._manual(qs, 'cast__manual')
- def producers(self):
- qs = self.people.filter(cast__role='producers').order_by('cast__position')
- return self._manual(qs, 'cast__manual')
- def cinematographers(self):
- qs = self.people.filter(cast__role='cinematographers').order_by('cast__position')
- return self._manual(qs, 'cast__manual')
-
- def cast(self):
- cast = []
- qs = Cast.objects.filter(movie=self, role='cast').order_by('position')
- qs = self._manual(qs)
- for c in qs:
- cast.append((c.person.name, c.character))
- return tuple(cast)
-
- def alternative_titles(self):
- return self._manual(self.alternative_titles_all)
- def genres(self):
- return self._manual(self.genres_all)
- def keywords(self):
- return self._manual(self.keywords_all)
- def countries(self):
- return self._manual(self.countries_all, 'moviecountry__manual').order_by('moviecountry__position')
- def languages(self):
- return self._manual(self.languages_all, 'movielanguage__manual').order_by('movielanguage__position')
- def trivia(self):
- return self._manual(self.trivia_all)
- def locations(self):
- return self._manual(self.locations_all)
- def connections(self):
- return self._manual(self.connections_all)
-
- def connections_json(self):
- connections = {}
- for connection in self.connections():
- if connection.relation not in connections:
- connections[connection.relation] = []
- connections[connection.relation].append(connection.object.movieId)
- return connections
-
def reviews(self):
- q = self.reviews_all.filter(manual=True)
- if q.count() > 0:
- return q
- whitelist = ReviewWhitelist.objects.all()
- q = Q(id=-1)
- for w in whitelist:
- q = q | Q(url__contains=w.url)
- return self.reviews_all.filter(q).filter(manual=False)
+ reviews = self.get('reviews', [])
+ whitelist = [w for w in ReviewWhitelist.objects.all()]
+ _reviews = {}
+ for r in reviews:
+ for w in whitelist:
+ if w.url in r[0]:
+ _reviews[w.title] = r[0]
+ return _reviews
+ imdb = fields.DictField(default={}, editable=False)
+ metadata = fields.DictField(default={}, editable=False)
json = fields.DictField(default={}, editable=False)
+ def updateImdb(self):
+ if len(self.movieId) == 7:
+ self.imdb = ox.web.imdb.Imdb(self.movieId)
+ self.save()
+
#FIXME: use data.0xdb.org
'''
tpb_id = models.CharField(max_length=128, blank=True)
@@ -282,22 +161,14 @@ class Movie(models.Model):
return u'%s (%s)' % (self.get('title'), self.get('year'))
def save(self, *args, **kwargs):
- if not self.oxdb:
- oxdb = MovieOxdb()
- oxdb.save()
- self.oxdb = oxdb
- if self.imdb:
- mid = self.imdb.imdbId
- else:
- mid = self.oxdbId
- self.movieId = mid
-
- if self.id:
- self.json = self.get_json()
+ self.json = self.get_json()
+ if not self.oxdbId:
+ self.oxdbId = self.oxid()
super(Movie, self).save(*args, **kwargs)
self.updateFind()
self.updateSort()
+ self.updateFacets()
_public_fields = {
'movieId': 'id',
@@ -335,11 +206,7 @@ class Movie(models.Model):
value = getattr(self, key)
else:
value = self.get(key)
- if key in ('directors', 'writers', 'editors', 'cinematographers', 'producers',
- 'reviews', 'countries', 'languages',
- 'keywords', 'genres', 'trivia', 'alternative_titles'):
- movie[pub_key] = tuple([v.json() for v in value()])
- elif callable(value):
+ if callable(value):
movie[pub_key] = value()
else:
movie[pub_key] = value
@@ -359,26 +226,9 @@ class Movie(models.Model):
return fields
fields = classmethod(fields)
- #Class functions to get Movies by ID, right now movieId, imdbId and oxdbId
- #FIXME: this should go into a manager
- def byMovieId(self, movieId):
- if len(movieId) == 7:
- return self.byImdbId(movieId)
- return self.byOxdbId(movieId)
- byMovieId = classmethod(byMovieId)
-
- def byImdbId(self, imdbId):
- return self.objects.get(imdb__imdbId=imdbId)
- byImdbId = classmethod(byImdbId)
-
- def byOxdbId(self, oxdbId):
- return self.objects.get(oxdbId=oxdbId)
- byOxdbId = classmethod(byOxdbId)
-
def oxid(self):
- directors = ','.join([d.name for d in self.directors()])
- return utils.oxid(self.get('title', ''), directors, self.get('year', ''),
- self.get('series_title', ''), self.get('episode_title', ''),
+ return utils.oxid(self.get('title', ''), self.get('directors', []), str(self.get('year', '')),
+ self.get('series title', ''), self.get('episode title', ''),
self.get('season', ''), self.get('episode', ''))
def frame(self, position, width=128):
@@ -395,25 +245,28 @@ class Movie(models.Model):
f.title = self.get('title')
#FIXME: filter us/int title
#f.title += ' '.join([t.title for t in self.alternative_titles()])
- f.director = '|%s|'%'|'.join([i.name for i in self.directors()])
- f.country = '|%s|'%'|'.join([i.name for i in self.countries()])
+ f.director = '|%s|'%'|'.join(self.get('directors', []))
+ f.country = '|%s|'%'|'.join(self.get('countries', []))
f.year = self.get('year', '')
- f.language = '|%s|'%'|'.join([i.name for i in self.languages()])
- f.writer = '|%s|'%'|'.join([i.name for i in self.writers()])
- f.producer = '|%s|'%'|'.join([i.name for i in self.producers()])
- f.editor = '|%s|'%'|'.join([i.name for i in self.editors()])
- f.cinematographer = '|%s|'%'|'.join([i.name for i in self.cinematographers()])
- f.cast = ' '.join(['%s %s' % i for i in self.cast()])
- f.genre = '|%s|'%'|'.join([i.name for i in self.genres()])
- f.keywords = '|%s|'%'|'.join([i.name for i in self.keywords()])
+ for key in ('language', 'writer', 'producer', 'editor', 'cinematographer'):
+ setattr(f, key, '|%s|'%'|'.join(self.get('%ss'%key, [])))
+
+ f.actor = '|%s|'%'|'.join([i[0] for i in self.get('actor', [])])
+ f.character = '|%s|'%'|'.join([stripTagsl(i[1]) for i in self.get('actor', [])])
+
+ f.genre = '|%s|'%'|'.join(self.get('genres', []))
+ f.keyword = '|%s|'%'|'.join(self.get('keywords', []))
f.summary = self.get('plot', '') + self.get('plot_outline', '')
- f.trivia = ' '.join([i.trivia for i in self.trivia()])
- f.location = '|%s|'%'|'.join([i.name for i in self.locations()])
+ f.trivia = ' '.join(self.get('trivia', []))
+ f.location = '|%s|'%'|'.join(self.get('filming_locations', []))
+
+ f.dialog = 'fixme'
+
#FIXME: collate filenames
#f.filename = self.filename
- f.all = ' '.join(filter(None, [f.title, f.director, f.country, f.year, f.language,
+ f.all = ' '.join(filter(None, [f.title, f.director, f.country, str(f.year), f.language,
f.writer, f.producer, f.editor, f.cinematographer,
- f.cast, f.genre, f.keywords, f.summary, f.trivia,
+ f.actor, f.character, f.genre, f.keyword, f.summary, f.trivia,
f.location, f.filename]))
f.save()
@@ -423,14 +276,12 @@ class Movie(models.Model):
except MovieSort.DoesNotExist:
s = MovieSort(movie=self)
- def sortName(value):
- sort_value = '~'
- if value:
- sort_value = stripTags(value).split(',')
- sort_value = '; '.join([canonicalName(name.strip()) for name in sort_value])
- sort_value = sort_value.replace(u'\xc5k', 'A')
+ def sortNames(values):
+ sort_value = ''
+ if values:
+ sort_value = '; '.join([getPersonSort(name) for name in values])
if not sort_value:
- sort_value = '~'
+ sort_value = ''
return sort_value
#title
@@ -445,31 +296,22 @@ class Movie(models.Model):
s.title = title.strip()
- directors = ','.join([i.name for i in self.directors()])
- s.director = sortName(directors)
-
- s.country = ','.join([i.name for i in self.countries()])
+ s.country = ','.join(self.get('countries', []))
s.year = self.get('year', '')
- names = ','.join([i.name for i in self.producers()])
- s.producer = sortName(names)
- names = ','.join([i.name for i in self.writers()])
- s.writer = sortName(names)
- names = ','.join([i.name for i in self.editors()])
- s.editor = sortName(names)
- names = ','.join([i.name for i in self.cinematographers()])
- s.cinematographer = sortName(names)
+ for key in ('director', 'writer', 'producer', 'editor', 'cinematographer'):
+ setattr(s, key, sortNames(self.get('%ss'%key, [])))
- s.language = ','.join([i.name for i in self.languages()])
- s.country = ','.join([i.name for i in self.countries()])
+ s.language = ','.join(self.get('languages', []))
+ s.country = ','.join(self.get('countries', []))
s.runtime = self.get('runtime', 0)
- s.keywords = self.keywords().count()
- s.genre = self.genres().count()
- s.cast = len(self.cast())
+ s.keywords = len(self.get('keywords', []))
+ s.genre = len(self.get('genres', []))
+ s.cast = len(self.get('cast', []))
s.summary = len(self.get('plot', '').split())
- s.trivia = self.trivia().count()
- s.connections = self.connections().count()
+ s.trivia = len(self.get('trivia', []))
+ s.connections = len(self.get('connections', []))
s.movieId = self.movieId
s.rating = self.get('rating', -1)
s.votes = self.get('votes', -1)
@@ -488,8 +330,38 @@ class Movie(models.Model):
s.filename = 0 #FIXME
s.files = 0 #FIXME
s.size = 0 #FIXME
+
+ for key in ('title', 'director', 'writer', 'producer', 'editor', 'cinematographer', 'language', 'country'):
+ setattr(s, '%s_desc'%key, getattr(s, key))
+ if not getattr(s, key):
+ setattr(s, key, u'zzzzzzzzzzzzzzzzzzzzzzzzz')
+ if not s.year:
+ s.year_desc = '';
+ s.year = '9999';
s.save()
+ def updateFacets(self):
+ #"year", is extra is it?
+ #FIXME: what to do with Unkown Director, Year, Country etc.
+ def plural(term):
+ return {
+ 'country': 'countries',
+ }.get(term, term + 's')
+ for key in ("director", "country", "language", "genre"):
+ current_values = self.get(plural(key), [])
+ saved_values = [i.value for i in Facet.objects.filter(movie=self, key=key)]
+ removed_values = filter(lambda x: x not in current_values, saved_values)
+ if removed_values:
+ Facet.objects.filter(movie=self, key=key, value__in=removed_values).delete()
+ for value in current_values:
+ if value not in saved_values:
+ value_sort = value
+ if key in ('director', ):
+ value_sort = getPersonSort(value)
+ f = Facet(key=key, value=value, value_sort=value_sort)
+ f.movie = self
+ f.save()
+
class MovieFind(models.Model):
"""
used to search movies, all search values are in here
@@ -506,14 +378,15 @@ class MovieFind(models.Model):
producer = models.TextField(blank=True, default='')
editor = models.TextField(blank=True, default='')
cinematographer = models.TextField(blank=True, default='')
- cast = models.TextField(blank=True, default='')
+ actor = models.TextField(blank=True, default='')
+ character = models.TextField(blank=True, default='')
#person
genre = models.TextField(blank=True)
- keywords = models.TextField(blank=True)
+ keyword = models.TextField(blank=True)
summary = models.TextField(blank=True)
trivia = models.TextField(blank=True)
- locations = models.TextField(blank=True, default='')
+ location = models.TextField(blank=True, default='')
#only for own files or as admin?
filename = models.TextField(blank=True, default='')
@@ -575,6 +448,20 @@ class MovieSort(models.Model):
files = models.IntegerField(blank=True, db_index=True)
size = models.BigIntegerField(blank=True, db_index=True)
+ #required to move empty values to the bottom for both asc and desc sort
+ title_desc = models.CharField(max_length=1000, db_index=True)
+ director_desc = models.TextField(blank=True, db_index=True)
+ country_desc = models.TextField(blank=True, db_index=True)
+ year_desc = models.CharField(max_length=4, db_index=True)
+
+ producer_desc = models.TextField(blank=True, db_index=True)
+ writer_desc = models.TextField(blank=True, db_index=True)
+ editor_desc = models.TextField(blank=True, db_index=True)
+ cinematographer_desc = models.TextField(blank=True, db_index=True)
+
+ language_desc = models.TextField(blank=True, db_index=True)
+
+
_private_fields = ('id', 'movie')
#return available sort fields
#FIXME: should return mapping name -> verbose_name
@@ -588,27 +475,26 @@ class MovieSort(models.Model):
return tuple(fields)
fields = classmethod(fields)
-class AlternativeTitle(models.Model):
- movie = models.ForeignKey(Movie, related_name='alternative_titles_all')
- title = models.TextField()
- type = models.CharField(max_length=1000)
- manual = models.BooleanField(default=False)
+class Facet(models.Model):
+ movie = models.ForeignKey('Movie', related_name='facets')
+ key = models.CharField(max_length=200, db_index=True)
+ value = models.CharField(max_length=200)
+ value_sort = models.CharField(max_length=200)
- class Meta:
- ordering = ('title', )
-
- def __unicode__(self):
- return self.title
-
- def json(self):
- return (self.title, self.type)
+ def save(self, *args, **kwargs):
+ if not self.value_sort:
+ self.value_sort = self.value
+ super(Facet, self).save(*args, **kwargs)
+def getPersonSort(name):
+ person, created = Person.objects.get_or_create(name=name)
+ name_sort = person.name_sort.replace(u'\xc5k', 'A')
+ return name_sort
class Person(models.Model):
name = models.CharField(max_length=200)
imdbId = models.CharField(max_length=7, blank=True)
name_sort = models.CharField(max_length=200)
- movies = models.ManyToManyField(Movie, related_name='people', through='Cast')
class Meta:
ordering = ('name_sort', )
@@ -639,153 +525,6 @@ class Person(models.Model):
def json(self):
return self.name
-class Cast(models.Model):
- movie = models.ForeignKey(Movie, related_name='cast_relation')
- person = models.ForeignKey(Person)
- role = models.CharField(max_length=200)
- character = models.CharField(max_length=1000, blank=True)
- position = models.IntegerField()
- manual = models.BooleanField(default=False)
-
- class Meta:
- ordering = ('position', 'person__name_sort')
-
- def __unicode__(self):
- return "%s <> %s" % (self.person, self.movie)
-
- def link(self, movie, person, role, character, position, manual=False):
- q = self.objects.filter(movie=movie, person=person, role=role, character=character)
- if q.count() > 0:
- link = q[0]
- link.position = position
- link.manual = manual
- link.save()
- else:
- link = self()
- link.movie=movie
- link.person=person
- link.role=role
- link.character=character
- link.position = position
- link.manual = manual
- link.save()
- return link
- link = classmethod(link)
-
- def json(self):
- return (self.person.json(), self.character)
-
-class Country(models.Model):
- name = models.CharField(max_length=200, unique=True)
- movies = models.ManyToManyField(Movie, related_name='countries_all', through='MovieCountry')
-
- class Meta:
- #!! adding this to ordering, breaks:
- # models.Country.objects.values("name").annotate(movies=Count('movies'))
- #'moviecountry__position',
- ordering = ('name', )
-
- def __unicode__(self):
- return self.name
-
- def json(self):
- return self.name
-
-class MovieCountry(models.Model):
- movie = models.ForeignKey(Movie)
- country = models.ForeignKey(Country)
- position = models.IntegerField()
- manual = models.BooleanField(default=False)
-
- class Meta:
- ordering = ('position', 'country')
-
- def __unicode__(self):
- return "%s <> %s" % (self.country, self.movie)
-
- def link(self, movie, country, position):
- q = self.objects.filter(movie=movie, country=country)
- if q.count() > 0:
- link = q[0]
- link.position = position
- link.save()
- else:
- link = self()
- link.movie=movie
- link.country=country
- link.position=position
- link.save()
- return link
- link = classmethod(link)
-
-class Language(models.Model):
- name = models.CharField(max_length=200, unique=True)
- movies = models.ManyToManyField(Movie, related_name='languages_all', through="MovieLanguage")
-
- class Meta:
- ordering = ('name', )
-
- def __unicode__(self):
- return self.name
-
- def json(self):
- return self.name
-
-class MovieLanguage(models.Model):
- movie = models.ForeignKey(Movie)
- language = models.ForeignKey(Language)
- position = models.IntegerField()
- manual = models.BooleanField(default=False)
-
- class Meta:
- ordering = ('position', 'language')
-
- def __unicode__(self):
- return self.language.name
-
- def link(self, movie, language, position):
- q = self.objects.filter(movie=movie, language=language)
- if q.count() > 0:
- link = q[0]
- link.position = position
- link.save()
- else:
- link = self()
- link.movie=movie
- link.language=language
- link.position=position
- link.save()
- return link
- link = classmethod(link)
-
-class Keyword(models.Model):
- name = models.CharField(max_length=200, unique=True)
- manual = models.BooleanField(default=False)
- movies = models.ManyToManyField(Movie, related_name='keywords_all')
-
- class Meta:
- ordering = ('name', )
-
- def __unicode__(self):
- return self.name
-
- def json(self):
- return self.name
-
-class Genre(models.Model):
- name = models.CharField(max_length=200, unique=True)
- manual = models.BooleanField(default=False)
- movies = models.ManyToManyField(Movie, related_name='genres_all')
-
- class Meta:
- ordering = ('name', )
-
- def __unicode__(self):
- return self.name
-
- def json(self):
- return self.name
-
class Location(models.Model):
name = models.CharField(max_length=200, unique=True)
manual = models.BooleanField(default=False)
@@ -809,92 +548,6 @@ class Location(models.Model):
def json(self):
return self.name
-class Trivia(models.Model):
- trivia = models.TextField()
- manual = models.BooleanField(default=False)
- position = models.IntegerField()
- movie = models.ForeignKey(Movie, related_name='trivia_all')
-
- class Meta:
- ordering = ('position', )
-
- def __unicode__(self):
- return self.trivia
-
- def json(self):
- trivia = self.trivia
- trivia = ox.fixAmpersands(trivia)
- trivia = re.sub(' ', '', trivia)
- trivia = re.sub('(.*?)', '\\2', trivia)
- trivia = re.sub('(.*?)', '\\2', trivia)
- return trivia
-
-class Connection(models.Model):
- subject = models.ForeignKey(Movie, related_name='connections_all')
- relation = models.CharField(max_length=512)
- object = models.ForeignKey(Movie)
- manual = models.BooleanField(default=False)
-
- def get_or_create(model, subject, relation, object, reverse=True, manual=False):
- q = model.objects.filter(subject=subject, relation=relation, object=object)
- if q.count() > 0:
- o = q[0]
- else:
- o = model.objects.create(subject=subject, relation=relation, object=object, manual=manual)
- o.save()
- if reverse:
- _map = {
- 'Edited into': 'Edited from',
- 'Features': 'Featured in',
- 'Follows': 'Followed by',
- 'References': 'Referenced in',
- 'Remake of': 'Remade as',
- 'Spin off from': 'Spin off',
- 'Spoofs': 'Spoofed in',
- 'Version of': 'Version of',
- 'Alternate language version of': 'Alternate language version of',
- }
- if relation in _map.values():
- for k in _map:
- if _map[k] == relation:
- reverse_relation = k
- else:
- reverse_relation = _map[relation]
- o2 = model.get_or_create(object, reverse_relation, subject, reverse=False)
- return o
- get_or_create = classmethod(get_or_create)
-
- def __unicode__(self):
- return '%s %s %s' % (self.subject, self.relation, self.object)
-
-class Review(models.Model):
- movie = models.ForeignKey('Movie', related_name='reviews_all')
- title = models.CharField(blank=True, max_length=2048)
- url = models.CharField(blank=True, max_length=2048)
- manual = models.BooleanField(default=False)
-
- def __unicode__(self):
- return self.title
-
- def get_or_create(self, movie, url):
- q = self.objects.filter(movie=movie, url=url)
- if q.count() > 0:
- o = q[0]
- else:
- o = self.objects.create(movie=movie, url=url)
- o.save()
- return o
- get_or_create = classmethod(get_or_create)
-
- def name(self):
- for w in ReviewWhitelist.objects.all():
- if w.url in self.url:
- return w.name
- return self.title
-
- def json(self):
- return (self.name(), self.url)
-
class ReviewWhitelist(models.Model):
name = models.CharField(max_length=255, unique=True)
url = models.CharField(max_length=255, unique=True)
@@ -936,213 +589,6 @@ class ListItem(models.Model):
def __unicode__(self):
return u'%s in %s' % (unicode(self.movie), unicode(self.list))
-def stream_path(f, size):
- name = "%s.%s" % (size, 'ogv')
- url_hash = f.oshash
- return os.path.join(url_hash[:2], url_hash[2:4], url_hash[4:6], url_hash, name)
-
-def timeline_path(f):
- name = "timeline.png"
- url_hash = f.oshash
- return os.path.join(url_hash[:2], url_hash[2:4], url_hash[4:6], url_hash, name)
-
-def frame_path(f):
- position = ox.formatDuration(f.position*1000).replace(':', '.')
- name = "%s.%s" % (position, 'png')
- url_hash = f.file.oshash
- return os.path.join(url_hash[:2], url_hash[2:4], url_hash[4:6], url_hash, 'frames', name)
-
-FILE_TYPES = (
- (0, 'unknown'),
- (1, 'video'),
- (2, 'audio'),
- (3, 'subtitle'),
-)
-
-class File(models.Model):
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
- published = models.DateTimeField(default=datetime.now, editable=False)
-
- verified = models.BooleanField(default=False)
-
- oshash = models.CharField(blank=True, unique=True, max_length=16)
- sha1 = models.CharField(blank=True, null=True, unique=True, max_length=40)
- md5 = models.CharField(blank=True, null=True, unique=True, max_length=32)
-
- movie = models.ForeignKey(Movie, related_name="files", default=None, null=True)
-
- type = models.IntegerField(default=0, choices=FILE_TYPES)
- info = fields.DictField(default={})
-
- #FIXME: why do i need those in the db? could just have them in info
- path = models.CharField(blank=True, max_length=2048)
- size = models.BigIntegerField(default=-1)
- duration = models.FloatField(default=-1)
-
- video_codec = models.CharField(blank=True, max_length=256)
- pixel_format = models.CharField(blank=True, max_length=256)
- width = models.IntegerField(default=-1)
- height = models.IntegerField(default=-1)
- pixel_aspect_ratio = models.CharField(blank=True, max_length=256)
- display_aspect_ratio = models.CharField(blank=True, max_length=256)
- framerate = models.CharField(blank=True, max_length=256)
-
- audio_codec = models.CharField(blank=True, max_length=256)
- samplerate = models.IntegerField(default=-1)
- channels = models.IntegerField(default=-1)
-
- #computed values
- bpp = models.FloatField(default=-1)
- pixels = models.BigIntegerField(default=0)
-
- part = models.IntegerField(default=0)
-
- needs_data = models.BooleanField(default=True)
-
- #stream related fields
- available = models.BooleanField(default=False)
- stream_low = models.FileField(default=None, upload_to=lambda f, x: stream_path(f, 'low'))
- stream_mid = models.FileField(default=None, upload_to=lambda f, x: stream_path(f, 'mid'))
- stream_high = models.FileField(default=None, upload_to=lambda f, x: stream_path(f, 'high'))
-
- def timeline_base_url(self):
- return '%s/timeline' % os.path.dirname(self.stream_low.url)
-
- def save_chunk(self, chunk, name='video.ogv'):
- if not self.available:
- #FIXME: this should use stream_low or stream_high depending on configuration
- video = getattr(self, 'stream_%s'%settings.VIDEO_PROFILE)
- if not video:
- video.save(name, chunk)
- self.save()
- else:
- f = open(video.path, 'a')
- f.write(chunk.read())
- f.close()
- return True
- print "somehing failed, not sure what?", self.available
- return False
-
- objects = managers.FileManager()
-
- def __unicode__(self):
- return "%s (%s)" % (self.path, self.oshash)
-
- def update(self, data=None):
- """
- only add, do not overwrite keys in file
- """
- if data and not self.info:
- self.info = data
- _video_map = {
- 'codec': 'video_codec',
- }
- if 'video' in self.info and self.info['video']:
- for key in ('codec', 'pixel_format', 'width', 'height',
- 'pixel_aspect_ratio', 'display_aspect_ratio', 'framerate'):
- if key in self.info['video'][0]:
- setattr(self, _video_map.get(key, key), self.info['video'][0][key])
- _audio_map = {
- 'codec': 'audio_codec',
- }
- if 'audio' in self.info and self.info['audio']:
- for key in ('codec', 'samplerate', 'channels'):
- if key in self.info['audio'][0]:
- setattr(self, _audio_map.get(key, key), self.info['audio'][0][key])
-
- for key in ('duration', 'size', 'sha1', 'md5'):
- if key in self.info:
- setattr(self, key, self.info[key])
-
- #detect and assign type based on extension or detected video track
- if os.path.splitext(self.info['path'])[-1] in ('.rar', '.sub', '.idx'):
- self.type = 0
- elif 'video' in self.info:
- self.type = 1
- elif os.path.splitext(self.info['path'])[-1] in ('.mp3', '.oga'):
- self.type = 2
- elif os.path.splitext(self.info['path'])[-1] in ('.srt', ):
- self.type = 3
- #FIXME: this should be computed and not submitted path
- self.path = self.info['path']
- self.save()
-
- def findMovie(self):
- info = utils.parsePath(self.path)
- self.movie = getMovie(info)
- self.save()
-
- def extract_timeline(self):
- if self.stream_high:
- video = self.stream_high.path
- elif self.stream_mid:
- video = self.stream_mid.path
- elif self.stream_low:
- video = self.stream_low.path
- else:
- return False
- prefix = os.path.join(os.path.dirname(video), 'timeline')
- cmd = ['oxtimeline', '-i', video, '-o', prefix]
- p = subprocess.Popen(cmd)
- p.wait()
- return p.returncode == 0
-
- def extract_video(self):
- ogg = Firefogg()
- source = None
- profiles = []
- if self.stream_high:
- source = self.stream_high
- profiles = ['low', 'mid']
- elif self.stream_mid:
- source = self.stream_mid
- profiles = ['low', ]
- for profile in profiles:
- output = getattr(self, 'stream_%s'%profile)
- output.name = stream_path(self, profile)
- output.save()
- ogg.encode(source.path, output.path, settings.VIDEO_ENCODING[profile])
-
- def extract(self):
- #FIXME: do stuff, like create timeline or create smaller videos etc
- self.extract_video()
- self.extract_timeline()
- return
-
- def frame(self, position, width=128):
- videoFile = getattr(self, 'stream_%s'%settings.VIDEO_PROFILE).path
- frameFolder = os.path.join(os.path.dirname(videoFile), 'frames')
- if position<= self.duration:
- return extract.frame(videoFile, position, frameFolder, width)
- return None
-
- def editable(self, user):
- '''
- #FIXME: this should use a queryset!!!
- archives = []
- for a in self.archive_files.all():
- archives.append(a.archive)
- users = []
- for a in archives:
- users += a.users.all()
- return user in users
- '''
- return self.archive_files.filter(archive__users__id=user.id).count() > 0
-
-class Frame(models.Model):
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
- file = models.ForeignKey(File, related_name="frames")
- position = models.FloatField()
- frame = models.ImageField(default=None, null=True, upload_to=lambda f, x: frame_path(f))
-
- #FIXME: frame path should be renamed on save to match current position
-
- def __unicode__(self):
- return '%s at %s' % (self.file, self.position)
-
-
class Layer(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
@@ -1167,54 +613,6 @@ class Layer(models.Model):
return True
return False
-class Archive(models.Model):
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
- name = models.CharField(max_length=255, unique=True)
- public = models.BooleanField(default=False)
- users = models.ManyToManyField(User, related_name='archives')
-
- def __unicode__(self):
- return '%s' % (self.name)
-
- def editable(self, user):
- return self.users.filter(id=user.id).count() > 0
-
-
-class ArchiveFile(models.Model):
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
- archive = models.ForeignKey(Archive, related_name='files')
- file = models.ForeignKey(File, related_name='archive_files')
- path = models.CharField(blank=True, max_length=2048)
-
- objects = managers.ArchiveFileManager()
-
- def update(self, data):
- """
- only add, do not overwrite keys in file
- """
- self.file.update(data)
- self.path = data.get('path', '')
- self.save()
-
- def get_or_create(model, archive, oshash):
- try:
- f = model.objects.by_oshash(oshash=oshash)
- except model.DoesNotExist:
- file, created = File.objects.get_or_create(oshash)
- if created:
- file.save()
- f = model.objects.create(archive=archive, file=file)
- f.save()
- return f
- get_or_create = classmethod(get_or_create)
-
- def __unicode__(self):
- return '%s (%s)' % (self.path, unicode(self.archive))
-
- def editable(self, user):
- return self.archive.editable(user)
class Collection(models.Model):
created = models.DateTimeField(auto_now_add=True)
diff --git a/pandora/backend/tasks.py b/pandora/backend/tasks.py
index bc712900..cf2b9356 100644
--- a/pandora/backend/tasks.py
+++ b/pandora/backend/tasks.py
@@ -12,16 +12,17 @@ import models
def cronjob(**kwargs):
print "do some cleanup stuff once a day"
-@task(ignore_resulsts=True)
-def loadIMDb(imdbId):
- load.loadIMDb(imdbId)
+@task(ignore_resulsts=True, queue='default')
+def updateImdb(imdbId):
+ movie = models.Movie.objects.get(movieId=imdbId)
+ movie.updateImdb()
@task(ignore_resulsts=True)
def findMovie(fileId):
f = models.File.objects.get(pk=fileId)
f.findMovie()
-@task(ignore_resulsts=True, exchange="encoding")
+@task(ignore_resulsts=True, queue="encoding")
def extractData(fileId):
'''
update file stuff
@@ -30,7 +31,7 @@ def extractData(fileId):
f = models.File.objects.get(pk=fileId)
f.extract()
-@task(ignore_resulsts=True, exchange="encoding")
+@task(ignore_resulsts=True, queue="encoding")
def updateMovie(movidId):
'''
update movie
diff --git a/pandora/backend/utils.py b/pandora/backend/utils.py
index 84347f7d..59063a85 100644
--- a/pandora/backend/utils.py
+++ b/pandora/backend/utils.py
@@ -12,7 +12,8 @@ import ox
import ox.iso
from ox.normalize import normalizeName
-def oxid(title, director, year='', seriesTitle='', episodeTitle='', season=0, episode=0):
+def oxid(title, directors, year='', seriesTitle='', episodeTitle='', season=0, episode=0):
+ director = ', '.join(directors)
oxid_value = u"\n".join([title, director, year])
oxid = hashlib.sha1(oxid_value.encode('utf-8')).hexdigest()
if seriesTitle:
@@ -22,15 +23,19 @@ def oxid(title, director, year='', seriesTitle='', episodeTitle='', season=0, ep
oxid += hashlib.sha1(oxid_value.encode('utf-8')).hexdigest()[:20]
return u"0x" + oxid
-def oxdb_director(director):
+def oxdb_directors(director):
director = os.path.basename(os.path.dirname(director))
if director.endswith('_'):
director = "%s." % director[:-1]
- director = ", ".join([normalizeName(d) for d in director.split('; ')])
- director = director.replace('Series', '')
- director = director.replace('Unknown Director', '')
- director = director.replace('Various Directors', '')
- return director
+ directors = [normalizeName(d) for d in director.split('; ')]
+ def cleanup(director):
+ director = director.strip()
+ director = director.replace('Series', '')
+ director = director.replace('Unknown Director', '')
+ director = director.replace('Various Directors', '')
+ return director
+ directors = filter(None, [cleanup(d) for d in directors])
+ return directors
def oxdb_title(_title, searchTitle = False):
'''
@@ -117,11 +122,15 @@ def parsePath(path):
search_title = oxdb_title(path, True)
r = {}
r['title'] = oxdb_title(path)
- r['director'] = oxdb_director(path)
+ r['directors'] = oxdb_directors(path)
r['episode_title'] = oxdb_episode_title(path)
r['season'], r['episode'] = oxdb_season_episode(path)
- r['series'] = oxdb_series_title(path)
+ r['series_title'] = oxdb_series_title(path)
r['part'] = oxdb_part(path)
- r['imdbId'] = ox.web.imdb.guess(search_title, r['director'], timeout=-1)
+ r['imdbId'] = ox.web.imdb.guess(search_title, ', '.join(r['directors']), timeout=-1)
+ r['oxdbId'] = oxid(r['title'], r['directors'],
+ seriesTitle=r['series_title'],
+ episodeTitle=r['episode_title'],
+ season=r['season'], episode=r['episode'])
return r
diff --git a/pandora/backend/views.py b/pandora/backend/views.py
index 539574d5..f9aabfdb 100644
--- a/pandora/backend/views.py
+++ b/pandora/backend/views.py
@@ -33,8 +33,10 @@ import tasks
from oxuser.models import getUserJSON
from oxuser.views import api_login, api_logout, api_register, api_contact, api_recover, api_preferences
+from archive.views import api_update, api_addArchive, api_editArchive, api_removeArchive
+
+from archive.models import File
-
def api(request):
if request.META['REQUEST_METHOD'] == "OPTIONS":
response = HttpResponse('')
@@ -78,10 +80,18 @@ def api_error(request):
def _order_query(qs, sort, prefix='sort__'):
order_by = []
+ if len(sort) == 1:
+ if sort[0]['key'] in ('title', 'director'):
+ sort.append({'operator': '-', 'key': 'year'})
+ if sort[0]['key'] in ('year', ):
+ sort.append({'operator': '+', 'key': 'director'})
for e in sort:
operator = e['operator']
if operator != '-': operator = ''
key = {'id': 'movieId'}.get(e['key'], e['key'])
+ #FIXME: this should be a property of models.MovieSort!!!
+ if operator=='-' and key in ('title', 'director', 'writer', 'producer', 'editor', 'cinematographer', 'language', 'country', 'year'):
+ key = '%s_desc' % key
order = '%s%s%s' % (operator, prefix, key)
order_by.append(order)
if order_by:
@@ -180,29 +190,23 @@ Positions
query['sort'] = [{'key': 'name', 'operator':'+'}]
#FIXME: also filter lists here
response['data']['items'] = []
- name = 'name'
items = 'movies'
movie_qs = query['qs']
- if query['group'] == "director":
- qs = models.Cast.objects.filter(role='directors').filter(movie__id__in=movie_qs).values('person__name').annotate(movies=Count('person__id')).order_by()
- name = 'person__name'
- elif query['group'] == "country":
- qs = models.Country.objects.filter(movies__id__in=movie_qs).values('name').annotate(movies=Count('id'))
- elif query['group'] == "genre":
- qs = models.Genre.objects.filter(movies__id__in=movie_qs).values('name').annotate(movies=Count('id'))
- elif query['group'] == "language":
- qs = models.Language.objects.filter(movies__id__in=movie_qs).values('name').annotate(movies=Count('id'))
- elif query['group'] == "year":
+ if query['group'] == "year":
qs = models.MovieSort.objects.filter(movie__id__in=movie_qs).values('year').annotate(movies=Count('year'))
name='year'
+ name_sort='year'
+ else:
+ qs = models.Facet.objects.filter(key=query['group']).filter(movie__id__in=movie_qs)
+ qs = qs.values('value').annotate(movies=Count('id')).order_by()
+ name = 'value'
+ name_sort = 'value_sort'
+
#replace normalized items/name sort with actual db value
for i in range(0, len(query['sort'])):
if query['sort'][i]['key'] == 'name':
- if query['group'] in ('director', ):
- query['sort'][i]['key'] = 'person__name_sort'
- else:
- query['sort'][i]['key'] = name
- if query['sort'][i]['key'] == 'items':
+ query['sort'][i]['key'] = name_sort
+ elif query['sort'][i]['key'] == 'items':
query['sort'][i]['key'] = items
qs = _order_query(qs, query['sort'], prefix='')
if 'ids' in query:
@@ -235,26 +239,25 @@ Positions
for p in _p:
r[p] = m.get(p, '')
return r
-
qs = qs[query['range'][0]:query['range'][1]]
response['data']['items'] = [only_p(m['json']) for m in qs.values('json')]
else: # otherwise stats
#movies = models.Movie.objects.filter(available=True)
movies = query['qs']
- files = models.File.objects.all().filter(movie__in=movies)
+ files = File.objects.all().filter(movie__in=movies)
r = files.aggregate(
- Count('duration'),
- Count('pixels'),
- Count('size')
+ Sum('duration'),
+ Sum('pixels'),
+ Sum('size')
)
- response['data']['duration'] = r['duration__count']
+ response['data']['duration'] = r['duration__sum']
response['data']['files'] = files.count()
response['data']['items'] = movies.count()
- response['data']['pixels'] = r['pixels__count']
+ response['data']['pixels'] = r['pixels__sum']
response['data']['runtime'] = movies.aggregate(Sum('sort__runtime'))['sort__runtime__sum']
if response['data']['runtime'] == None:
response['data']['runtime'] = 1337
- response['data']['size'] = r['size__count']
+ response['data']['size'] = r['size__sum']
return render_to_json_response(response)
def api_getItem(request):
@@ -401,106 +404,6 @@ def api_removeList(request):
response = json_response(status=501, text='not implemented')
return render_to_json_response(response)
-@login_required_json
-def api_addArchive(request):
- '''
- ARCHIVE API NEEDS CLEANUP
- param data
- {name: string}
- return {'status': {'code': int, 'text': string},
- 'data': {}}
- '''
- data = json.loads(request.POST['data'])
- try:
- archive = models.Archive.objects.get(name=data['name'])
- response = {'status': {'code': 401, 'text': 'archive with this name exists'}}
- except models.Archive.DoesNotExist:
- archive = models.Archive(name=data['name'])
- archive.save()
- archive.users.add(request.user)
- response = json_response({})
- response['status']['text'] = 'archive created'
- return render_to_json_response(response)
-
-@login_required_json
-def api_editArchive(request):
- '''
- ARCHIVE API NEEDS CLEANUP
- param data
- {id: string, key: value,..}
- return {'status': {'code': int, 'text': string},
- 'data': {}}
- '''
- data = json.loads(request.POST['data'])
- item = get_object_or_404_json(models.Archive, name=data['name'])
- if item.editable(request.user):
- response = json_response(status=501, text='not implemented')
- item.edit(data)
- else:
- response = json_response(status=403, text='permission denied')
- return render_to_json_response(response)
-
-@login_required_json
-def api_removeArchive(request):
- '''
- ARCHIVE API NEEDS CLEANUP
- param data
- string id
-
- return {'status': {'code': int, 'text': string}}
- '''
- response = json_response({})
- itemId = json.loads(request.POST['data'])
- item = get_object_or_404_json(models.Archive, movieId=itemId)
- if item.editable(request.user):
- response = json_response(status=501, text='not implemented')
- else:
- response = json_response(status=403, text='permission denied')
- return render_to_json_response(response)
-
-
-
-#@login_required_json
-def api_update(request):
- '''
- param data
- {archive: string, files: json}
- return {'status': {'code': int, 'text': string},
- 'data': {info: object, rename: object}}
- '''
- data = json.loads(request.POST['data'])
- archive = data['archive']
- files = data['files']
- archive = get_object_or_404_json(models.Archive, name=archive)
- if archive.editable(request.user):
- needs_data = []
- rename = {}
- for oshash in files:
- data = files[oshash]
- q = models.ArchiveFile.objects.filter(archive=archive, file__oshash=oshash)
- if q.count() == 0:
- #print "adding file", oshash, data['path']
- f = models.ArchiveFile.get_or_create(archive, oshash)
- f.update(data)
- if not f.file.movie:
- task.findMovie(f.file.id)
- #FIXME: only add if it was not in File
- else:
- f = q[0]
- if data['path'] != f.path:
- f.path = data['path']
- f.save()
- if f.file.needs_data:
- needs_data.append(oshash)
- if f.path != f.file.path:
- rename[oshash] = f.file.path
- #print "processed files for", archive.name
- #remove all files not in files.keys() from ArchiveFile
- response = json_response({'info': needs_data, 'rename': rename})
- else:
- response = json_response(status=403, text='permission denied')
- return render_to_json_response(response)
-
def api_encodingSettings(request):
'''
returns Firefogg encoding settings as specified by site
diff --git a/pandora/settings.py b/pandora/settings.py
index d08766eb..b034bd98 100644
--- a/pandora/settings.py
+++ b/pandora/settings.py
@@ -112,6 +112,7 @@ INSTALLED_APPS = (
'app',
'backend',
+ 'archive',
'oxuser',
'torrent',
)