diff --git a/pandora/0xdb.jsonc b/pandora/0xdb.jsonc index 77dd498c..8495a99c 100644 --- a/pandora/0xdb.jsonc +++ b/pandora/0xdb.jsonc @@ -21,6 +21,7 @@ "canSeeDebugMenu": {"admin": true}, "canSeeFiles": {"staff": true, "admin": true}, "canSeeItem": {"guest": 2, "member": 2, "friend": 3, "staff": 4, "admin": 4}, + "canSeeNotes": {"staff": true, "admin": true}, "canSeeExtraItemViews": {"friend": true, "staff": true, "admin": true} }, /* diff --git a/pandora/app/views.py b/pandora/app/views.py index fa6fb4b6..60f8f354 100644 --- a/pandora/app/views.py +++ b/pandora/app/views.py @@ -25,7 +25,7 @@ def index(request): return render_to_response('index.html', context) -def embed(request): +def embed(request, id): context = RequestContext(request, {'settings': settings}) return render_to_response('embed.html', context) diff --git a/pandora/archive/extract.py b/pandora/archive/extract.py index 1cf41cd6..1c357f1a 100644 --- a/pandora/archive/extract.py +++ b/pandora/archive/extract.py @@ -291,7 +291,7 @@ def average_color(prefix, start=0, end=0): timelines = sorted(filter(lambda t: t!= '%s%sp.png'%(prefix,height), glob("%s%sp*.png"%(prefix, height)))) for image in timelines: start_offset = 0 - timeline = Image.open(image) + timeline = Image.open(image).convert('RGB') frames += timeline.size[0] if start and frames < start: continue diff --git a/pandora/archive/models.py b/pandora/archive/models.py index 449083a0..5e963375 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -504,14 +504,9 @@ class Stream(models.Model): self.file.save() def json(self): - if settings.XSENDFILE or settings.XACCELREDIRECT: - base_url = '/%s' % self.file.item.itemId - else: - base_url = os.path.dirname(self.video.url) return { 'duration': self.duration, 'aspectRatio': self.aspect_ratio, - 'baseUrl': base_url } def delete_stream(sender, **kwargs): diff --git a/pandora/item/models.py b/pandora/item/models.py index 3cde9962..6a20a015 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -159,6 +159,8 @@ class Item(models.Model): upload_to=lambda i, x: i.path('torrent.torrent')) stream_info = fields.DictField(default={}, editable=False) + notes = models.TextField(default='') + #stream related fields stream_aspect = models.FloatField(default=4/3) @@ -401,7 +403,8 @@ class Item(models.Model): def get_json(self, keys=None): i = { 'id': self.itemId, - 'rendered': self.rendered + 'rendered': self.rendered, + 'rightsLevel': self.level } i.update(self.external_data) i.update(self.data) diff --git a/pandora/item/urls.py b/pandora/item/urls.py index a7895553..23bf9fe6 100644 --- a/pandora/item/urls.py +++ b/pandora/item/urls.py @@ -27,5 +27,4 @@ urlpatterns = patterns("item.views", (r'^(?P[A-Z0-9].+)/poster\.jpg$', 'siteposter'), (r'^(?P[A-Z0-9].+)/frameposter(?P\d+).jpg$', 'poster_frame'), - ) diff --git a/pandora/item/views.py b/pandora/item/views.py index a51443c5..d56183b5 100644 --- a/pandora/item/views.py +++ b/pandora/item/views.py @@ -395,6 +395,9 @@ def get(request): info['layers'] = item.get_layers(request.user) if data['keys'] and 'files' in data['keys']: info['files'] = item.get_files(request.user) + if not data['keys'] or 'notes' in data['keys'] \ + and request.user.get_profile().capability('canSeeNotes'): + info['notes'] = item.notes response['data'] = info else: response = json_response(status=403, text='permission denied') @@ -438,6 +441,10 @@ def editItem(request): item = get_object_or_404_json(models.Item, itemId=data['id']) if item.editable(request.user): response = json_response(status=200, text='ok') + if 'notes' in data: + if request.user.get_profile().capability('canSeeNotes'): + item.notes = data['notes'] + del data['notes'] item.edit(data) else: response = json_response(status=403, text='permissino denied') diff --git a/pandora/templates/embed.html b/pandora/templates/embed.html index 65e1d5a1..b63fa1d3 100644 --- a/pandora/templates/embed.html +++ b/pandora/templates/embed.html @@ -3,15 +3,9 @@ {{settings.SITENAME}} - - - + - + + diff --git a/pandora/urls.py b/pandora/urls.py index 23a2b6f5..78ecfddf 100644 --- a/pandora/urls.py +++ b/pandora/urls.py @@ -27,6 +27,7 @@ urlpatterns = patterns('', (r'^url=(?P.*)$', 'app.views.redirect_url'), (r'^file/(?P.*)$', 'archive.views.lookup_file'), (r'^api/$', include('api.urls')), + (r'^resetUI$', 'user.views.reset_ui'), (r'', include('item.urls')), (r'^list/(?P.*?)/icon(?P\d*).jpg$', 'itemlist.views.icon'), (r'^robots.txt$', serve_static_file, {'location': os.path.join(settings.STATIC_ROOT, 'robots.txt'), 'content_type': 'text/plain'}), @@ -47,7 +48,7 @@ urlpatterns += patterns('', (r'^(V[a-z0-9]*/.*)$', 'urlalias.views.padma_video'), ) urlpatterns += patterns('', - (r'^.*?embed$', 'app.views.embed'), + (r'^(?P[A-Z0-9].+)/embed', 'app.views.embed'), (r'^[A-Z0-9].*$', 'app.views.index'), (r'^[a-z0-9].+$', 'app.views.index'), (r'^$', 'app.views.index'), diff --git a/pandora/user/models.py b/pandora/user/models.py index 4299a511..1c09cc32 100644 --- a/pandora/user/models.py +++ b/pandora/user/models.py @@ -42,6 +42,9 @@ class UserProfile(models.Model): def get_level(self): return settings.CONFIG['userLevels'][self.level] + def capability(self, capability): + return settings.CONFIG['capabilities'][capability].get(self.get_level()) == True + def user_post_save(sender, instance, **kwargs): profile, new = UserProfile.objects.get_or_create(user=instance) diff --git a/pandora/user/views.py b/pandora/user/views.py index 8737a4af..a5bd5f97 100644 --- a/pandora/user/views.py +++ b/pandora/user/views.py @@ -4,7 +4,6 @@ import random random.seed() import re -from django import forms from django.contrib.auth.models import User from django.contrib.auth import authenticate, login, logout from django.template import RequestContext, loader @@ -12,6 +11,7 @@ from django.utils import simplejson as json from django.conf import settings from django.core.mail import send_mail, BadHeaderError from django.db.models import Sum +from django.shortcuts import redirect from ox.django.shortcuts import render_to_json_response, json_response, get_object_or_404_json from ox.django.decorators import admin_required_json, login_required_json @@ -26,11 +26,6 @@ import models import managers -class SigninForm(forms.Form): - username = forms.TextInput() - password = forms.TextInput() - - def signin(request): ''' param data { @@ -52,9 +47,10 @@ def signin(request): } ''' data = json.loads(request.POST['data']) - form = SigninForm(data, request.FILES) - if form.is_valid(): - if models.User.objects.filter(username=form.data['username']).count() == 0: + if 'username' in data and 'password' in data: + data['username'] = data['username'].strip() + data['password'] = data['password'].strip() + if models.User.objects.filter(username=data['username']).count() == 0: response = json_response({ 'errors': { 'username': 'Unknown Username' @@ -112,12 +108,6 @@ def signout(request): actions.register(signout, cache=False) -class SignupForm(forms.Form): - username = forms.TextInput() - password = forms.TextInput() - email = forms.TextInput() - - def signup(request): ''' param data { @@ -140,21 +130,22 @@ def signup(request): } ''' data = json.loads(request.POST['data']) - form = SignupForm(data, request.FILES) - if form.is_valid(): - if models.User.objects.filter(username=form.data['username']).count() > 0: + if 'username' in data and 'password' in data: + data['username'] = data['username'].strip() + data['password'] = data['password'].strip() + if models.User.objects.filter(username=data['username']).count() > 0: response = json_response({ 'errors': { 'username': 'Username already exists' } }) - elif models.User.objects.filter(email=form.data['email']).count() > 0: + elif models.User.objects.filter(email=data['email']).count() > 0: response = json_response({ 'errors': { 'email': 'Email address already exits' } }) - elif not form.data['password']: + elif not data['password']: response = json_response({ 'errors': { 'password': 'Password can not be empty' @@ -162,8 +153,8 @@ def signup(request): }) else: first_user = models.User.objects.count() == 0 - user = models.User(username=form.data['username'], email=form.data['email']) - user.set_password(form.data['password']) + user = models.User(username=data['username'], email=data['email']) + user.set_password(data['password']) #make first user admin user.is_superuser = first_user user.is_staff = first_user @@ -176,8 +167,8 @@ def signup(request): setattr(list, key, l[key]) list.save() - user = authenticate(username=form.data['username'], - password=form.data['password']) + user = authenticate(username=data['username'], + password=data['password']) login(request, user) user_json = models.init_user(user) response = json_response({ @@ -375,7 +366,8 @@ def findUser(request): ''' param data { key: "username", - value: "foo", operator: "=" + value: "foo", + operator: "==" keys: [] } @@ -528,12 +520,6 @@ Positions actions.register(findUsers) -class ContactForm(forms.Form): - email = forms.EmailField() - subject = forms.TextInput() - message = forms.TextInput() - - def contact(request): ''' param data { @@ -547,8 +533,7 @@ def contact(request): } ''' data = json.loads(request.POST['data']) - form = ContactForm(data, request.FILES) - if form.is_valid(): + if 'email' in data and 'message' in data: email = data['email'] template = loader.get_template('contact_email.txt') context = RequestContext(request, { @@ -607,6 +592,16 @@ def editPreferences(request): actions.register(editPreferences, cache=False) +def reset_ui(request): + response = json_response() + if request.user.is_authenticated(): + profile = request.user.get_profile() + profile.ui = {} + profile.save() + else: + request.session['ui'] = '{}' + return redirect('/') + def resetUI(request): ''' reset user ui settings to defaults diff --git a/static/js/pandora.embed.js b/static/js/pandora.embed.js deleted file mode 100755 index 60f896ec..00000000 --- a/static/js/pandora.embed.js +++ /dev/null @@ -1,132 +0,0 @@ -/*** - Pandora embed -***/ -Ox.load('UI', { - debug: true, - hideScreen: false, - loadImages: true, - showScreen: true, - theme: 'modern' -}, function() { -window.pandora = new Ox.App({url: '/api/'}).bindEvent({ - apiURL: '/api/', -}).bindEvent('load', function(data) { - Ox.extend(pandora, { - ui: {}, - info: function(item) { - var that = Ox.Element() - .append( - ui.infoTimeline = Ox.Element('') - .css({ - position: 'absolute', - left: 0, - bottom: 0, - height: '16px', - }) - .attr('src', '/' + item + '/timeline16p.png') - ) - .append( - ui.infoStill = new app.flipbook(item) - .css({ - position: 'absolute', - left: 0, - width: '100%', - height: $(document).height()-16 + 'px', - }) - ) - return that; - }, - clip: function(item, inPoint, outPoint) { - Ox.print('!@#!@#!@#', inPoint, outPoint); - var that = Ox.Element(); - pandora.api.getItem(item, function(result) { - var video = result.data.stream, - format = $.support.video.supportedFormat(video.formats); - video.height = video.profiles[0]; - video.width = parseInt(video.height * video.aspectRatio / 2) * 2; - video.url = video.baseUrl + '/' + video.height + 'p.' + format; - that.append(pandora.player = Ox.VideoPlayer({ - controlsBottom: ['playInToOut', 'space', 'position'], - enableFind: false, - enableFullscreen: true, - enableVolume: true, - externalControls: false, - height: 192, - paused: true, - showMarkers: true, - showMilliseconds: 2, - width: 360, - 'in': inPoint, - out: outPoint, - position: inPoint, - poster: '/' + item + '/' + '128p' + inPoint +'.jpg', - title: result.data.title, - video: video.url - }) - .bindEvent({ - position: function(data) { - if(data.positionoutPoint) { - if(!pandora.player.options('paused')) - pandora.player.togglePaused(); - pandora.player.options({ - position: inPoint, - }); - } - } - }) - - ); - Ox.UI.hideLoadingScreen(); - }); - return that; - }, - flipbook: function(item) { - var that = Ox.Flipbook({ - }).bindEvent('click', function(data) { - var item_url = document.location.origin + '/' + item; - window.top.location.href = item_url + '/timeline#t=' + data.position; - }); - pandora.api.getItem(item, function(result) { - var duration = result.data.item.duration, - posterFrame = result.data.item.posterFrame || parseInt(duration/2), - steps = 24, - framePrefix = '/' + item + '/' + that.height() + 'p', - frames = {}; - Ox.range(0, duration, duration/steps).forEach(function(position) { - position = parseInt(position); - frames[position] = framePrefix + position + '.jpg'; - }); - that.options({ - frames: frames, - icon: framePrefix + posterFrame + '.jpg', - duration: duration - }); - }); - return that; - } - }); - var item = document.location.pathname.split('/')[1]; - function getArgument(key, result) { - var args = Ox.map(document.location.hash.substr(1).split('&'), function(a) { - a = a.split('='); - var key = a[0], - value = a[1]; - return { - 'key': key, - 'value': value - } - }); - args.forEach(function(a, i) { - Ox.print(i, a); - if (a.key == key) { - result = a.value; - return false; - } - }); - return result; - } - var t = getArgument('t', '0,10').split(',') - pandora.ui.info = pandora.clip(item, parseInt(t[0]), parseInt(t[1])) - .appendTo(document.body); -}); -}); diff --git a/static/js/pandoraEmbed.js b/static/js/pandoraEmbed.js new file mode 100755 index 00000000..4874ccd4 --- /dev/null +++ b/static/js/pandoraEmbed.js @@ -0,0 +1,74 @@ +/*** + Pandora embed +***/ +Ox.load('UI', { + debug: false, + hideScreen: false, + loadImages: true, + showScreen: true, + theme: 'modern' +}, function() { + window.pandora = new Ox.App({url: '/api/'}).bindEvent({ + load: function(data) { + Ox.extend(pandora, { + site: data.site, + user: data.user.level == 'guest' ? Ox.clone(data.site.user) : data.user, + ui: {}, + clip: function(item, inPoint, outPoint) { + Ox.print('!@#!@#!@#', inPoint, outPoint); + var that = Ox.Element(); + pandora.api.get({id: item, keys: []}, function(result) { + var video = {}; + pandora.site.video.resolutions.forEach(function(resolution) { + video[resolution] = Ox.range(result.data.parts).map(function(i) { + return '/' + pandora.user.ui.item + '/' + + resolution + 'p' + (i + 1) + '.' + pandora.user.videoFormat; + }); + }); + that.append(pandora.player = Ox.VideoPlayer({ + controlsBottom: ['play', 'playInToOut', 'space', 'position'], + enableFind: false, + enableFullscreen: true, + enableVolume: true, + externalControls: false, + height: document.height, + 'in': inPoint, + out: outPoint, + paused: true, + position: inPoint, + poster: '/' + item + '/' + '128p' + inPoint +'.jpg', + showMarkers: true, + showMilliseconds: 2, + title: result.data.title, + video: video, + width: document.width, + }) + .bindEvent({ + position: function(data) { + if(data.positionoutPoint) { + if(!pandora.player.options('paused')) + pandora.player.togglePaused(); + pandora.player.options({ + position: inPoint, + }); + } + } + }) + ); + Ox.UI.hideLoadingScreen(); + }); + return that; + }, + }); + Ox.extend(pandora.user, { + videoFormat: Ox.UI.getVideoFormat(pandora.site.video.formats) + }); + var item = document.location.pathname.split('/')[1], + inPoint = 10, + outPoint = 15; + pandora.ui.info = pandora.clip(item, inPoint, outPoint) + .css({width: '100%', height: '100%'}) + .appendTo(document.body); + } + }); +});