X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/7e6d14043e3e2dce8e3fdcef0b0fc649680b07b3..f906193db2ec44590f57beae2e8ee2df76117b7b:/apps/catalogue/models.py diff --git a/apps/catalogue/models.py b/apps/catalogue/models.py index 2ca78b01e..2b33964c2 100644 --- a/apps/catalogue/models.py +++ b/apps/catalogue/models.py @@ -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 @@ -174,16 +168,39 @@ class Tag(TagBase): def url_chunk(self): return '/'.join((Tag.categories_dict[self.category], self.slug)) + @staticmethod + def tags_from_info(info): + from slughifi import slughifi + from sortify import sortify + meta_tags = [] + categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch')) + for field_name, category in categories: + try: + tag_names = getattr(info, field_name) + except: + tag_names = [getattr(info, category)] + for tag_name in tag_names: + tag_sort_key = tag_name + if category == 'author': + tag_sort_key = tag_name.last_name + tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name + tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category) + if created: + tag.name = tag_name + tag.sort_key = sortify(tag_sort_key.lower()) + tag.save() + meta_tags.append(tag) + return meta_tags + + def get_dynamic_path(media, filename, ext=None, maxlen=100): from slughifi import slughifi # 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: @@ -202,8 +219,10 @@ def get_customized_pdf_path(book, customizations): """ customizations.sort() h = hash(tuple(customizations)) + pdf_name = '%s-custom-%s' % (book.fileid(), h) - pdf_file = models.get_dynamic_path(None, pdf_name, ext='pdf') + pdf_file = get_dynamic_path(None, pdf_name, ext='pdf') + return pdf_file @@ -218,7 +237,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) @@ -331,8 +359,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) @@ -429,14 +458,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) @@ -479,15 +508,13 @@ class Book(models.Model): formats = [] # files generated during publication if self.has_media("html"): - formats.append(u'%s' % (reverse('book_text', [self.fileid()]), _('Read online'))) - if self.has_media("pdf"): - formats.append(u'PDF' % self.get_media('pdf').url) - if self.has_media("mobi"): - formats.append(u'MOBI' % self.get_media('mobi').url) - if self.root_ancestor.has_media("epub"): - formats.append(u'EPUB' % self.root_ancestor.get_media('epub').url) - if self.has_media("txt"): - formats.append(u'TXT' % self.get_media('txt').url) + formats.append(u'%s' % (reverse('book_text', args=[self.fileid()]), _('Read online'))) + for ebook_format in self.ebook_formats: + if self.has_media(ebook_format): + formats.append(u'%s' % ( + self.get_media(ebook_format).url, + ebook_format.upper() + )) # other files for m in self.media.order_by('type'): formats.append(u'%s' % (m.file.url, m.type.upper())) @@ -501,17 +528,22 @@ 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 """ + def mini_box(self): + if self.id: + cache_key = "Book.mini_boxs/%d" % (self.id, ) + short_html = cache.get(cache_key) + else: + short_html = None + + if short_html is None: + authors = self.tags.filter(category='author') - if not hasattr(self, '_root_ancestor'): - book = self - while book.parent: - book = book.parent - self._root_ancestor = book - return self._root_ancestor + short_html = unicode(render_to_string('catalogue/book_mini_box.html', + {'book': self, 'authors': authors, 'STATIC_URL': settings.STATIC_URL})) + if self.id: + cache.set(cache_key, short_html, CACHE_FOREVER) + return mark_safe(short_html) def has_description(self): return len(self.description) > 0 @@ -519,11 +551,6 @@ class Book(models.Model): 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' @@ -565,16 +592,17 @@ class Book(models.Model): current_self.pdf_file.save('%s.pdf' % self.fileid(), File(open(pdf.get_filename()))) self.pdf_file = current_self.pdf_file + + # remove cached downloadables + remove_zip(settings.ALL_PDF_ZIP) + + for customized_pdf in get_existing_customized_pdf(self): + unlink(customized_pdf) else: print "saving %s" % file_name print "to: %s" % DefaultStorage().path(file_name) DefaultStorage().save(file_name, File(open(pdf.get_filename()))) - # remove cached downloadables - remove_zip(settings.ALL_PDF_ZIP) - for customized_pdf in get_existing_customized_pdf(self): - unlink(customized_pdf) - def build_mobi(self): """ (Re)builds the MOBI file. @@ -589,34 +617,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) @@ -728,7 +737,6 @@ class Book(models.Model): def from_text_and_meta(cls, raw_file, book_info, overwrite=False, build_epub=True, build_txt=True, build_pdf=True, build_mobi=True): import re - from slughifi import slughifi from sortify import sortify # check for parts before we do anything @@ -763,24 +771,7 @@ class Book(models.Model): book.set_extra_info_value(book_info.to_dict()) book.save() - meta_tags = [] - categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch')) - for field_name, category in categories: - try: - tag_names = getattr(book_info, field_name) - except: - tag_names = [getattr(book_info, category)] - for tag_name in tag_names: - tag_sort_key = tag_name - if category == 'author': - tag_sort_key = tag_name.last_name - tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name - tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category) - if created: - tag.name = tag_name - tag.sort_key = sortify(tag_sort_key.lower()) - tag.save() - meta_tags.append(tag) + meta_tags = Tag.tags_from_info(book_info) book.tags = set(meta_tags + book_shelves) @@ -802,17 +793,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] @@ -982,7 +972,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),