polyphonic/library/views.py
2021-03-11 09:32:44 +11:00

217 lines
7.1 KiB
Python

from django.shortcuts import render, redirect, resolve_url
from django.views.generic.detail import DetailView, SingleObjectMixin, View
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, FormView, UpdateView
from django.http import FileResponse, HttpResponse
from django.db import IntegrityError
import json
from interface.views import EnsembleMixin, ProjectMixin
from interface.models import Project
from .models import Work, Document, Part, Playlist, INSTRUMENTS
from . import forms
from .pdf_utils import extract_pages, extract_and_concat
class PlaylistView(ProjectMixin, ListView):
template_name = "library/playlist_view.html"
model = Playlist
def post(self, request, **kwargs):
project = self.get_project()
project_works = project.works.all()
instruments = request.POST.getlist('instruments')
works = request.POST.getlist('works')
self.request.session['part'] = request.POST.get('part', '')
self.request.session['instrument'] = request.POST.get('instrument')
valid_pks = [ x.pk for x in project_works ]
sections = []
for i, pk in enumerate(works):
if int(pk) not in valid_pks:
raise Exception(f"Not a valid work pk: {pk}")
tag = instruments[i]
if tag == '-':
continue
part = Part.objects.filter(tag=tag, doc__work=pk).select_related('doc').get()
sections.append((part.doc.upload.path, part.doc.work.name, part.start, part.end))
result = extract_and_concat(sections)
download_name = f'{project.name}.pdf'
response = FileResponse(result, content_type="application/pdf")
response['Content-Disposition'] = f'inline; filename="{download_name}"'
return response
def get_queryset(self):
return super(PlaylistView, self).get_queryset().select_related('project', 'work')
def get_context_data(self, **kwargs):
data = super(PlaylistView, self).get_context_data(**kwargs)
data['instruments'] = INSTRUMENTS
data['instrument'] = self.request.session.get('instrument', 'Score')
data['part'] = self.request.session.get('part', '0')
return data
class PlaylistManageView(ProjectMixin, ListView):
template_name = "library/playlist_manage.html"
model = Playlist
def post(self, request, **kwargs):
self.request = request
self.kwargs = kwargs
data = json.loads(request.body)
q = self.get_queryset()
for pk, order in data.items():
i = q.filter(pk=pk).update(order=order)
return HttpResponse(status=204)
def get_queryset(self):
return super(PlaylistManageView, self).get_queryset().select_related('project', 'work')
class PlaylistAddView(ProjectMixin, UpdateView):
form_class = forms.PlaylistAddForm
template_name = "interface/default_form.html"
def get_success_url(self):
return resolve_url('playlist_manage', project=self.kwargs['project'])
def get_object(self):
return self.get_project()
class WorkListView(EnsembleMixin, ListView):
def get_queryset(self):
return Work.objects.filter(ensemble=self.request.ensemble_id).order_by('name')
class WorkAddView(EnsembleMixin, FormView):
template_name = "interface/default_form.html"
form_class = forms.WorkCreateForm
def form_valid(self, form):
obj = form.save(commit=False)
obj.ensemble_id = self.request.ensemble_id
try:
obj.save()
except IntegrityError:
form.add_error('name', 'Name must be unique')
return self.form_invalid(form)
# handle the files
uploads = self.request.FILES.getlist('uploads')
docs = []
for f in uploads:
docs.append(obj.docs.create(upload=f).pk)
if len(docs) == 1:
return redirect('document_annotate', docs[0])
else:
return redirect('work_detail', pk=obj.pk)
class WorkDetailView(EnsembleMixin, DetailView):
def get_queryset(self):
return Work.objects.filter(ensemble=self.request.ensemble_id)
class DocumentDetailView(EnsembleMixin, DetailView):
def get_queryset(self):
return Document.objects.filter(work__ensemble=self.request.ensemble_id).select_related('work')
class DocumentAddView(EnsembleMixin, CreateView):
template_name = "interface/default_form.html"
model = Document
fields = ['upload']
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.work_id = self.kwargs['pk']
self.object.save()
return redirect('document_annotate', self.object.pk)
class DocumentDownloadView(EnsembleMixin, SingleObjectMixin, View):
def get(self, request, **args):
self.request = request
self.args = args
self.object = self.get_object()
#response = FileResponse(self.object.upload, content_type="application/pdf")
#return response
return redirect(self.object.upload.url)
def get_queryset(self):
return Document.objects.filter(work__ensemble=self.request.ensemble_id)
class DocumentAnnotateView(EnsembleMixin, DetailView):
template_name = 'library/document_annotate.html'
def post(self, request, **args):
self.request = request
self.args = args
self.object = self.get_object()
data = json.loads(request.body)
tags = {}
for page, tag in data.items():
tags.setdefault(tag, []).append(int(page))
try:
del(tags['None'])
except KeyError:
pass
self.object.parts.all().delete()
for tag, pages in tags.items():
pages.sort()
end = pages[-1] if len(pages) > 1 else None
o = self.object.parts.create(tag=tag, start=pages[0], end=end)
return HttpResponse(status=204)
def get_context_data(self, **kwargs):
data = super(DocumentAnnotateView, self).get_context_data(**kwargs)
pages = {}
for part in data['document'].parts.all():
for i in range(part.start, (part.end or part.start)+1):
pages[i] = part.tag
data['json_data'] = {'pageTags': pages, 'instruments': data['document'].work.instruments}
return data
def get_queryset(self):
return Document.objects.filter(work__ensemble=self.request.ensemble_id).select_related('work')
class PartDownloadView(EnsembleMixin, SingleObjectMixin, View):
def get(self, request, **args):
self.request = request
self.args = args
self.object = self.get_object()
result = extract_pages(self.object.doc.upload.path, self.object.doc.work.name, self.object.start, self.object.end)
download_name = f'{self.object.doc.work.name}_{self.object.instrument}.pdf'
response = FileResponse(result, content_type="application/pdf")
response['Content-Disposition'] = f'inline; filename="foo.pdf"'
return response
def get_queryset(self):
return Part.objects.filter(doc__work__ensemble=self.request.ensemble_id).select_related('doc', 'doc__work')