from catalogue import tasks
import re
-import search
# Those are hard-coded here so that makemessages sees them.
TAG_CATEGORIES = (
class Tag(TagBase):
+ """A tag attachable to books and fragments (and possibly anything).
+
+ Used to represent searchable metadata (authors, epochs, genres, kinds),
+ fragment themes (motifs) and some book hierarchy related kludges."""
name = models.CharField(_('name'), max_length=50, db_index=True)
slug = models.SlugField(_('slug'), max_length=120, db_index=True)
sort_key = models.CharField(_('sort key'), max_length=120, db_index=True)
class BookMedia(models.Model):
+ """Represents media attached to a book."""
FileFormat = namedtuple("FileFormat", "name ext")
formats = SortedDict([
('mp3', FileFormat(name='MP3', ext='mp3')),
class Book(models.Model):
+ """Represents a book imported from WL-XML."""
title = models.CharField(_('title'), max_length=120)
sort_key = models.CharField(_('sort key'), max_length=120, db_index=True, editable=False)
slug = models.SlugField(_('slug'), max_length=120, db_index=True,
cover = models.FileField(_('cover'), upload_to=book_upload_path('png'),
null=True, blank=True)
- ebook_formats = ['pdf', 'epub', 'mobi', 'txt']
+ ebook_formats = ['pdf', 'epub', 'mobi', 'fb2', 'txt']
formats = ebook_formats + ['html', 'xml']
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
# Thin wrappers for builder tasks
def build_pdf(self, *args, **kwargs):
+ """(Re)builds PDF."""
return tasks.build_pdf.delay(self.pk, *args, **kwargs)
def build_epub(self, *args, **kwargs):
+ """(Re)builds EPUB."""
return tasks.build_epub.delay(self.pk, *args, **kwargs)
def build_mobi(self, *args, **kwargs):
+ """(Re)builds MOBI."""
return tasks.build_mobi.delay(self.pk, *args, **kwargs)
+ def build_fb2(self, *args, **kwargs):
+ """(Re)build FB2"""
+ return tasks.build_fb2.delay(self.pk, *args, **kwargs)
def build_txt(self, *args, **kwargs):
+ """(Re)builds TXT."""
return tasks.build_txt.delay(self.pk, *args, **kwargs)
@staticmethod
return create_zip(paths, "%s_%s" % (self.slug, format_))
def search_index(self, book_info=None, reuse_index=False, index_tags=True):
+ import search
if reuse_index:
idx = search.ReusableIndex()
else:
@classmethod
def from_text_and_meta(cls, raw_file, book_info, overwrite=False,
- build_epub=True, build_txt=True, build_pdf=True, build_mobi=True,
+ build_epub=True, build_txt=True, build_pdf=True, build_mobi=True, build_fb2=True,
search_index=True, search_index_tags=True, search_index_reuse=False):
# check for parts before we do anything
if not settings.NO_BUILD_MOBI and build_mobi:
book.build_mobi()
+ if not settings.NO_BUILD_FB2 and build_fb2:
+ book.build_fb2()
+
if not settings.NO_SEARCH_INDEX and search_index:
book.search_index(index_tags=search_index_tags, reuse_index=search_index_reuse)
#index_book.delay(book.id, book_info)
@classmethod
def tagged_top_level(cls, tags):
- """ Returns top-level books tagged with `tags'.
+ """ Returns top-level books tagged with `tags`.
It only returns those books which don't have ancestors which are
also tagged with those tags.
def _has_factory(ftype):
has = lambda self: bool(getattr(self, "%s_file" % ftype))
- has.short_description = t.upper()
+ has.short_description = ftype.upper()
+ has.__doc__ = None
has.boolean = True
has.__name__ = "has_%s_file" % ftype
return has
class Fragment(models.Model):
+ """Represents a themed fragment of a book."""
text = models.TextField()
short_text = models.TextField(editable=False)
anchor = models.CharField(max_length=120)
post_save.connect(_post_save_handler)
-@django.dispatch.receiver(post_delete, sender=Book)
-def _remove_book_from_index_handler(sender, instance, **kwargs):
- """ remove the book from search index, when it is deleted."""
- search.JVM.attachCurrentThread()
- idx = search.Index()
- idx.open(timeout=10000) # 10 seconds timeout.
- try:
- idx.remove_book(instance)
- idx.index_tags()
- finally:
- idx.close()
+if not settings.NO_SEARCH_INDEX:
+ @django.dispatch.receiver(post_delete, sender=Book)
+ def _remove_book_from_index_handler(sender, instance, **kwargs):
+ """ remove the book from search index, when it is deleted."""
+ import search
+ search.JVM.attachCurrentThread()
+ idx = search.Index()
+ idx.open(timeout=10000) # 10 seconds timeout.
+ try:
+ idx.remove_book(instance)
+ idx.index_tags()
+ finally:
+ idx.close()