From 825fa8b2c67ddc42da44a32964773266fba2959b Mon Sep 17 00:00:00 2001 From: Guillaume Pellerin Date: Thu, 7 May 2015 00:48:42 +0200 Subject: [PATCH] add EPUB3 collection downloader --- .../templates/telemeta/collection_detail.html | 9 +- .../templates/telemeta/collection_epub.html | 24 ----- telemeta/urls.py | 6 +- telemeta/views/collection.py | 25 ++++- telemeta/views/core.py | 93 +++++++++++++++++++ telemeta/views/resource.py | 89 +----------------- 6 files changed, 132 insertions(+), 114 deletions(-) delete mode 100644 telemeta/templates/telemeta/collection_epub.html diff --git a/telemeta/templates/telemeta/collection_detail.html b/telemeta/templates/telemeta/collection_detail.html index d78d03af..c9804fef 100644 --- a/telemeta/templates/telemeta/collection_detail.html +++ b/telemeta/templates/telemeta/collection_detail.html @@ -65,12 +65,19 @@ {% if audio_export_enabled or perms.telemeta.can_download_all_items or user.is_superuser %} - + {% endif %} + {% if user.is_superuser %} + + + + {% endif %} {% endif %} {% endblock %} diff --git a/telemeta/templates/telemeta/collection_epub.html b/telemeta/templates/telemeta/collection_epub.html deleted file mode 100644 index 37020245..00000000 --- a/telemeta/templates/telemeta/collection_epub.html +++ /dev/null @@ -1,24 +0,0 @@ - - -

{{ collection.title }}

- -{% for item in items %} -
-

- Son {{ item.old_code }} : {{ item.title }}. {{ item.comment }} ({{ item.track }}) -

