From 88641780db735c4283b21a5ee32e0dbbbd47f739 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Mon, 8 Jun 2009 18:08:59 +0200 Subject: [PATCH] foo --- __init__.py | 0 backend/__init__.py | 0 backend/load.py | 143 ++++++++++ backend/models.py | 594 ++++++++++++++++++++++++++++++++++++++++++ backend/urls.py | 39 +++ backend/utils.py | 24 ++ backend/views.py | 88 +++++++ fixtures/reviews.json | 59 +++++ manage.py | 11 + settings.py | 80 ++++++ urls.py | 17 ++ 11 files changed, 1055 insertions(+) create mode 100644 __init__.py create mode 100644 backend/__init__.py create mode 100644 backend/load.py create mode 100644 backend/models.py create mode 100644 backend/urls.py create mode 100644 backend/utils.py create mode 100644 backend/views.py create mode 100644 fixtures/reviews.json create mode 100644 manage.py create mode 100644 settings.py create mode 100644 urls.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/load.py b/backend/load.py new file mode 100644 index 00000000..0e278e64 --- /dev/null +++ b/backend/load.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +import os.path +from django.db import models +from django.contrib.auth.models import User + +import oxweb.imdb +from oxlib import stripTags, findRe + +import models + +def debug(*msgs): + for m in msgs: + print m, + print + +'''Import data from imdb into database, + param: impdb id + return: Movie Object, None if failed +''' + +def loadIMDb(imdbId): + if len(imdbId) != 7: + debug("IMDb ID not valid") + return None + try: + movie = models.Movie.byImdbId(imdbId) + except models.Movie.DoesNotExist: + movie = models.Movie() + movie.imdbId = imdbId + + info = oxweb.imdb.getMovieInfo(imdbId) + for key in ('title', + 'tagline', + 'year', + 'release_date', + 'rating', + 'votes', + 'series_imdb' + 'season', + 'episode'): + if key in info: + setattr(movie, key, info[key]) + debug(key, info[key]) + _info_map = { + 'episode title': 'episode_title', + 'series title': 'series_title', + } + for key in _info_map.keys(): + if key in info: + setattr(movie, _info_map.get(key, key), info[key]) + + movie.plot = oxweb.imdb.getMoviePlot(imdbId) + debug("plot", movie.plot) + + movie.runtime = oxweb.imdb.getMovieRuntimeSeconds(imdbId) + business = oxweb.imdb.getMovieBusinessSum(imdbId) + for key in ('gross', 'profit', 'budget'): + setattr(movie, key, business[key]) + + movie.save() + + #FIXME: related tables should be cleaned to not accumulate cruft + #Country + models.MovieCountry.objects.filter(movie=movie).delete() + position = 0 + for i in info['country']: + debug("add country", i) + country = models.Country.get_or_create(i) + models.MovieCountry.link(movie, country, position) + position += 1 + + #Language + models.MovieLanguage.objects.filter(movie=movie).delete() + position = 0 + for i in info['language']: + debug("add language", i) + language = models.Language.get_or_create(i) + models.MovieLanguage.link(movie, language, position) + position += 1 + + #Location + movie.locations.all().delete() + locations = oxweb.imdb.getMovieLocations(imdbId) + for i in locations: + debug("add location", i) + location = models.Location.get_or_create(i) + location.movies.add(movie) + + #Genre + movie.genres.all().delete() + for i in info['genre']: + debug("add genre", i) + genre = models.Genre.get_or_create(i) + genre.movies.add(movie) + + #Keyword + movie.keywords.all().delete() + keywords = oxweb.imdb.getMovieKeywords(imdbId) + for g in keywords: + debug("add keyword", g) + keyword = models.Keyword.get_or_create(g) + keyword.movies.add(movie) + + movie.trivia.all().delete() + position = 0 + trivia = oxweb.imdb.getMovieTrivia(imdbId) + for i in trivia: + debug("add trivia", g) + t = models.Trivia() + t.movie = movie + t.trivia = i + t.position = position + t.save() + position += 1 + + position = 0 + credits = oxweb.imdb.getMovieCredits(imdbId) + for role in credits: + for p in credits[role]: + name = stripTags(p[0]) + imdb_id = findRe(p[0], 'nm(\d{7})') + debug("add cast", name) + #FIXME: we could save character information here + character = stripTags(p[1]) + person = models.Person.get_or_create(name, imdb_id) + models.Cast.link(movie, person, role, character, position) + position += 1 + + #FIXME: connections + #m.addMovieConnections(IMDb['connections']) + + reviews = oxweb.imdb.getMovieExternalReviews(imdbId) + for r in reviews: + debug("add review", r) + review = models.Review.get_or_create(movie, r) + review.title = reviews[r] + review.save() + + movie.oxdbId = movie.oxid() + movie.save() + return movie + diff --git a/backend/models.py b/backend/models.py new file mode 100644 index 00000000..1c585c5d --- /dev/null +++ b/backend/models.py @@ -0,0 +1,594 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +import os.path +from django.db import models +from django.db.models import Q +from django.contrib.auth.models import User + +import oxlib + +import utils + + +class Movie(models.Model): + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + accessed = models.DateTimeField(null=True, blank=True) + + movieId = models.CharField(max_length=128, blank=True) + imdbId = models.CharField(max_length=7, blank=True) + oxdbId = models.CharField(max_length=42, blank=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.IntegerField(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) + + #FIXME: how to deal with files now? + #files = + files_modified = models.DateTimeField(auto_now=True) + filename = models.TextField(blank=True) + extracted = models.IntegerField(null=True, blank=True) + + #length = models.IntegerField(null=True, blank=True) + duration = models.FloatField(null=True, blank=True) + + #FIXME: should this be a done via a manager for person? + def directors(self): + return self.people.filter(cast__role='directors').order_by('cast__position') + def writers(self): + return self.people.filter(cast__role='writers').order_by('cast__position') + def editors(self): + return self.people.filter(cast__role='editors').order_by('cast__position') + def producers(self): + return self.people.filter(cast__role='producers').order_by('cast__position') + def cinematographers(self): + return self.people.filter(cast__role='cinematographers').order_by('cast__position') + + #FIXME: include role and character + def cast(self): + cast = [] + for c in Cast.objects.filter(movie=self, role=cast).order_by('position'): + cast.append((c.person.name, c.character)) + return tuple(cast) + #return self.person.filter(cast__role='cast').order_by('cast__position') + + def filtered_reviews(self): + whitelist = ReviewWhitelist.objects.all() + q = Q(id=-1) + for w in whitelist: + q = q | Q(url__contains=w.url) + return self.reviews.filter(q) + + risk = models.IntegerField(null=True, blank=True) + rights_level = models.IntegerField(null=True, blank=True) + rights_text = models.TextField(blank=True) + + #title_english = models.TextField(blank=True) + #FIXME: join AltTitle + + #FIXME: use mapping + tpb_id = models.CharField(max_length=128, blank=True) + kg_id = models.CharField(max_length=128, blank=True) + open_subtitle_id = models.IntegerField(null=True, blank=True) + wikipedia_url = models.TextField(blank=True) + + #FIXME: join Location + #locations = models.TextField(blank=True) + + #Series information + 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) + + #what of this is still required? + still_pos = models.IntegerField(null=True, blank=True) + poster = models.TextField(blank=True) + posters_disabled = models.TextField(blank=True) + posters_available = models.TextField(blank=True) + poster_height = models.IntegerField(null=True, blank=True) + poster_width = models.IntegerField(null=True, blank=True) + + scene_height = models.IntegerField(null=True, blank=True) + + def __unicode__(self): + return "%s (%s)" % (self.title, self.year) + + def save(self, *args, **kwargs): + if self.imdbId: + mid = self.imdbId + else: + mid = self.oxdbId + self.movieId = mid + #FIXME: update sort and find values here + + super(Movie, self).save(*args, **kwargs) + + _public_fields = { + 'movieId': 'id', + 'title': 'title', + 'year': 'year', + + 'runtime': 'runtime', + 'release_date': 'release_date', + + 'countries': 'country', + 'directors': 'director', + 'genres': 'genres', + 'keywords': 'keywords', + 'cast': 'cast', + 'series_title': 'series_title', + 'episode_title': 'episode_title', + 'season': 'season', + 'episode': 'episode', + 'filtered_reviews': 'reviews', + } + def json(self, fields=None): + movie = {} + for key in self._public_fields: + pub_key = self._public_fields.get(key, key) + if not fields or pub_key in fields: + value = getattr(self, key) + if key in ('directors', 'writers', 'filtered_reviews'): + movie[pub_key] = tuple([v.json() for v in value()]) + elif key in ('countries', 'keywords', 'genres'): + movie[pub_key] = tuple([v.json() for v in value.all()]) + else: + movie[pub_key] = value + return movie + + #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): + q = self.objects.filter(imdbId=imdbId) + if q.count() == 0: + raise self.DoesNotExist("%s matching imdb id %s does not exist." % (self._meta.object_name, imdbId)) + return q[0] + byImdbId = classmethod(byImdbId) + + def byOxdbId(self, oxdbId): + q = self.objects.filter(oxdbId=oxdbId) + if q.count() == 0: + raise self.DoesNotExist("%s matching oxdb id %s does not exist." % (self._meta.object_name, oxdbId)) + return q[0] + byOxdbId = classmethod(byOxdbId) + + def oxid(self): + directors = ",".join([d.name for d in self.directors()]) + return utils.oxid(self.title, directors, self.year, self.series_title, self.episode_title, self.season, self.episode) + +''' + used to search movies, all search values are in here +''' +class MovieFind(models.Model): + movie = models.ForeignKey('Movie') + + title = models.CharField(max_length=1000) + director = models.TextField(blank=True) + country = models.TextField(blank=True) + year = models.CharField(max_length=4) + language = models.TextField(blank=True) + writer = models.TextField(blank=True) + producer = models.TextField(blank=True) + editor = models.TextField(blank=True) + cinematographers = models.TextField(blank=True) + cast = models.IntegerField(blank=True) + #person + + genre = models.TextField(blank=True) + keywords = models.TextField(blank=True) + summary = models.TextField(blank=True) + trivia = models.TextField(blank=True) + locations = models.TextField(blank=True) + connections = models.TextField(blank=True) + + #only for own files or as admin? + filename = models.TextField(blank=True) + + _private_fields = ('id', 'movie') + _public_names = { + 'movieId': 'id' + } + def options(self): + options = [] + for f in self._meta.fields: + if f.name not in self._private_fields: + name = f.name + name = self._public_names.get(name, name) + options.append((name, 'Find: %s' % name.capitalize())) + return tuple(options) + options = classmethod(options) + +''' + used to sort movies, all sort values are in here +''' +class MovieSort(models.Model): + movie = models.ForeignKey('Movie') + + title = models.CharField(max_length=1000) + director = models.TextField(blank=True) + country = models.TextField(blank=True) + year = models.CharField(max_length=4) + + producer = models.TextField(blank=True) + writer = models.TextField(blank=True) + editor = models.TextField(blank=True) + cinematographers = models.TextField(blank=True) + + language = models.TextField(blank=True) + runtime = models.IntegerField(blank=True) + + keywords = models.IntegerField(blank=True) + genre = models.TextField(blank=True) + cast = models.IntegerField(blank=True) + summary = models.IntegerField(blank=True) + trivia = models.IntegerField(blank=True) + connections = models.IntegerField(blank=True) + + scenes = models.IntegerField(blank=True) + words = models.IntegerField(null=True, blank=True) + wpm = models.IntegerField(null=True, blank=True) + risk = models.IntegerField(null=True, blank=True) + + movieId = models.CharField(max_length=128, blank=True) + + duration = models.FloatField(default=-1) + resolution = models.IntegerField(blank=True) + aspectratio = models.IntegerField(blank=True) + bitrate = models.IntegerField(blank=True) + pixels = models.IntegerField(blank=True) + filename = models.IntegerField(blank=True) + files = models.IntegerField(blank=True) + size = models.IntegerField(blank=True) + + _private_fields = ('id', 'movie') + _public_names = { + 'movieId': 'id' + } + def options(self): + options = [] + for f in self._meta.fields: + if f.name not in self._private_fields: + name = f.name + name = self._public_names.get(name, name) + options.append((name, 'Sort: %s' % name.capitalize())) + return tuple(options) + options = classmethod(options) + +class AlternativeTitle(models.Model): + movie = models.ForeignKey(Movie, related_name='alternative_titles') + type = models.CharField(max_length=128) + title = models.TextField() + + class Meta: + ordering = ('title', ) + + def __unicode__(self): + return self.title + +def get_or_create(model, name): + try: + o = model.objects.get(name=name) + except model.DoesNotExist: + o = model.objects.create(name=name) + o.save() + return o + +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', ) + + def __unicode__(self): + return self.name + + def save(self, *args, **kwargs): + if not self.name_sort: + self.name_sort = oxlib.normalize.canonicalName(self.name) + super(Person, self).save(*args, **kwargs) + + def get_or_create(model, name, imdbId=None): + if imdbId: + q = model.objects.filter(name=name, imdbId=imdbId) + else: + q = model.objects.get(name=name) + if q.count() > 0: + o = q[0] + else: + o = model.objects.create(name=name) + if imdbId: + o.imdbId = imdbId + o.save() + return o + get_or_create = classmethod(get_or_create) + + def json(self): + return self.name + +class Cast(models.Model): + movie = models.ForeignKey(Movie) + person = models.ForeignKey(Person) + role = models.CharField(max_length=200) + character = models.CharField(max_length=200, blank=True) + position = models.IntegerField() + + 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): + q = self.objects.filter(movie=movie, person=person, role=role, character=character) + if q.count() > 0: + link = q[0] + link.position = position + link.save() + else: + link = self() + link.movie=movie + link.person=person + link.role=role + link.character=character + link.position = position + 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) + movies = models.ManyToManyField(Movie, related_name='countries', through='MovieCountry') + + class Meta: + ordering = ('moviecountry__position', 'name', ) + + def __unicode__(self): + return self.name + + get_or_create = classmethod(get_or_create) + + def json(self): + return self.name + +class MovieCountry(models.Model): + movie = models.ForeignKey(Movie) + country = models.ForeignKey(Country) + position = models.IntegerField() + + 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) + movies = models.ManyToManyField(Movie, related_name='language', through="MovieLanguage") + + class Meta: + ordering = ('name', ) + + def __unicode__(self): + return self.name + get_or_create = classmethod(get_or_create) + + def json(self): + return self.name + +class MovieLanguage(models.Model): + movie = models.ForeignKey(Movie) + language = models.ForeignKey(Language) + position = models.IntegerField() + + 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) + movies = models.ManyToManyField(Movie, related_name='keywords') + + class Meta: + ordering = ('name', ) + + def __unicode__(self): + return self.name + + get_or_create = classmethod(get_or_create) + + def json(self): + return self.name + + +class Genre(models.Model): + name = models.CharField(max_length=200) + movies = models.ManyToManyField(Movie, related_name='genres') + + class Meta: + ordering = ('name', ) + + def __unicode__(self): + return self.name + + get_or_create = classmethod(get_or_create) + + def json(self): + return self.name + +class Location(models.Model): + name = models.CharField(max_length=200) + movies = models.ManyToManyField(Movie, related_name='locations') + #fixme: geo data + + class Meta: + ordering = ('name', ) + + def __unicode__(self): + return self.name + + get_or_create = classmethod(get_or_create) + + def json(self): + return self.name + +class Trivia(models.Model): + trivia = models.TextField() + movie = models.ForeignKey(Movie, related_name='trivia') + position = models.IntegerField() + + class Meta: + ordering = ('position', ) + + def __unicode__(self): + return self.trivia + + def json(self): + return self.trivia + +class MovieFile(models.Model): + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + + oshash = models.CharField(blank=True, max_length=16) + sha1hash = models.CharField(blank=True, max_length=40) + md5sum = models.CharField(blank=True, max_length=32) + + movie = models.ForeignKey('Movie', related_name="files") + + computed_path = models.CharField(blank=True, max_length=2048) + size = models.IntegerField(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.IntegerField(default=0) + + part = models.IntegerField(default=1) + + def __unicode__(self): + return "%s (%s)" % (self.computed_path, self.oshash) + +class UserFile(models.Model): + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + user = models.ForeignKey(User) + movie_file = models.ForeignKey(MovieFile) + path = models.CharField(blank=True, max_length=2048) + + def __unicode__(self): + return "%s (%s)" % (self.path, unicode(self.user)) + +class Subtitle(models.Model): + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + user = models.ForeignKey(User) + + movie_file = models.ForeignKey(MovieFile) + language = models.CharField(max_length=16) + srt = models.TextField(blank=True) + + def __unicode__(self): + return "%s.%s.srt" % (os.path.splitext(self.movie_file.computed_path)[0], self.language) + +class Review(models.Model): + movie = models.ForeignKey('Movie', related_name="reviews") + title = models.CharField(blank=True, max_length=2048) + url = models.CharField(blank=True, max_length=2048) + + 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) + diff --git a/backend/urls.py b/backend/urls.py new file mode 100644 index 00000000..f7491f5a --- /dev/null +++ b/backend/urls.py @@ -0,0 +1,39 @@ +from django.conf.urls.defaults import * + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +''' +files/find +files/info +files/add +files/remove + +movies/find +movies/get +movies/edit?movie_id... + +subtitles/list?oshash +subtitles/get?oshash&language +subtitles/add?oshash&language +subtitles/remove?oshash&language +''' + +urlpatterns = patterns('oxdata.api.views', + (r'^files/find', 'find_files'), + (r'^files/info', 'file_info'), + (r'^files/add', 'add_file'), + (r'^files/remove', 'remove_file'), + (r'^subtitle/get', 'get_subtitle'), + + # Example: + # (r'^oxdata/', include('oxdata.foo.urls')), + + # Uncomment the admin/doc line below and add 'django.contrib.admindocs' + # to INSTALLED_APPS to enable admin documentation: + # (r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + # (r'^admin/(.*)', admin.site.root), +) diff --git a/backend/utils.py b/backend/utils.py new file mode 100644 index 00000000..cbebe9dd --- /dev/null +++ b/backend/utils.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +# +import errno +import os +import sys +import re +import hashlib + +import oxlib +import oxlib.iso +from oxlib.normalize import normalizeName + +def oxid(title, director, year='', seriesTitle='', episodeTitle='', season=0, episode=0): + oxid_value = u"\n".join([title, director, year]) + oxid = hashlib.sha1(oxid_value.encode('utf-8')).hexdigest() + if seriesTitle: + oxid_value = u"\n".join([seriesTitle, "%02d" % season]) + oxid = hashlib.sha1(oxid_value.encode('utf-8')).hexdigest()[:20] + oxid_value = u"\n".join(["%02d" % episode, episodeTitle, director, year]) + oxid += hashlib.sha1(oxid_value.encode('utf-8')).hexdigest()[:20] + return u"0x" + oxid + diff --git a/backend/views.py b/backend/views.py new file mode 100644 index 00000000..c3da00f6 --- /dev/null +++ b/backend/views.py @@ -0,0 +1,88 @@ +# Create your views here. + +''' +GET info?oshash=a41cde31c581e11d + > { + "movie_id": 0123456, + "duration": 5.266667, + "video_codec": "mpeg1", + "pixel_format": "yuv420p", + "width": 352, + "height": 240, + "pixel_aspect_ratio": "1:1", + "display_aspect_ratio": "22:15", + "framerate": "30:1", + "audio_codec": "mp2", + "samplerate": 44100, + "channels": 1, + "path": "E/Example, The/An Example.avi", + "size": 1646274 + "oshash": "a41cde31c581e11d", + "sha1":.., + "md5":.. + } +''' +def file_info(request): + oshash = request.GET['oshash'] + + +''' +GET subtitles?oshash=a41cde31c581e11d + > { + "languages": ['en', 'fr', 'de'] + } +GET subtitles?oshash=a41cde31c581e11d&language=en + > srt file +POST subtitle?oshash=a41cde31c581e11d&language=en +srt = +''' +def subtitles(request): + oshash = request.GET['oshash'] + language = request.GET.get('language', None) + if language: + return srt + return movie.subtitle_languages() + +''' +GET list + > { + "files": { + "a41cde31c581e11d": {"path": "E/Example, The/An Example.avi", "size":1646274}, + } + } +''' +def list_files(request): + files = {} + return dict(files=files) + +''' +POST add + > { + "duration": 5.266667, + "video_codec": "mpeg1", + "pixel_format": "yuv420p", + "width": 352, + "height": 240, + "pixel_aspect_ratio": "1:1", + "display_aspect_ratio": "22:15", + "framerate": "30:1", + "audio_codec": "mp2", + "samplerate": 44100, + "channels": 1, + "path": "E/Example, The/An Example.avi", + "size": 1646274 + "oshash": "a41cde31c581e11d", + "sha1":.., + "md5":.. + } +''' +def add_file(request): + oshash = request.POST['oshash'] + +''' +POST remove?oshash= +''' +def remove_file(request): + oshash = request.POST['oshash'] + + diff --git a/fixtures/reviews.json b/fixtures/reviews.json new file mode 100644 index 00000000..4052c710 --- /dev/null +++ b/fixtures/reviews.json @@ -0,0 +1,59 @@ +[ + { + "pk": 1, + "model": "backend.reviewwhitelist", + "fields": { + "url": "://filmcritic.com", + "name": "Filmcritic" + } + }, + { + "pk": 2, + "model": "backend.reviewwhitelist", + "fields": { + "url": "villagevoice.com", + "name": "Village Voice" + } + }, + { + "pk": 3, + "model": "backend.reviewwhitelist", + "fields": { + "url": "salon.com", + "name": "Salon.com" + } + }, + { + "pk": 4, + "model": "backend.reviewwhitelist", + "fields": { + "url": "rottentomatoes.com", + "name": "Rotten Tomatoes" + } + }, + { + "pk": 5, + "model": "backend.reviewwhitelist", + "fields": { + "url": "nytimes.com", + "name": "New York Times" + } + }, + { + "pk": 6, + "model": "backend.reviewwhitelist", + "fields": { + "url": "metacritic.com", + "name": "Metacritic" + } + }, + { + "pk": 7, + "model": "backend.reviewwhitelist", + "fields": { + "url": "sensesofcinema.com", + "name": "Senses of Cinema" + } + } +] + diff --git a/manage.py b/manage.py new file mode 100644 index 00000000..5e78ea97 --- /dev/null +++ b/manage.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python +from django.core.management import execute_manager +try: + import settings # Assumed to be in the same directory. +except ImportError: + import sys + sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) + sys.exit(1) + +if __name__ == "__main__": + execute_manager(settings) diff --git a/settings.py b/settings.py new file mode 100644 index 00000000..8b91d81f --- /dev/null +++ b/settings.py @@ -0,0 +1,80 @@ +# Django settings for oxdata project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + # ('Your Name', 'your_email@domain.com'), +) + +MANAGERS = ADMINS + +DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. +DATABASE_NAME = 'dev.sqlite' # Or path to database file if using sqlite3. +DATABASE_USER = '' # Not used with sqlite3. +DATABASE_PASSWORD = '' # Not used with sqlite3. +DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. +DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# Absolute path to the directory that holds media. +# Example: "/home/media/media.lawrence.com/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash if there is a path component (optional in other cases). +# Examples: "http://media.lawrence.com", "http://example.com/media/" +MEDIA_URL = '' + +# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a +# trailing slash. +# Examples: "http://foo.com/media/", "/media/". +ADMIN_MEDIA_PREFIX = '/media/' + +# Make this unique, and don't share it with anybody. +SECRET_KEY = '3fh^twg4!7*xcise#3d5%ty+^-#9+*f0innkjcco+y0dag_nr-' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.load_template_source', + 'django.template.loaders.app_directories.load_template_source', +# 'django.template.loaders.eggs.load_template_source', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', +) + +ROOT_URLCONF = 'oxdata.urls' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'oxdb.backend', +) diff --git a/urls.py b/urls.py new file mode 100644 index 00000000..e07f6a76 --- /dev/null +++ b/urls.py @@ -0,0 +1,17 @@ +from django.conf.urls.defaults import * + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +urlpatterns = patterns('', + # Example: + # (r'^oxdata/', include('oxdata.foo.urls')), + + # Uncomment the admin/doc line below and add 'django.contrib.admindocs' + # to INSTALLED_APPS to enable admin documentation: + # (r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + # (r'^admin/(.*)', admin.site.root), +)