inital version of scroll view, burger menu, css reset
This commit is contained in:
parent
0508d8cd9a
commit
4faf546335
20 changed files with 438 additions and 42 deletions
9
README.md
Normal file
9
README.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
Getting started:
|
||||||
|
```
|
||||||
|
python3 -m venv venv
|
||||||
|
./venv/bin/pip install -r requirements.txt
|
||||||
|
./manage.py migrate
|
||||||
|
./manage.py load_titles
|
||||||
|
./mange.py runserver
|
||||||
|
```
|
|
@ -143,3 +143,6 @@ STATICFILES_FINDERS = [
|
||||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
|
||||||
|
TIMELINE_PREFIX = "https://aab21.pad.ma/"
|
||||||
|
|
34
app/static/css/partials/_ascroll.scss
Normal file
34
app/static/css/partials/_ascroll.scss
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ascroll {
|
||||||
|
font-family: "Noton Sans";
|
||||||
|
width: 100vw;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 4px;
|
||||||
|
margin-top: 32px;
|
||||||
|
margin-bottom: 64px;
|
||||||
|
font-size: 24px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.player {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
width: 100vw;
|
||||||
|
height: auto;
|
||||||
|
//transition: opacity 0.4s;
|
||||||
|
|
||||||
|
}
|
||||||
|
.annotation {
|
||||||
|
.frame {
|
||||||
|
img {
|
||||||
|
width: 100vw;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
margin: 20px 20px;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
app/static/css/partials/_layout.scss
Normal file
18
app/static/css/partials/_layout.scss
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
body {
|
||||||
|
background: #d3d;
|
||||||
|
color: #eee;
|
||||||
|
font-family: "Noto Sans";
|
||||||
|
font-size: 20px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
line-height: 1.2em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
48
app/static/css/partials/_reset.scss
Normal file
48
app/static/css/partials/_reset.scss
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
53
app/static/css/partials/burger.scss
Normal file
53
app/static/css/partials/burger.scss
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
.topnav {
|
||||||
|
background-color: #333;
|
||||||
|
position: relative;
|
||||||
|
height: 72px;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-top: 16px;
|
||||||
|
@media screen and (max-width: 799px) {
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 100;
|
||||||
|
height: initial;
|
||||||
|
padding-left: initial;
|
||||||
|
padding-top: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: block;
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 16px;
|
||||||
|
@media screen and (max-width: 799px) {
|
||||||
|
display: none;
|
||||||
|
text-align: initial;
|
||||||
|
margin-right: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 17px;
|
||||||
|
@media screen and (max-width: 799px) {
|
||||||
|
padding: 14px 16px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon {
|
||||||
|
display: none;
|
||||||
|
@media screen and (max-width: 799px) {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,12 +1,4 @@
|
||||||
body {
|
@import "partials/reset";
|
||||||
background: #000;
|
@import "partials/layout";
|
||||||
color: #fff;
|
@import "partials/burger";
|
||||||
font-family: "Noto Sans";
|
@import "partials/ascroll";
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav {
|
|
||||||
a {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
121
app/static/js/ascroll.js
Normal file
121
app/static/js/ascroll.js
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
var cache = cache || {}
|
||||||
|
var layer = 'descriptions'
|
||||||
|
var baseURL = 'https://pad.ma'
|
||||||
|
var imageResolution = 480
|
||||||
|
|
||||||
|
let lastKnownScrollPosition = 0
|
||||||
|
let ticking = false;
|
||||||
|
|
||||||
|
|
||||||
|
async function pandoraAPI(action, data) {
|
||||||
|
var url = baseURL + '/api/'
|
||||||
|
//var url = '/pandoraAPI/'
|
||||||
|
var key = JSON.stringify([action, data])
|
||||||
|
if (!cache[key]) {
|
||||||
|
var response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: JSON.stringify({
|
||||||
|
action: action,
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
cache[key] = await response.json()
|
||||||
|
}
|
||||||
|
return cache[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlayerPosition(video, lastKnownScrollPosition) {
|
||||||
|
console.log('update', lastKnownScrollPosition)
|
||||||
|
video.style.top = lastKnownScrollPosition + 'px'
|
||||||
|
video.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlayer(video, frame, currentTime) {
|
||||||
|
var rect = frame.getBoundingClientRect();
|
||||||
|
video.style.opacity = 0
|
||||||
|
console.log('update player', rect)
|
||||||
|
video.style.top = (rect.top + window.scrollY) + 'px'
|
||||||
|
video.style.display = 'block';
|
||||||
|
//video.poster = frame.querySelector('img').src
|
||||||
|
video.currentTime = currentTime
|
||||||
|
video.controls = true
|
||||||
|
video.play()
|
||||||
|
video.style.opacity = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function isElementInViewport (el) {
|
||||||
|
var rect = el.getBoundingClientRect();
|
||||||
|
return (
|
||||||
|
rect.top >= 0 &&
|
||||||
|
rect.left >= 0 &&
|
||||||
|
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /* or $(window).height() */
|
||||||
|
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onVisibilityChange(el, callback) {
|
||||||
|
var old_visible;
|
||||||
|
return function () {
|
||||||
|
var visible = isElementInViewport(el);
|
||||||
|
if (visible != old_visible) {
|
||||||
|
old_visible = visible;
|
||||||
|
if (typeof callback == 'function') {
|
||||||
|
callback(visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pandoraAPI('get', {id: film.id, keys: ['id', 'title', 'layers']}).then(response => {
|
||||||
|
var ascroll = document.querySelector('#ascroll')
|
||||||
|
var loaded = false
|
||||||
|
|
||||||
|
var video = document.createElement('video')
|
||||||
|
video.classList.add('player')
|
||||||
|
video.muted = true
|
||||||
|
video.src = `${baseURL}/${film.id}/480p.webm`
|
||||||
|
ascroll.appendChild(video)
|
||||||
|
|
||||||
|
var h1 = document.createElement('h1')
|
||||||
|
h1.innerHTML = response.data.title
|
||||||
|
ascroll.appendChild(h1)
|
||||||
|
|
||||||
|
response.data.layers[layer].forEach(annotation => {
|
||||||
|
var div = document.createElement('div')
|
||||||
|
div.classList.add('annotation')
|
||||||
|
div.innerHTML = `
|
||||||
|
<div class="frame"><img src="${baseURL}/${annotation.id.split('/')[0]}/${imageResolution}p${annotation.in}.jpg"></div>
|
||||||
|
<div class="text">${annotation.value}</div>
|
||||||
|
|
||||||
|
`
|
||||||
|
ascroll.appendChild(div)
|
||||||
|
var frame = div.querySelector('.frame')
|
||||||
|
document.addEventListener('scroll', onVisibilityChange(div.querySelector('.frame'), function(visible) {
|
||||||
|
if (loaded && visible)
|
||||||
|
updatePlayer(video, frame, annotation['in'])
|
||||||
|
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
loaded = true
|
||||||
|
let frame = ascroll.querySelector('.annotation .frame')
|
||||||
|
if (frame) {
|
||||||
|
updatePlayer(video, frame, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
document.addEventListener('scroll', function(e) {
|
||||||
|
lastKnownScrollPosition = window.scrollY;
|
||||||
|
|
||||||
|
if (!ticking) {
|
||||||
|
window.requestAnimationFrame(function() {
|
||||||
|
updatePlayerPosition(video, lastKnownScrollPosition);
|
||||||
|
ticking = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
ticking = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
})
|
|
@ -12,21 +12,36 @@
|
||||||
{% block head %}{% endblock head %}
|
{% block head %}{% endblock head %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>
|
<div class="topnav">
|
||||||
phtantasmapolis: Looking Back to the Future
|
<a href="/" class="active">
|
||||||
<br>
|
phtantasmapolis: Looking Back to the Future
|
||||||
未竟之城:回顧未來
|
<br>
|
||||||
</h1>
|
未竟之城:回顧未來
|
||||||
<nav>
|
</a>
|
||||||
<a href="{% url 'films'%}">films - 影片</a> |
|
<nav>
|
||||||
<a href="{% url 'edits' %}">edits - 編輯</a> |
|
<a href="{% url 'films'%}">films - 影片</a>
|
||||||
<a href="{% url 'tv' %}">tv - 頻道</a> |
|
<a href="{% url 'edits' %}">edits - 編輯</a>
|
||||||
<a href="{% url 'essays' %}">essays - 專文</a> |
|
<a href="{% url 'tv' %}">tv - 頻道</a>
|
||||||
<a href="{% url 'about' %}">about - 關於</a>
|
<a href="{% url 'essays' %}">essays - 專文</a>
|
||||||
</nav>
|
<a href="{% url 'about' %}">about - 關於</a>
|
||||||
|
</nav>
|
||||||
|
<a class="icon">
|
||||||
|
<svg height="32px" style="enable-background:new 0 0 32 32;" version="1.1" viewBox="0 0 32 32" width="32px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M4,10h24c1.104,0,2-0.896,2-2s-0.896-2-2-2H4C2.896,6,2,6.896,2,8S2.896,10,4,10z M28,14H4c-1.104,0-2,0.896-2,2 s0.896,2,2,2h24c1.104,0,2-0.896,2-2S29.104,14,28,14z M28,22H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h24c1.104,0,2-0.896,2-2 S29.104,22,28,22z"/></svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<main>
|
<main>
|
||||||
{% block main %}{% endblock main %}
|
{% block main %}{% endblock main %}
|
||||||
</main>
|
</main>
|
||||||
{% block end %}{% endblock end %}
|
{% block end %}{% endblock end %}
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll(".topnav a.icon").forEach(a => {
|
||||||
|
a.onclick = (event) => {
|
||||||
|
var nav = document.querySelector('.topnav nav')
|
||||||
|
nav.style.display = nav.style.display === 'block' ? 'none' : 'block'
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
<video src="https://aab21.pad.ma/{{ film.padma_id }}/loop.mp4" autoplay loop muted></video>
|
<video src="{{ settings.TIMELINE_PREFIX }}{{ film.padma_id }}/loop.mp4" autoplay loop muted></video>
|
||||||
|
|
||||||
<h1>{{ film.data.title | safe }}</h1>
|
<h1>{{ film.data.title | safe }}</h1>
|
||||||
<h2>{{ film.data.director|join:", "|safe }}</h2>
|
<h2>{{ film.data.director|join:", "|safe }}</h2>
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<h1>{{ film.data.title }}</h1>
|
<div id="ascroll"></div>
|
||||||
{% if film.vimeo_id %}
|
{% endblock %}
|
||||||
<iframe src="https://player.vimeo.com/video/{{ film.vimeo_id }}" width="640" height="564" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>
|
{% block end %}
|
||||||
{% endif %}
|
<script>
|
||||||
|
var film = {
|
||||||
|
id: "{{ film.padma_id }}",
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="/static/js/ascroll.js"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
some overview page with stuff
|
|
||||||
{% for film in films %}
|
{% for film in films %}
|
||||||
<div class="film">
|
<div class="film">
|
||||||
<a href="{% url 'film' film.slug %}">{{ film.data.title | safe }}</a>
|
<a href="{% url 'film' film.slug %}">{{ film.data.title | safe }}</a>
|
||||||
<span>{{ film.data.director|join:", "|safe }}</span>
|
<span>{{ film.data.director|join:", "|safe }}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -15,7 +15,7 @@ def essays(request):
|
||||||
context['essays'] = models.Essay.objects.filter(public=True).order_by('created')
|
context['essays'] = models.Essay.objects.filter(public=True).order_by('created')
|
||||||
return render(request, 'essays.html', context)
|
return render(request, 'essays.html', context)
|
||||||
|
|
||||||
def essay(request, slug):
|
def essay(request, slug, lang):
|
||||||
context = {}
|
context = {}
|
||||||
context['essay'] = get_object_or_404(models.Essay, slug=slug)
|
context['essay'] = get_object_or_404(models.Essay, slug=slug)
|
||||||
return render(request, 'essay.html', context)
|
return render(request, 'essay.html', context)
|
||||||
|
|
|
@ -21,15 +21,17 @@ from .text import views as text
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
|
#path('pandoraAPI/', video.pandoraAPI, name='pandoraAPI'),
|
||||||
path('films/', video.films, name='films'),
|
path('films/', video.films, name='films'),
|
||||||
path('film/<str:slug>/play', video.film_play, name='film_play'),
|
path('film/<str:slug>/play/<str:lang>', video.film_play, name='film_play'),
|
||||||
path('film/<str:slug>/', video.film, name='film'),
|
path('film/<str:slug>/', video.film, name='film'),
|
||||||
path('edits/', video.edits, name='edits'),
|
path('edits/', video.edits, name='edits'),
|
||||||
path('edit/<str:slug>/play', video.edit_play, name='edit_play'),
|
path('edit/<str:slug>/play/<str:lang>', video.edit_play, name='edit_play'),
|
||||||
path('edit/<str:slug>/', video.edit, name='edit'),
|
path('edit/<str:slug>/', video.edit, name='edit'),
|
||||||
path('tv/', video.tv, name='tv'),
|
path('tv/', video.tv, name='tv'),
|
||||||
path('essays/', text.essays, name='essays'),
|
path('essays/', text.essays, name='essays'),
|
||||||
path('essay/<str:slug>/', text.essay, name='essay'),
|
path('essay/<str:slug>/<str:lang>', text.essay, name='essay'),
|
||||||
path('about/', text.about, name='about'),
|
path('about/', text.about, name='about'),
|
||||||
|
|
||||||
path('', text.index, name='index'),
|
path('', text.index, name='index'),
|
||||||
]
|
]
|
||||||
|
|
18
app/user/migrations/0002_alter_user_data.py
Normal file
18
app/user/migrations/0002_alter_user_data.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.7 on 2021-09-30 15:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('user', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='user',
|
||||||
|
name='data',
|
||||||
|
field=models.JSONField(blank=True, default=dict, editable=False),
|
||||||
|
),
|
||||||
|
]
|
23
app/video/migrations/0002_auto_20210930_1527.py
Normal file
23
app/video/migrations/0002_auto_20210930_1527.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.7 on 2021-09-30 15:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('video', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='edit',
|
||||||
|
name='data',
|
||||||
|
field=models.JSONField(blank=True, default=dict),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='film',
|
||||||
|
name='data',
|
||||||
|
field=models.JSONField(blank=True, default=dict),
|
||||||
|
),
|
||||||
|
]
|
39
app/video/utils.py
Normal file
39
app/video/utils.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import datetime
|
||||||
|
from django.utils import datetime_safe
|
||||||
|
from django.http import HttpResponse, Http404
|
||||||
|
import json
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
def json_response(data=None, status=200, text='ok'):
|
||||||
|
if not data:
|
||||||
|
data = {}
|
||||||
|
return {'status': {'code': status, 'text': text}, 'data': data}
|
||||||
|
|
||||||
|
def _to_json(python_object):
|
||||||
|
if isinstance(python_object, datetime.datetime):
|
||||||
|
if python_object.year < 1900:
|
||||||
|
tt = python_object.timetuple()
|
||||||
|
return '%d-%02d-%02dT%02d:%02d%02dZ' % tuple(list(tt)[:6])
|
||||||
|
return python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
if isinstance(python_object, datetime_safe.datetime):
|
||||||
|
return python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
raise TypeError('%s %s is not JSON serializable' % (repr(python_object), type(python_object)))
|
||||||
|
|
||||||
|
def json_dump(data, fp, indent=4):
|
||||||
|
return json.dump(data, fp, indent=indent, default=_to_json, ensure_ascii=False)
|
||||||
|
|
||||||
|
def json_dumps(data, indent=4):
|
||||||
|
return json.dumps(data, indent=indent, default=_to_json, ensure_ascii=False)
|
||||||
|
|
||||||
|
def render_to_json_response(dictionary, content_type="application/json", status=200):
|
||||||
|
indent = None
|
||||||
|
if settings.DEBUG:
|
||||||
|
content_type = "text/javascript"
|
||||||
|
indent = 2
|
||||||
|
if getattr(settings, 'JSON_DEBUG', False):
|
||||||
|
print(json_dumps(dictionary, indent=2).encode('utf-8'))
|
||||||
|
response = json_dumps(dictionary, indent=indent)
|
||||||
|
if not isinstance(response, bytes):
|
||||||
|
response = response.encode('utf-8')
|
||||||
|
return HttpResponse(response, content_type=content_type, status=status)
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
def films(request):
|
def films(request):
|
||||||
context = {}
|
context = {}
|
||||||
context['films'] = models.Film.objects.filter(public=True).order_by('created')
|
context['films'] = models.Film.objects.filter(public=True).order_by('data__title')
|
||||||
return render(request, 'films.html', context)
|
return render(request, 'films.html', context)
|
||||||
|
|
||||||
def film(request, slug):
|
def film(request, slug):
|
||||||
|
@ -12,9 +14,10 @@ def film(request, slug):
|
||||||
context['film'] = get_object_or_404(models.Film, slug=slug)
|
context['film'] = get_object_or_404(models.Film, slug=slug)
|
||||||
return render(request, 'film.html', context)
|
return render(request, 'film.html', context)
|
||||||
|
|
||||||
def film_play(request, slug):
|
def film_play(request, slug, lang):
|
||||||
context = {}
|
context = {}
|
||||||
context['film'] = get_object_or_404(models.Film, slug=slug)
|
context['film'] = get_object_or_404(models.Film, slug=slug)
|
||||||
|
context['lang'] = lang
|
||||||
return render(request, 'film_play.html', context)
|
return render(request, 'film_play.html', context)
|
||||||
|
|
||||||
def edits(request):
|
def edits(request):
|
||||||
|
@ -27,11 +30,26 @@ def edit(request, slug):
|
||||||
context['edit'] = get_object_or_404(models.Edit, slug=slug)
|
context['edit'] = get_object_or_404(models.Edit, slug=slug)
|
||||||
return render(request, 'edit.html', context)
|
return render(request, 'edit.html', context)
|
||||||
|
|
||||||
def edit_play(request, slug):
|
def edit_play(request, slug, lang):
|
||||||
context = {}
|
context = {}
|
||||||
context['edit'] = get_object_or_404(models.Edit, slug=slug)
|
context['edit'] = get_object_or_404(models.Edit, slug=slug)
|
||||||
|
context['lang'] = lang
|
||||||
return render(request, 'edit_play.html', context)
|
return render(request, 'edit_play.html', context)
|
||||||
|
|
||||||
def tv(request):
|
def tv(request):
|
||||||
context = {}
|
context = {}
|
||||||
return render(request, 'tv.html', context)
|
return render(request, 'tv.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@csrf_exempt
|
||||||
|
def pandoraAPI(request):
|
||||||
|
import ox
|
||||||
|
from .utils import render_to_json_response
|
||||||
|
import json
|
||||||
|
data = json.loads(request.body.decode())
|
||||||
|
print('pandora request', data)
|
||||||
|
api = ox.api.signin('https://pad.ma/api/')
|
||||||
|
data = getattr(api, data['action'])(**data['data'])
|
||||||
|
print('response', data)
|
||||||
|
return render_to_json_response(data)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
"""Django's command-line utility for administrative tasks."""
|
"""Django's command-line utility for administrative tasks."""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
Django
|
Django
|
||||||
psycopg2
|
|
||||||
libsass
|
libsass
|
||||||
django-sass-processor
|
django-compressor
|
||||||
django-sass-processor
|
django-sass-processor
|
||||||
|
|
||||||
ox
|
ox
|
||||||
|
|
Loading…
Reference in a new issue