- -
- -
- - {% for image in item.related.all %} - {% if 'image' in image.mime_type %} -
- -
- {% endif %} - {% endfor %} - -
-{% endfor %} diff --git a/telemeta/urls.py b/telemeta/urls.py index 59cc23af..7ebc6a2d 100644 --- a/telemeta/urls.py +++ b/telemeta/urls.py @@ -122,8 +122,10 @@ urlpatterns = patterns('', # FIXME: need all paths url(r'^collections/(?P[A-Za-z0-9._-s/]+)/$', RedirectView.as_view(), {'url': '/archives/collections/%(path)s/', 'permanent': False}, name="telemeta-collection-redir"), - url(r'^archives/collections/(?P[A-Za-z0-9._-]+)/package/$', CollectionPackageView.as_view(), - name="telemeta-collection-package"), + url(r'^archives/collections/(?P[A-Za-z0-9._-]+)/zip/$', CollectionZipView.as_view(), + name="telemeta-collection-zip"), + url(r'^archives/collections/(?P[A-Za-z0-9._-]+)/epub/$', CollectionEpubView.as_view(), + name="telemeta-collection-epub"), # Generic resources url(r'^archives/(?P[A-Za-z0-9._-]+)/$', ResourceListView.as_view(), name="telemeta-resource-list"), diff --git a/telemeta/views/collection.py b/telemeta/views/collection.py index 3365c460..643b1a1d 100644 --- a/telemeta/views/collection.py +++ b/telemeta/views/collection.py @@ -172,7 +172,7 @@ class CollectionView(object): return render(request, template, {'collection': collection, 'formset': formset,}) -class CollectionPackageView(View): +class CollectionZipView(View): model = MediaCollection @@ -230,7 +230,7 @@ class CollectionPackageView(View): @method_decorator(login_required) def dispatch(self, *args, **kwargs): - return super(CollectionPackageView, self).dispatch(*args, **kwargs) + return super(CollectionZipView, self).dispatch(*args, **kwargs) class CollectionViewMixin(object): @@ -372,3 +372,24 @@ class CollectionCopyView(CollectionAddView): return super(CollectionCopyView, self).dispatch(*args, **kwargs) +class CollectionEpubView(BaseEpubMixin, View): + "Download collection data embedded in an EPUB3 file" + + model = MediaCollection + + def get_object(self): + return MediaCollection.objects.get(public_id=self.kwargs['public_id']) + + def get(self, request, *args, **kwargs): + collection = self.get_object() + corpus = collection.corpus.all()[0] + self.write_book(corpus, collection=collection) + epub_file = open(self.path, 'rb') + response = HttpResponse(epub_file.read(), content_type='application/epub+zip') + response['Content-Disposition'] = "attachment; filename=%s" % self.name + return response + + @method_decorator(login_required) + def dispatch(self, *args, **kwargs): + return super(CollectionEpubView, self).dispatch(*args, **kwargs) + diff --git a/telemeta/views/core.py b/telemeta/views/core.py index 28fccc2f..26486c2d 100644 --- a/telemeta/views/core.py +++ b/telemeta/views/core.py @@ -304,3 +304,96 @@ def get_kwargs_or_none(key, kwargs): else: return None + +class BaseEpubMixin(TelemetaBaseMixin): + "Download corpus data embedded in an EPUB3 file" + + abstract = True + local_path = os.path.dirname(__file__) + css = os.sep.join([local_path, '..', 'static', 'telemeta', 'css', 'telemeta_epub.css']) + template = os.sep.join([local_path, '..', 'templates', 'telemeta', 'inc', 'collection_epub.html']) + + def write_book(self, corpus, collection=None, path=None): + from collections import OrderedDict + from ebooklib import epub + from django.template.loader import render_to_string + + self.book = epub.EpubBook() + self.corpus = corpus + site = Site.objects.get_current() + self.chapters = [] + self.name = self.corpus.code + '.epub' + self.path = self.cache_data.dir + os.sep + self.name + + # add metadata + self.book.set_identifier(self.corpus.public_id) + self.book.set_title(self.corpus.title) + self.book.set_language('fr') + self.book.add_author(self.corpus.descriptions) + + # add cover image + for media in self.corpus.related.all(): + if 'cover' in media.title or 'Cover' in media.title: + self.book.set_cover("cover.jpg", open(media.file.path, 'r').read()) + break + + if collection: + self.collections = [collection] + else: + self.collections = self.corpus.children.all() + + for collection in self.collections: + items = {} + for item in collection.items.all(): + if '.' in item.old_code: + id = item.old_code.split('.')[1] + else: + id = item.old_code + for c in id: + if c.isalpha(): + id = id.replace(c, '.' + str(ord(c)-96)) + items[item] = float(id) + items = OrderedDict(sorted(items.items(), key=lambda t: t[1])) + + for item in items: + if item.file: + audio = open(item.file.path, 'r') + filename = str(item.file) + epub_item = epub.EpubItem(file_name=str(item.file), content=audio.read()) + self.book.add_item(epub_item) + for related in item.related.all(): + if 'image' in related.mime_type: + image = open(related.file.path, 'r') + epub_item = epub.EpubItem(file_name=str(related.file), content=image.read()) + self.book.add_item(epub_item) + context = {'collection': collection, 'site': site, 'items': items} + c = epub.EpubHtml(title=collection.title, file_name=collection.code + '.xhtml', lang='fr') + c.content = render_to_string(self.template, context) + self.chapters.append(c) + # add self.chapters to the self.book + self.book.add_item(c) + + # create table of contents + # - add manual link + # - add section + # - add auto created links to chaptersfesse + + self.book.toc = (( self.chapters )) + + # add navigation files + self.book.add_item(epub.EpubNcx()) + self.book.add_item(epub.EpubNav()) + + # add css style + style = open(self.css, 'r') + nav_css = epub.EpubItem(uid="style_nav", file_name="style/nav.css", media_type="text/css", content=style.read()) + self.book.add_item(nav_css) + + # create spin, add cover page as first page + self.chapters.insert(0,'nav') + self.chapters.insert(0,'cover') + self.book.spine = self.chapters + + # write epub file + epub.write_epub(self.path, self.book, {}) + diff --git a/telemeta/views/resource.py b/telemeta/views/resource.py index 1230fcee..bda4bc6a 100644 --- a/telemeta/views/resource.py +++ b/telemeta/views/resource.py @@ -356,7 +356,7 @@ def cleanup_path(path): return os.sep.join(new_path) -class CorpusEpubView(TelemetaBaseMixin, View): +class CorpusEpubView(BaseEpubMixin, View): "Download corpus data embedded in an EPUB3 file" model = MediaCorpus @@ -365,91 +365,10 @@ class CorpusEpubView(TelemetaBaseMixin, View): return MediaCorpus.objects.get(public_id=self.kwargs['public_id']) def get(self, request, *args, **kwargs): - from collections import OrderedDict - from ebooklib import epub - from django.template.loader import render_to_string - - book = epub.EpubBook() - corpus = self.get_object() - local_path = os.path.dirname(__file__) - css = os.sep.join([local_path, '..', 'static', 'telemeta', 'css', 'telemeta_epub.css']) - collection_template = os.sep.join([local_path, '..', 'templates', 'telemeta', 'collection_epub.html']) - site = Site.objects.get_current() - - # add metadata - book.set_identifier(corpus.public_id) - book.set_title(corpus.title) - book.set_language('fr') - book.add_author(corpus.descriptions) - - # add cover image - for media in corpus.related.all(): - if 'cover' in media.title or 'Cover' in media.title: - book.set_cover("cover.jpg", open(media.file.path, 'r').read()) - break - - chapters = [] - for collection in corpus.children.all(): - items = {} - for item in collection.items.all(): - if '.' in item.old_code: - id = item.old_code.split('.')[1] - else: - id = item.old_code - for c in id: - if c.isalpha(): - id = id.replace(c, '.' + str(ord(c)-96)) - items[item] = float(id) - items = OrderedDict(sorted(items.items(), key=lambda t: t[1])) - - for item in items: - if item.file: - audio = open(item.file.path, 'r') - filename = str(item.file) - epub_item = epub.EpubItem(file_name=str(item.file), content=audio.read()) - book.add_item(epub_item) - for related in item.related.all(): - if 'image' in related.mime_type: - image = open(related.file.path, 'r') - epub_item = epub.EpubItem(file_name=str(related.file), content=image.read()) - book.add_item(epub_item) - context = {'collection': collection, 'site': site, 'items': items} - c = epub.EpubHtml(title=collection.title, file_name=collection.code + '.xhtml', lang='fr') - c.content = render_to_string(collection_template, context) - chapters.append(c) - # add chapters to the book - book.add_item(c) - - # create table of contents - # - add manual link - # - add section - # - add auto created links to chaptersfesse - - book.toc = (( chapters )) - - # add navigation files - book.add_item(epub.EpubNcx()) - book.add_item(epub.EpubNav()) - - # add css style - style = open(css, 'r') - nav_css = epub.EpubItem(uid="style_nav", file_name="style/nav.css", media_type="text/css", content=style.read()) - book.add_item(nav_css) - - # create spin, add cover page as first page - chapters.insert(0,'nav') - chapters.insert(0,'cover') - book.spine = chapters - - # create epub file - epub_name = corpus.code + '.epub' - path = self.cache_data.dir + os.sep + epub_name - epub.write_epub(path, book, {}) - epub_file = open(path, 'rb') - + self.write_book(self.get_object()) + epub_file = open(self.path, 'rb') response = HttpResponse(epub_file.read(), content_type='application/epub+zip') - response['Content-Disposition'] = "attachment; filename=%s" % epub_name - + response['Content-Disposition'] = "attachment; filename=%s" % self.name return response @method_decorator(login_required) -- 2.39.5