diff --git a/pandora/archive/models.py b/pandora/archive/models.py index 95610e0..92b9860 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -20,13 +20,14 @@ import chardet from item import utils from item.models import Item from person.models import get_name_sort -from annotation.models import Annotation, Layer + class File(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) verified = models.BooleanField(default=False) + auto = models.BooleanField(default=True) oshash = models.CharField(max_length=16, unique=True) item = models.ForeignKey(Item, related_name='files') @@ -75,7 +76,7 @@ class File(models.Model): def __unicode__(self): return self.name - def save(self, *args, **kwargs): + def set_state(self): instance = self.get_instance() if instance: if instance.name.lower().startswith('extras/'): @@ -152,6 +153,10 @@ class File(models.Model): if self.type not in ('audio', 'video'): self.duration = None + + def save(self, *args, **kwargs): + if self.auto: + self.set_state() super(File, self).save(*args, **kwargs) #upload and data handling @@ -268,7 +273,7 @@ class File(models.Model): 'height': self.height, 'width': self.width, 'resolution': resolution, - 'oshash': self.oshash, + 'id': self.oshash, 'samplerate': self.samplerate, 'video_codec': self.video_codec, 'audio_codec': self.audio_codec, diff --git a/pandora/archive/views.py b/pandora/archive/views.py index 6a99b12..1e992b0 100644 --- a/pandora/archive/views.py +++ b/pandora/archive/views.py @@ -119,7 +119,7 @@ actions.register(encodingProfile) @login_required_json def upload(request): ''' - oshash: string + id: string frame: [] //multipart frames file: [] //multipart file @@ -132,7 +132,7 @@ def upload(request): } ''' response = json_response({}) - f = get_object_or_404_json(models.File, oshash=request.POST['oshash']) + f = get_object_or_404_json(models.File, oshash=request.POST['id']) if 'frame' in request.FILES: if f.frames.count() == 0: for frame in request.FILES.getlist('frame'): @@ -164,7 +164,7 @@ class VideoChunkForm(forms.Form): @login_required_json def firefogg_upload(request): profile = request.GET['profile'] - oshash = request.GET['oshash'] + oshash = request.GET['id'] #handle video upload if request.method == 'POST': #post next chunk @@ -203,7 +203,7 @@ def firefogg_upload(request): f.save() response = { #is it possible to no hardcode url here? - 'uploadUrl': request.build_absolute_uri('/api/upload/?oshash=%s&profile=%s' % (f.oshash, profile)), + 'uploadUrl': request.build_absolute_uri('/api/upload/?id=%s&profile=%s' % (f.oshash, profile)), 'result': 1 } return render_to_json_response(response) @@ -221,6 +221,7 @@ def taskStatus(request): return render_to_json_response(response) actions.register(taskStatus, cache=False) + @login_required_json def moveFiles(request): ''' @@ -253,37 +254,34 @@ def moveFiles(request): return render_to_json_response(response) actions.register(moveFiles, cache=False) + @login_required_json def editFile(request): ''' change file / item link param data { - oshash: hash of file - itemId: new itemId + id: hash of file + part: + id_extra: boolean } return { status: {'code': int, 'text': string}, data: { - imdbId:string } } ''' #FIXME: permissions, need to be checked data = json.loads(request.POST['data']) - f = get_object_or_404_json(models.File, oshash=data['oshash']) + f = get_object_or_404_json(models.File, oshash=data['id']) response = json_response() - if f.item.id != data['itemId']: - if len(data['itemId']) != 7: - folder = f.instances.all()[0].folder - item_info = utils.parse_path(folder) - item = get_item(item_info) - else: - item = get_item({'imdbId': data['itemId']}) - f.item = item + if data.keys() != ('id', ): + for key in data: + if key in ('is_extra', 'is_subtitle', 'is_video', 'is_version', + 'part', 'language'): + setattr(f, key, data[key]) + f.auto = False f.save() - #FIXME: other things might need updating here - response = json_response(text='updated') return render_to_json_response(response) actions.register(editFile, cache=False) diff --git a/pandora/item/admin.py b/pandora/item/admin.py index 0b33cfd..dc14151 100644 --- a/pandora/item/admin.py +++ b/pandora/item/admin.py @@ -8,7 +8,7 @@ import models class ItemAdmin(admin.ModelAdmin): search_fields = ['itemId', 'data', 'external_data'] - list_display = ['available', 'itemId', '__unicode__'] + list_display = ['rendered', 'itemId', '__unicode__'] list_display_links = ('__unicode__', ) admin.site.register(models.Item, ItemAdmin) diff --git a/pandora/item/managers.py b/pandora/item/managers.py index ee5c213..9ee4032 100644 --- a/pandora/item/managers.py +++ b/pandora/item/managers.py @@ -239,7 +239,6 @@ class ItemManager(Manager): #join query with operator qs = self.get_query_set() #only include items that have hard metadata - qs = qs.filter(available=True) conditions = parseConditions(data.get('query', {}).get('conditions', []), data.get('query', {}).get('operator', '&')) qs = qs.filter(conditions).distinct() diff --git a/pandora/item/models.py b/pandora/item/models.py index a8d2950..cf77025 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -100,9 +100,8 @@ class Item(models.Model): user = models.ForeignKey(User, null=True, related_name='items') groups = models.ManyToManyField(Group, blank=True, related_name='items') - #only items that have data from files are available, - #this is indicated by setting available to True - available = models.BooleanField(default=False, db_index=True) + #while metadata is updated, files are set to rendered=False + rendered = models.BooleanField(default=False, db_index=True) public = models.BooleanField(default=False, db_index=True) itemId = models.CharField(max_length=128, unique=True, blank=True) @@ -133,7 +132,7 @@ class Item(models.Model): return default def access(self, user): - if self.public and self.available: + if self.public: return True elif user.is_authenticated() and \ (user.is_staff or self.user == user or \ @@ -333,7 +332,8 @@ class Item(models.Model): def get_json(self, fields=None): i = { - 'id': self.itemId + 'id': self.itemId, + 'rendered': self.rendered } i.update(self.external_data) i.update(self.data) @@ -526,7 +526,7 @@ class Item(models.Model): s.volume = None if 'color' in self.data: - s.hue, s.saturation, s.brightness = self.data['color'] + s.hue, s.saturation, s.lightness = self.data['color'] else: s.hue = None s.saturation = None @@ -657,7 +657,7 @@ class Item(models.Model): self.make_local_posters() self.make_poster() self.make_icon() - self.available = True + self.rendered = True self.save() ''' diff --git a/pandora/item/views.py b/pandora/item/views.py index da4116e..e3f800a 100644 --- a/pandora/item/views.py +++ b/pandora/item/views.py @@ -553,7 +553,9 @@ def poster(request, id, size=None): if not size: size='large' poster_path = os.path.join(settings.STATIC_ROOT, 'png/posterDark.48.png') - return HttpFileResponse(poster_path, content_type='image/jpeg') + response = HttpFileResponse(poster_path, content_type='image/jpeg') + response['Cache-Control'] = 'no-cache' + return response def icon(request, id, size=None): diff --git a/requirements.txt b/requirements.txt index 90cfe61..11804de 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ -e bzr+http://code.0x2620.org/python-ox/#egg=python-ox -e bzr+http://code.0x2620.org/oxtimeline/#egg=oxtimeline simplejson +chardet -e hg+https://django-ajax-filtered-fields.googlecode.com/hg/#egg=django-ajax-filtered-fields celery>2.1.1 django-celery>2.1.1 diff --git a/static/js/pandora/ui/Ox.FilesView.js b/static/js/pandora/ui/Ox.FilesView.js index 176141c..bd1571b 100644 --- a/static/js/pandora/ui/Ox.FilesView.js +++ b/static/js/pandora/ui/Ox.FilesView.js @@ -105,9 +105,9 @@ Ox.FilesView = function(options, self) { }, { align: 'left', - id: 'oshash', + id: 'id', operator: '+', - title: 'Hash', + title: 'ID', unique: true, visible: false, width: 120 diff --git a/static/js/pandora/ui/item.js b/static/js/pandora/ui/item.js index 5a417bf..e8d9e8a 100644 --- a/static/js/pandora/ui/item.js +++ b/static/js/pandora/ui/item.js @@ -6,6 +6,14 @@ pandora.ui.item = function() { pandora.$ui.contentPanel.replaceElement(1, Ox.Element().html( 'The '+pandora.site.itemName.singular+' you are looking for does not exist.')); + } else if (!result.data.rendered && + ['clips', 'map', + 'player', 'timeline'].indexOf(pandora.user.ui.itemView)>-1) { + pandora.$ui.contentPanel.replaceElement(1, + Ox.Element().css({margin: '16px'}).html( + 'We are sorry, "' + result.data.title + + '" does not have a '+pandora.user.ui.itemView + + ' view right now.')); } else if (pandora.user.ui.itemView == 'calendar') { pandora.$ui.contentPanel.replaceElement(1, Ox.Element().html('Calendar')); } else if (pandora.user.ui.itemView == 'clips') { @@ -55,7 +63,7 @@ pandora.ui.item = function() { var $form, $edit = Ox.Element() .append($form = Ox.FormElementGroup({ - elements: Ox.map(pandora.site.itemKeys, function(key) { + elements: Ox.map(pandora.site.sortKeys, function(key) { return Ox.Input({ id: key.id, label: key.title, @@ -228,7 +236,14 @@ pandora.ui.item = function() { } })); } else if (pandora.user.ui.itemView == 'statistics') { - pandora.$ui.contentPanel.replaceElement(1, Ox.Element().html('Statistics')); + var stats = Ox.Container(); + Ox.TreeList({ + data: result.data, + width: 256 + }).appendTo(stats); + + pandora.$ui.contentPanel.replaceElement(1, stats); + } else if (pandora.user.ui.itemView == 'timeline') { var layers = [], video = result.data.stream, diff --git a/static/js/pandora/ui/list.js b/static/js/pandora/ui/list.js index c60f15c..28aa934 100644 --- a/static/js/pandora/ui/list.js +++ b/static/js/pandora/ui/list.js @@ -48,7 +48,7 @@ pandora.ui.list = function(view) { // fixme: remove view argument }) .bindEvent({ columnchange: function(event, data) { - var columnWidth = {} + var columnWidth = {}; pandora.UI.set(['lists', pandora.user.ui.list, 'columns'].join('|'), data.ids); /* data.ids.forEach(function(id) { @@ -95,6 +95,16 @@ pandora.ui.list = function(view) { // fixme: remove view argument sort: pandora.user.ui.lists[pandora.user.ui.list].sort, unique: 'id' }); + } else if (view == 'info') { + that = Ox.Element().css({margin: '16px'}).html(view + ' results view still missing.'); + } else if (view == 'clips') { + that = Ox.Element().css({margin: '16px'}).html(view + ' results view still missing.'); + } else if (view == 'timelines') { + that = Ox.Element().css({margin: '16px'}).html(view + ' results view still missing.'); + } else if (view == 'maps') { + that = Ox.Element().css({margin: '16px'}).html(view + ' results view still missing.'); + } else if (view == 'calendars') { + that = Ox.Element().css({margin: '16px'}).html(view + ' results view still missing.'); } else if (view == 'clip') { that = Ox.IconList({ item: function(data, sort, size) {