add share link at /m/, add share dialog in view menu, fix preview for documents
This commit is contained in:
parent
17801df8de
commit
bea0d301a4
30 changed files with 2704 additions and 4 deletions
|
|
@ -190,6 +190,12 @@ class MetaClip(object):
|
|||
def __str__(self):
|
||||
return self.public_id
|
||||
|
||||
def get_first_frame(self, resolution=None):
|
||||
if resolution is None:
|
||||
resolution = max(settings.CONFIG['video']['resolutions'])
|
||||
return '/%s/%sp%0.03f.jpg' % (self.item.public_id, resolution, float(self.start))
|
||||
|
||||
|
||||
class Meta:
|
||||
unique_together = ("item", "start", "end")
|
||||
|
||||
|
|
|
|||
|
|
@ -567,7 +567,7 @@ class Document(models.Model, FulltextMixin):
|
|||
if len(crop) == 4:
|
||||
path = os.path.join(folder, '%s.jpg' % ','.join(map(str, crop)))
|
||||
if not os.path.exists(path):
|
||||
img = Image.open(src).crop(crop)
|
||||
img = Image.open(src).convert('RGB').crop(crop)
|
||||
img.save(path)
|
||||
else:
|
||||
img = Image.open(path)
|
||||
|
|
|
|||
|
|
@ -12,9 +12,10 @@ from oxdjango.decorators import login_required_json
|
|||
from oxdjango.http import HttpFileResponse
|
||||
from oxdjango.shortcuts import render_to_json_response, get_object_or_404_json, json_response, HttpErrorJson
|
||||
from django import forms
|
||||
from django.db.models import Count, Sum
|
||||
from django.conf import settings
|
||||
from django.db.models import Count, Sum
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
|
||||
from item import utils
|
||||
from item.models import Item
|
||||
|
|
@ -512,3 +513,33 @@ def autocompleteDocuments(request, data):
|
|||
response['data']['items'] = [i['value'] for i in qs]
|
||||
return render_to_json_response(response)
|
||||
actions.register(autocompleteDocuments)
|
||||
|
||||
|
||||
def document(request, fragment):
|
||||
context = {}
|
||||
parts = fragment.split('/')
|
||||
id = parts[0]
|
||||
page = None
|
||||
crop = None
|
||||
if len(parts) == 2:
|
||||
rect = parts[1].split(',')
|
||||
if len(rect) == 1:
|
||||
page = rect[0]
|
||||
else:
|
||||
crop = rect
|
||||
document = models.Document.objects.filter(id=ox.fromAZ(id)).first()
|
||||
if document and document.access(request.user):
|
||||
context['title'] = document.data['title']
|
||||
if document.data.get('description'):
|
||||
context['description'] = document.data['description']
|
||||
link = request.build_absolute_uri(document.get_absolute_url())
|
||||
public_id = ox.toAZ(document.id)
|
||||
preview = '/documents/%s/512p.jpg' % public_id
|
||||
if page:
|
||||
preview = '/documents/%s/512p%s.jpg' % (public_id, page)
|
||||
if crop:
|
||||
preview = '/documents/%s/512p%s.jpg' % (public_id, ','.join(crop))
|
||||
context['preview'] = request.build_absolute_uri(preview)
|
||||
context['url'] = request.build_absolute_uri('/documents/' + fragment)
|
||||
context['settings'] = settings
|
||||
return render(request, "document.html", context)
|
||||
|
|
|
|||
0
pandora/mobile/__init__.py
Normal file
0
pandora/mobile/__init__.py
Normal file
3
pandora/mobile/admin.py
Normal file
3
pandora/mobile/admin.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
5
pandora/mobile/apps.py
Normal file
5
pandora/mobile/apps.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class MobileConfig(AppConfig):
|
||||
name = 'mobile'
|
||||
0
pandora/mobile/migrations/__init__.py
Normal file
0
pandora/mobile/migrations/__init__.py
Normal file
3
pandora/mobile/models.py
Normal file
3
pandora/mobile/models.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
pandora/mobile/tests.py
Normal file
3
pandora/mobile/tests.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
75
pandora/mobile/views.py
Normal file
75
pandora/mobile/views.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
from django.conf import settings
|
||||
from django.shortcuts import render
|
||||
|
||||
import ox
|
||||
|
||||
|
||||
def index(request, fragment):
|
||||
from item.models import Item
|
||||
from edit.models import Edit
|
||||
from document.models import Document
|
||||
context = {}
|
||||
parts = fragment.split('/')
|
||||
if parts[0] in ('document', 'documents'):
|
||||
type = 'document'
|
||||
id = parts[1]
|
||||
page = None
|
||||
crop = None
|
||||
if len(parts) == 3:
|
||||
rect = parts[2].split(',')
|
||||
if len(rect) == 1:
|
||||
page = rect[0]
|
||||
else:
|
||||
crop = rect
|
||||
document = Document.objects.filter(id=ox.fromAZ(id)).first()
|
||||
if document and document.access(request.user):
|
||||
context['title'] = document.data['title']
|
||||
link = request.build_absolute_uri(document.get_absolute_url())
|
||||
# FIXME: get preview image or fragment parse from url
|
||||
public_id = ox.toAZ(document.id)
|
||||
preview = '/documents/%s/512p.jpg' % public_id
|
||||
if page:
|
||||
preview = '/documents/%s/512p%s.jpg' % (public_id, page)
|
||||
if crop:
|
||||
preview = '/documents/%s/512p%s.jpg' % (public_id, ','.join(crop))
|
||||
context['preview'] = request.build_absolute_uri(preview)
|
||||
|
||||
elif parts[0] == 'edits':
|
||||
type = 'edit'
|
||||
id = parts[1]
|
||||
id = id.split(':')
|
||||
username = id[0]
|
||||
name = ":".join(id[1:])
|
||||
name = name.replace('_', ' ')
|
||||
edit = Edit.objects.filter(user__username=username, name=name).first()
|
||||
if edit and edit.accessible(request.user):
|
||||
link = request.build_absolute_uri('/m' + edit.get_absolute_url())
|
||||
context['title'] = name
|
||||
context['description'] = edit.description.split('\n\n')[0]
|
||||
# FIXME: use sort from parts if needed
|
||||
context['preview'] = request.build_absolute_uri(edit.get_clips().first().get_first_frame())
|
||||
else:
|
||||
type = 'item'
|
||||
id = parts[0]
|
||||
item = Item.objects.filter(public_id=id).first()
|
||||
if item and item.accessible(request.user):
|
||||
link = request.build_absolute_uri(item.get_absolute_url())
|
||||
if len(parts) > 1 and parts[1] in ('editor', 'player'):
|
||||
parts = [parts[0]] + parts[2:]
|
||||
if len(parts) > 1:
|
||||
inout = parts[1]
|
||||
if '-' in inout:
|
||||
inout = inout.split('-')
|
||||
else:
|
||||
inout = inout.split(',')
|
||||
inout = [ox.parse_timecode(p) for p in inout]
|
||||
if len(inout) == 3:
|
||||
inout.pop(1)
|
||||
context['preview'] = link + '/480p%s.jpg' % inout[0]
|
||||
else:
|
||||
context['preview'] = link + '/480p.jpg'
|
||||
context['title'] = item.get('title')
|
||||
if context:
|
||||
context['url'] = request.build_absolute_uri('/m/' + fragment)
|
||||
context['settings'] = settings
|
||||
return render(request, "mobile/index.html", context)
|
||||
|
|
@ -67,7 +67,8 @@ STATICFILES_DIRS = (
|
|||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
#'django.contrib.staticfiles.finders.DefaultStorageFinder',
|
||||
"sass_processor.finders.CssFinder",
|
||||
"compressor.finders.CompressorFinder",
|
||||
)
|
||||
|
||||
GEOIP_PATH = normpath(join(PROJECT_ROOT, '..', 'data', 'geo'))
|
||||
|
|
@ -124,6 +125,9 @@ INSTALLED_APPS = (
|
|||
'django_extensions',
|
||||
'django_celery_results',
|
||||
'django_celery_beat',
|
||||
'compressor',
|
||||
'sass_processor',
|
||||
|
||||
'app',
|
||||
'log',
|
||||
'annotation',
|
||||
|
|
@ -150,6 +154,7 @@ INSTALLED_APPS = (
|
|||
'websocket',
|
||||
'taskqueue',
|
||||
'home',
|
||||
'mobile',
|
||||
)
|
||||
|
||||
AUTH_USER_MODEL = 'system.User'
|
||||
|
|
|
|||
38
pandora/templates/document.html
Normal file
38
pandora/templates/document.html
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>{{head_title}}</title>
|
||||
<link rel="alternate" type="application/json+oembed" href="{{base_url}}oembed?url={{current_url|urlencode}}" title="oEmbed Profile"/>
|
||||
{% include "baseheader.html" %}
|
||||
<meta name="title" content="{{title}}"/>
|
||||
{%if description %}<meta name="description" content="{{description}}"/> {%endif%}
|
||||
<meta content="{{ preview }}" name="thumbnail"/>
|
||||
<meta content="{{ preview }}" name="image_src"/>
|
||||
<meta property="og:title" content="{{title}}"/>
|
||||
<meta property="og:url" content="{{url}}"/>
|
||||
<meta property="og:image" content="{{ preview }}"/>
|
||||
<meta property="og:site_name" content="{{settings.SITENAME}}"/>
|
||||
{%if description %}<meta property="og:description" content="{{description}}"/>{%endif%}
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<div style="position: fixed; left: 0; top: 0; right: 0; bottom: 0; background-color: rgb(144, 144, 144);"></div>
|
||||
<div style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; text-align: center; font-family: Lucida Grande, Segoe UI, DejaVu Sans, Lucida Sans Unicode, Helvetica, Arial, sans-serif; font-size: 11px; color: rgb(0, 0, 0); -moz-user-select: none; -o-user-select: none; -webkit-user-select: none">
|
||||
<img src="/{{id}}/{{icon}}128.jpg" alt="" style="padding-top: 64px; -moz-user-drag: none; -o-user-drag: none; -webkit-user-drag: none">
|
||||
<div style="position: absolute; width: 512px; left: 0; right: 0; margin: auto; -moz-user-select: text; -o-user-select: text; -webkit-user-select: text">
|
||||
<div style="padding: 16px 0 8px 0; font-weight: bold; font-size: 13px">{{title}}</div>
|
||||
<div>{{description_html|safe}}</div>
|
||||
{% for c in clips %}
|
||||
<div style="clear:both; padding-top: 4px">
|
||||
<img src="/{{id}}/96p{{c.in}}.jpg" alt="" style="float: left; margin-right: 8px">
|
||||
{{c.annotations|safe}}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div style="clear: both; padding-top: 16px; padding-bottom: 16px; font-style: italic">{{settings.SITENAME}} requires JavaScript.</div>
|
||||
</div>
|
||||
</div>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
45
pandora/templates/mobile/index.html
Normal file
45
pandora/templates/mobile/index.html
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>{% load static sass_tags compress %}
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% if title %}
|
||||
<title>{{title}}</title>
|
||||
<meta name="title" content="{{title}}"/>
|
||||
<meta property="og:title" content="{{title}}"/>
|
||||
{% endif %}
|
||||
{%if description %}
|
||||
<meta name="description" content="{{description}}"/>
|
||||
<meta property="og:description" content="{{description}}"/>
|
||||
{%endif%}
|
||||
{% if preview %}
|
||||
<meta content="{{ preview }}" name="thumbnail"/>
|
||||
<meta content="{{ preview }}" name="image_src"/>
|
||||
<meta property="og:image" content="{{ preview }}"/>
|
||||
{% endif %}
|
||||
{% if url %}
|
||||
<meta property="og:url" content="{{ url }}"/>
|
||||
{% endif %}
|
||||
<meta property="og:site_name" content="{{ settings.SITENAME }}"/>
|
||||
{% compress css file m %}
|
||||
<link rel="stylesheet" href="{% static 'mobile/css/reset.css' %}"></link>
|
||||
<link rel="stylesheet" href="{% static 'mobile/css/style.css' %}"></link>
|
||||
{% endcompress %}
|
||||
<meta name="google" value="notranslate"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content"></div>
|
||||
{% compress js file m %}
|
||||
<script src="{% static 'mobile/js/utils.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/api.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/icons.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/VideoElement.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/VideoPlayer.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/documents.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/edits.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/item.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/render.js' %}"></script>
|
||||
<script src="{% static 'mobile/js/main.js' %}"></script>
|
||||
{% endcompress %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -26,6 +26,7 @@ import edit.views
|
|||
import itemlist.views
|
||||
import item.views
|
||||
import item.site
|
||||
import mobile.views
|
||||
import translation.views
|
||||
import urlalias.views
|
||||
|
||||
|
|
@ -47,6 +48,7 @@ urlpatterns = [
|
|||
re_path(r'^collection/(?P<id>.*?)/icon(?P<size>\d*).jpg$', documentcollection.views.icon),
|
||||
re_path(r'^documents/(?P<id>[A-Z0-9]+)/(?P<size>\d*)p(?P<page>[\d,]*).jpg$', document.views.thumbnail),
|
||||
re_path(r'^documents/(?P<id>[A-Z0-9]+)/(?P<name>.*?\.[^\d]{3})$', document.views.file),
|
||||
re_path(r'^documents/(?P<fragment>.*?)$', document.views.document),
|
||||
re_path(r'^edit/(?P<id>.*?)/icon(?P<size>\d*).jpg$', edit.views.icon),
|
||||
re_path(r'^list/(?P<id>.*?)/icon(?P<size>\d*).jpg$', itemlist.views.icon),
|
||||
re_path(r'^text/(?P<id>.*?)/icon(?P<size>\d*).jpg$', text.views.icon),
|
||||
|
|
@ -65,6 +67,7 @@ urlpatterns = [
|
|||
re_path(r'^robots.txt$', app.views.robots_txt),
|
||||
re_path(r'^sitemap.xml$', item.views.sitemap_xml),
|
||||
re_path(r'^sitemap(?P<part>\d+).xml$', item.views.sitemap_part_xml),
|
||||
re_path(r'm/(?P<fragment>.*?)$', mobile.views.index),
|
||||
path(r'', item.site.urls),
|
||||
]
|
||||
#sould this not be enabled by default? nginx should handle those
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue