cleaning around ebooks
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 16 Dec 2011 15:36:38 +0000 (16:36 +0100)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 16 Dec 2011 15:46:04 +0000 (16:46 +0100)
apps/api/handlers.py
apps/catalogue/forms.py
apps/catalogue/management/commands/importbooks.py
apps/catalogue/management/commands/pack.py
apps/catalogue/models.py
apps/catalogue/views.py
wolnelektury/settings.py
wolnelektury/templates/catalogue/book_detail.html

index f83a492..e10a4b5 100644 (file)
@@ -93,7 +93,7 @@ class BookDetailHandler(BaseHandler):
 
     """
     allowed_methods = ['GET']
-    fields = ['title', 'parent'] + Book.file_types + [
+    fields = ['title', 'parent'] + Book.formats + [
         'media', 'url'] + category_singular.keys()
 
     @piwik_track
@@ -205,7 +205,7 @@ def _file_getter(format):
         else:
             return ''
     return get_file
-for format in Book.file_types:
+for format in Book.formats:
     setattr(BooksHandler, format, _file_getter(format))
 
 
@@ -364,8 +364,7 @@ class CatalogueHandler(BaseHandler):
     def book_dict(book, fields=None):
         all_fields = ['url', 'title', 'description',
                       'gazeta_link', 'wiki_link',
-                      ] + Book.file_types + [
-                      'mp3', 'ogg', 'daisy',
+                      ] + Book.formats + BookMedia.formats + [
                       'parent', 'parent_number',
                       'tags',
                       'license', 'license_description', 'source_name',
@@ -382,7 +381,7 @@ class CatalogueHandler(BaseHandler):
         obj = {}
         for field in fields:
 
-            if field in Book.file_types:
+            if field in Book.formats:
                 f = getattr(book, field+'_file')
                 if f:
                     obj[field] = {
@@ -390,7 +389,7 @@ class CatalogueHandler(BaseHandler):
                         'size': f.size,
                     }
 
-            elif field in ('mp3', 'ogg', 'daisy'):
+            elif field in BookMedia.formats:
                 media = []
                 for m in book.media.filter(type=field):
                     media.append({
index 094aaaf..852513a 100644 (file)
@@ -78,20 +78,12 @@ class NewSetForm(forms.Form):
         return new_set
 
 
-FORMATS = (
-    ('mp3', 'MP3'),
-    ('ogg', 'OGG'),
-    ('pdf', 'PDF'),
-    ('odt', 'ODT'),
-    ('txt', 'TXT'),
-    ('epub', 'EPUB'),
-    ('daisy', 'DAISY'),
-    ('mobi', 'MOBI'),
-)
+FORMATS = [(f, f.upper()) for f in Book.ebook_formats]
 
 
 class DownloadFormatsForm(forms.Form):
-    formats = forms.MultipleChoiceField(required=False, choices=FORMATS, widget=forms.CheckboxSelectMultiple)
+    formats = forms.MultipleChoiceField(required=False, choices=FORMATS,
+            widget=forms.CheckboxSelectMultiple)
 
     def __init__(self, *args, **kwargs):
          super(DownloadFormatsForm, self).__init__(*args, **kwargs)
index ecd3fcc..24356cc 100644 (file)
@@ -90,22 +90,13 @@ class Command(BaseCommand):
                                                   build_mobi=options.get('build_mobi'))
                         files_imported += 1
 
-                        if os.path.isfile(file_base + '.pdf'):
-                            book.pdf_file.save('%s.pdf' % book.slug, File(file(file_base + '.pdf')))
-                            if verbose:
-                                print "Importing %s.pdf" % file_base
-                        if os.path.isfile(file_base + '.mobi'):
-                            book.mobi_file.save('%s.mobi' % book.slug, File(file(file_base + '.mobi')))
-                            if verbose:
-                                print "Importing %s.mobi" % file_base
-                        if os.path.isfile(file_base + '.epub'):
-                            book.epub_file.save('%s.epub' % book.slug, File(file(file_base + '.epub')))
-                            if verbose:
-                                print "Importing %s.epub" % file_base
-                        if os.path.isfile(file_base + '.txt'):
-                            book.txt_file.save('%s.txt' % book.slug, File(file(file_base + '.txt')))
-                            if verbose:
-                                print "Importing %s.txt" % file_base
+                        for ebook_format in Book.ebook_formats:
+                            if os.path.isfile(file_base + '.' + ebook_format):
+                                getattr(book, '%s_file' % ebook_format).save(
+                                    '%s.%s' % (book.slug, ebook_format), 
+                                    File(file(file_base + '.' + ebook_format)))
+                                if verbose:
+                                    print "Importing %s.%s" % (file_base, ebook_format)
 
                         book.save()
 
index c75f092..280c0f6 100755 (executable)
@@ -23,7 +23,7 @@ class Command(BaseCommand):
         make_option('-e', '--exclude', dest='exclude', metavar='SLUG,...',
             help='Exclude specific books by slug')
     )
-    help = 'Prepare data for Lesmianator.'
+    help = 'Prepare ZIP package with files of given type.'
     args = '[%s] output_path.zip' % '|'.join(ftypes)
 
     def handle(self, ftype, path, **options):
@@ -33,7 +33,7 @@ class Command(BaseCommand):
         include = options.get('include')
         exclude = options.get('exclude')
 
-        if ftype in Book.file_types:
+        if ftype in Book.formats:
             field = "%s_file" % ftype
         else:
             print self.style.ERROR('Unknown file type.')
index a5b0ebf..3fd80ef 100644 (file)
@@ -2,6 +2,7 @@
 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
+from collections import namedtuple
 from datetime import datetime
 
 from django.db import models
@@ -40,13 +41,6 @@ TAG_CATEGORIES = (
     ('book', _('book')),
 )
 
-MEDIA_FORMATS = (
-    ('odt', _('ODT file')),
-    ('mp3', _('MP3 file')),
-    ('ogg', _('OGG file')),
-    ('daisy', _('DAISY file')), 
-)
-
 # not quite, but Django wants you to set a timeout
 CACHE_FOREVER = 2419200  # 28 days
 
@@ -180,10 +174,8 @@ def get_dynamic_path(media, filename, ext=None, maxlen=100):
 
     # how to put related book's slug here?
     if not ext:
-        if media.type == 'daisy':
-            ext = 'daisy.zip'
-        else:
-            ext = media.type
+        # BookMedia case
+        ext = media.formats[media.type].ext
     if media is None or not media.name:
         name = slughifi(filename.split(".")[0])
     else:
@@ -220,7 +212,16 @@ def get_existing_customized_pdf(book):
 
 
 class BookMedia(models.Model):
-    type        = models.CharField(_('type'), choices=MEDIA_FORMATS, max_length="100")
+    FileFormat = namedtuple("FileFormat", "name ext")
+    formats = SortedDict([
+        ('mp3', FileFormat(name='MP3', ext='mp3')),
+        ('ogg', FileFormat(name='Ogg Vorbis', ext='ogg')),
+        ('daisy', FileFormat(name='DAISY', ext='daisy.zip')),
+    ])
+    format_choices = [(k, _('%s file') % t.name)
+            for k, t in formats.items()]
+
+    type        = models.CharField(_('type'), choices=format_choices, max_length="100")
     name        = models.CharField(_('name'), max_length="100")
     file        = OverwritingFileField(_('file'), upload_to=book_upload_path())
     uploaded_at = models.DateTimeField(_('creation date'), auto_now_add=True, editable=False)
@@ -333,8 +334,9 @@ class Book(models.Model):
     wiki_link     = models.CharField(blank=True, max_length=240)
     # files generated during publication
 
-    file_types = ['epub', 'html', 'mobi', 'pdf', 'txt', 'xml']
-    
+    ebook_formats = ['pdf', 'epub', 'mobi', 'txt']
+    formats = ebook_formats + ['html', 'xml']
+
     parent        = models.ForeignKey('self', blank=True, null=True, related_name='children')
     objects  = models.Manager()
     tagged   = managers.ModelTaggedItemManager(Tag)
@@ -431,14 +433,14 @@ class Book(models.Model):
         return book_tag
 
     def has_media(self, type):
-        if type in Book.file_types:
+        if type in Book.formats:
             return bool(getattr(self, "%s_file" % type))
         else:
             return self.media.filter(type=type).exists()
 
     def get_media(self, type):
         if self.has_media(type):
-            if type in Book.file_types:
+            if type in Book.formats:
                 return getattr(self, "%s_file" % type)
             else:                                             
                 return self.media.filter(type=type)
@@ -482,14 +484,12 @@ class Book(models.Model):
             # files generated during publication
             if self.has_media("html"):
                 formats.append(u'<a href="%s">%s</a>' % (reverse('book_text', args=[self.fileid()]), _('Read online')))
-            if self.has_media("pdf"):
-                formats.append(u'<a href="%s">PDF</a>' % self.get_media('pdf').url)
-            if self.has_media("mobi"):
-                formats.append(u'<a href="%s">MOBI</a>' % self.get_media('mobi').url)
-            if self.root_ancestor.has_media("epub"):
-                formats.append(u'<a href="%s">EPUB</a>' % self.root_ancestor.get_media('epub').url)
-            if self.has_media("txt"):
-                formats.append(u'<a href="%s">TXT</a>' % self.get_media('txt').url)
+            for ebook_format in self.ebook_formats:
+                if self.has_media(ebook_format):
+                    formats.append(u'<a href="%s">%s</a>' % (
+                        self.get_media(ebook_format).url,
+                        ebook_format.upper()
+                    ))
             # other files
             for m in self.media.order_by('type'):
                 formats.append(u'<a href="%s">%s</a>' % (m.file.url, m.type.upper()))
@@ -520,29 +520,12 @@ class Book(models.Model):
                 cache.set(cache_key, short_html, CACHE_FOREVER)
         return mark_safe(short_html)
 
-    @property
-    def root_ancestor(self):
-        """ returns the oldest ancestor """
-
-        if not hasattr(self, '_root_ancestor'):
-            book = self
-            while book.parent:
-                book = book.parent
-            self._root_ancestor = book
-        return self._root_ancestor
-
-
     def has_description(self):
         return len(self.description) > 0
     has_description.short_description = _('description')
     has_description.boolean = True
 
     # ugly ugly ugly
-    def has_odt_file(self):
-        return bool(self.has_media("odt"))
-    has_odt_file.short_description = 'ODT'
-    has_odt_file.boolean = True
-
     def has_mp3_file(self):
         return bool(self.has_media("mp3"))
     has_mp3_file.short_description = 'MP3'
@@ -609,34 +592,15 @@ class Book(models.Model):
         # remove zip with all mobi files
         remove_zip(settings.ALL_MOBI_ZIP)
 
-    def build_epub(self, remove_descendants=True):
-        """ (Re)builds the epub file.
-            If book has a parent, does nothing.
-            Unless remove_descendants is False, descendants' epubs are removed.
-        """
+    def build_epub(self):
+        """(Re)builds the epub file."""
         from django.core.files import File
         from catalogue.utils import remove_zip
 
-        if self.parent:
-            # don't need an epub
-            return
-
         epub = self.wldocument().as_epub()
 
-        try:
-            epub.transform(ORMDocProvider(self), self.fileid(), output_file=epub_file)
-            self.epub_file.save('%s.epub' % self.fileid(), File(open(epub.get_filename())))
-        except NoDublinCore:
-            pass
-
-        book_descendants = list(self.children.all())
-        while len(book_descendants) > 0:
-            child_book = book_descendants.pop(0)
-            if remove_descendants and child_book.has_epub_file():
-                child_book.epub_file.delete()
-            # save anyway, to refresh short_html
-            child_book.save()
-            book_descendants += list(child_book.children.all())
+        self.epub_file.save('%s.epub' % self.fileid(),
+                File(open(epub.get_filename())))
 
         # remove zip package with all epub files
         remove_zip(settings.ALL_EPUB_ZIP)
@@ -822,17 +786,16 @@ class Book(models.Model):
                 book.build_txt()
 
         if not settings.NO_BUILD_EPUB and build_epub:
-            book.root_ancestor.build_epub()
+            book.build_epub()
 
         if not settings.NO_BUILD_PDF and build_pdf:
-            book.root_ancestor.build_pdf()
+            book.build_pdf()
 
         if not settings.NO_BUILD_MOBI and build_mobi:
             book.build_mobi()
 
         book_descendants = list(book.children.all())
         # add l-tag to descendants and their fragments
-        # delete unnecessary EPUB files
         while len(book_descendants) > 0:
             child_book = book_descendants.pop(0)
             child_book.tags = list(child_book.tags) + [book_tag]
@@ -1002,7 +965,7 @@ def _has_factory(ftype):
 
     
 # add the file fields
-for t in Book.file_types:
+for t in Book.formats:
     field_name = "%s_file" % t
     models.FileField(_("%s file" % t.upper()),
             upload_to=book_upload_path(t),
index 3a0e04a..e6e5eb9 100644 (file)
@@ -593,32 +593,18 @@ def download_shelf(request, slug):
     if form.is_valid():
         formats = form.cleaned_data['formats']
     if len(formats) == 0:
-        formats = ['pdf', 'epub', 'mobi', 'odt', 'txt']
+        formats = models.Book.ebook_formats
 
     # Create a ZIP archive
     temp = tempfile.TemporaryFile()
     archive = zipfile.ZipFile(temp, 'w')
 
-    already = set()
     for book in collect_books(models.Book.tagged.with_all(shelf)):
         fileid = book.fileid()
-        if 'pdf' in formats and book.pdf_file:
-            filename = book.pdf_file.path
-            archive.write(filename, str('%s.pdf' % fileid))
-        if 'mobi' in formats and book.mobi_file:
-            filename = book.mobi_file.path
-            archive.write(filename, str('%s.mobi' % fileid))
-        if book.root_ancestor not in already and 'epub' in formats and book.root_ancestor.epub_file:
-            filename = book.root_ancestor.epub_file.path
-            archive.write(filename, str('%s.epub' % book.root_ancestor.fileid()))
-            already.add(book.root_ancestor)
-        if 'odt' in formats and book.has_media("odt"):
-            for file in book.get_media("odt"):
-                filename = file.file.path
-                archive.write(filename, str('%s.odt' % slughifi(file.name)))
-        if 'txt' in formats and book.txt_file:
-            filename = book.txt_file.path
-            archive.write(filename, str('%s.txt' % fileid))
+        for ebook_format in models.Book.ebook_formats:
+            if ebook_format in formats and book.has_media(ebook_format):
+                filename = book.get_media(ebook_format).path
+                archive.write(filename, str('%s.%s' % (fileid, ebook_format)))
     archive.close()
 
     response = HttpResponse(content_type='application/zip', mimetype='application/x-zip-compressed')
@@ -637,20 +623,14 @@ def shelf_book_formats(request, shelf):
     """
     shelf = get_object_or_404(models.Tag, slug=shelf, category='set')
 
-    formats = {'pdf': False, 'epub': False, 'mobi': False, 'odt': False, 'txt': False}
+    formats = {}
+    for ebook_format in models.Book.ebook_formats:
+        formats[ebook_format] = False
 
     for book in collect_books(models.Book.tagged.with_all(shelf)):
-        if book.pdf_file:
-            formats['pdf'] = True
-        if book.root_ancestor.epub_file:
-            formats['epub'] = True
-        if book.mobi_file:
-            formats['mobi'] = True
-        if book.txt_file:
-            formats['txt'] = True
-        for format in ('odt',):
-            if book.has_media(format):
-                formats[format] = True
+        for ebook_format in models.Book.ebook_formats:
+            if book.has_media(ebook_format):
+                formats[ebook_format] = True
 
     return HttpResponse(LazyEncoder().encode(formats))
 
@@ -774,7 +754,7 @@ def download_zip(request, format, book=None):
     kwargs = models.Book.split_fileid(book)
 
     url = None
-    if format in ('pdf', 'epub', 'mobi'):
+    if format in models.Book.ebook_formats:
         url = models.Book.zip_format(format)
     elif format == 'audiobook' and kwargs is not None:
         book = get_object_or_404(models.Book, **kwargs)
index ed63a1d..bd4e8a0 100644 (file)
@@ -180,12 +180,12 @@ COMPRESS_CSS = {
 }
 
 COMPRESS_JS = {
-    'jquery': {
-        #'source_filenames': ('js/jquery.js',),
-        'source_filenames': [],
-        'output_filename': 'js/jquery.min.js',
-    },
-    'all': {
+    #~ 'jquery': {
+        #~ #'source_filenames': ('js/jquery.js',),
+        #~ 'source_filenames': [],
+        #~ 'output_filename': 'js/jquery.min.js',
+    #~ },
+    #~ 'all': {
         #~ 'source_filenames': ('js/jquery.autocomplete.js', 'js/jquery.form.js',
             #~ 'js/jquery.countdown.js', 'js/jquery.countdown-pl.js',
             #~ 'js/jquery.countdown-de.js', 'js/jquery.countdown-uk.js',
@@ -194,19 +194,19 @@ COMPRESS_JS = {
             #~ 'js/jquery.cycle.min.js',
             #~ 'js/jquery.jqmodal.js', 'js/jquery.labelify.js', 'js/catalogue.js',
             #~ ),
-        'source_filenames': [],
-        'output_filename': 'js/all?.min.js',
-    },
-    'book': {
+        #~ 'source_filenames': [],
+        #~ 'output_filename': 'js/all?.min.js',
+    #~ },
+    #~ 'book': {
         #~ 'source_filenames': ('js/jquery.eventdelegation.js', 'js/jquery.scrollto.js', 'js/jquery.highlightfade.js', 'js/book.js',),
-        'source_filenames': [],
-        'output_filename': 'js/book?.min.js',
-    },
-    'book_ie': {
+        #~ 'source_filenames': [],
+        #~ 'output_filename': 'js/book?.min.js',
+    #~ },
+    #~ 'book_ie': {
         #~ 'source_filenames': ('js/ierange-m2.js',),
-        'source_filenames': [],
-        'output_filename': 'js/book_ie?.min.js',
-    }
+        #~ 'source_filenames': [],
+        #~ 'output_filename': 'js/book_ie?.min.js',
+    #~ }
 
 }
 
index 2d83c73..c47e217 100644 (file)
@@ -49,8 +49,8 @@
                     {% if book.pdf_file %}
                         <a href="{{ book.pdf_file.url }}"><img src="{{ STATIC_URL }}img/pdf.png" title="{% trans "Download PDF" %} &ndash; {% trans "for reading" %} {% trans "and printing using" %} Adobe Reader" %}" alt="{% trans "Download PDF" %}" /></a>
                     {% endif %}
-                    {% if book.root_ancestor.epub_file %}
-                        <a href="{{ book.root_ancestor.epub_file.url }}"><img src="{{ STATIC_URL }}img/epub.png" title="{% trans "Download EPUB" %} &ndash; {% trans "for reading" %} {% trans "on mobile devices" %}" alt="{% trans "Download EPUB" %}" /></a>
+                    {% if book.epub_file %}
+                        <a href="{{ book.epub_file.url }}"><img src="{{ STATIC_URL }}img/epub.png" title="{% trans "Download EPUB" %} &ndash; {% trans "for reading" %} {% trans "on mobile devices" %}" alt="{% trans "Download EPUB" %}" /></a>
                     {% endif %}
                     {% if book.mobi_file %}
                         <a href="{{ book.mobi_file.url }}"><img src="{{ STATIC_URL }}img/mobi.png" title="{% trans "Download MOBI" %} &ndash; {% trans "for reading" %} {% trans "on mobile devices" %}" alt="{% trans "Download MOBI" %}" /></a>
@@ -58,9 +58,6 @@
                     {% if book.txt_file %}
                         <a href="{{ book.txt_file.url }}"><img src="{{ STATIC_URL }}img/txt.png" title="{% trans "Download TXT" %} &ndash; {% trans "for reading" %} {% trans "on small displays, for example mobile phones" %}" alt="{% trans "Download TXT" %}" /></a>
                     {% endif %}
-                    {% for media in book.get_odt %}
-                        <a href="{{ media.file.url }}"><img src="{{ STATIC_URL }}img/odt.png" title="{% trans "Download ODT" %} &ndash; {% trans "for reading" %} {% trans "and editing using" %} OpenOffice.org: {{ media.name }}" alt="{% trans "Download ODT" %}" /></a>
-                    {% endfor %}
                        
                     {% if book.pdf_file %}
                        <br/><a href="#" id="custom-pdf-link">{% trans "Dowload customized PDF" %}</a>.