Fetch thumbnails from wikidata.
[wolnelektury.git] / src / catalogue / models / book.py
index 81f3b79..978bca4 100644 (file)
@@ -45,6 +45,7 @@ _cover_upload_to = UploadToPath('book/cover/%s.jpg')
 _cover_thumb_upload_to = UploadToPath('book/cover_thumb/%s.jpg')
 _cover_api_thumb_upload_to = UploadToPath('book/cover_api_thumb/%s.jpg')
 _simple_cover_upload_to = UploadToPath('book/cover_simple/%s.jpg')
+_cover_ebookpoint_upload_to = UploadToPath('book/cover_ebookpoint/%s.jpg')
 
 
 def _ebook_upload_to(upload_path):
@@ -82,22 +83,32 @@ class Book(models.Model):
         null=True, blank=True,
         upload_to=_cover_upload_to,
         storage=bofh_storage, max_length=255)
+    cover_etag = models.CharField(max_length=255, editable=False, default='', db_index=True)
     # Cleaner version of cover for thumbs
     cover_thumb = EbookField(
         'cover_thumb', _('cover thumbnail'),
         null=True, blank=True,
         upload_to=_cover_thumb_upload_to,
         max_length=255)
+    cover_thumb_etag = models.CharField(max_length=255, editable=False, default='', db_index=True)
     cover_api_thumb = EbookField(
         'cover_api_thumb', _('cover thumbnail for mobile app'),
         null=True, blank=True,
         upload_to=_cover_api_thumb_upload_to,
         max_length=255)
+    cover_api_thumb_etag = models.CharField(max_length=255, editable=False, default='', db_index=True)
     simple_cover = EbookField(
         'simple_cover', _('cover for mobile app'),
         null=True, blank=True,
         upload_to=_simple_cover_upload_to,
         max_length=255)
+    simple_cover_etag = models.CharField(max_length=255, editable=False, default='', db_index=True)
+    cover_ebookpoint = EbookField(
+        'cover_ebookpoint', _('cover for Ebookpoint'),
+        null=True, blank=True,
+        upload_to=_cover_ebookpoint_upload_to,
+        max_length=255)
+    cover_ebookpoint_etag = models.CharField(max_length=255, editable=False, default='', db_index=True)
     ebook_formats = constants.EBOOK_FORMATS
     formats = ebook_formats + ['html', 'xml']
 
@@ -173,7 +184,7 @@ class Book(models.Model):
         return self.tag_unicode('genre')
 
     def translators(self):
-        translators = self.get_extra_info_json().get('translators')
+        translators = self.get_extra_info_json().get('translators') or []
         return [
             '\xa0'.join(reversed(translator.split(', ', 1))) for translator in translators
         ]
@@ -192,6 +203,19 @@ class Book(models.Model):
     def cover_source(self):
         return self.get_extra_info_json().get('cover_source', self.parent.cover_source() if self.parent else '')
 
+    @property
+    def isbn_pdf(self):
+        return self.get_extra_info_json().get('isbn_pdf')
+
+    @property
+    def isbn_epub(self):
+        return self.get_extra_info_json().get('isbn_epub')
+
+    @property
+    def isbn_mobi(self):
+        return self.get_extra_info_json().get('isbn_mobi')
+
+
     def save(self, force_insert=False, force_update=False, **kwargs):
         from sortify import sortify
 
@@ -223,6 +247,41 @@ class Book(models.Model):
     def gallery_url(self):
         return gallery_url(self.slug)
 
+    def get_first_text(self):
+        if self.html_file:
+            return self
+        child = self.children.all().order_by('parent_number').first()
+        if child is not None:
+            return child.get_first_text()
+
+    def get_last_text(self):
+        if self.html_file:
+            return self
+        child = self.children.all().order_by('parent_number').last()
+        if child is not None:
+            return child.get_last_text()
+
+    def get_prev_text(self):
+        if not self.parent:
+            return None
+        sibling = self.parent.children.filter(parent_number__lt=self.parent_number).order_by('-parent_number').first()
+        if sibling is not None:
+            return sibling.get_last_text()
+        return self.parent.get_prev_text()
+
+    def get_next_text(self):
+        if not self.parent:
+            return None
+        sibling = self.parent.children.filter(parent_number__gt=self.parent_number).order_by('parent_number').first()
+        if sibling is not None:
+            return sibling.get_first_text()
+        return self.parent.get_next_text()
+
+    def get_siblings(self):
+        if not self.parent:
+            return []
+        return self.parent.children.all().order_by('parent_number')
+
     @property
     def name(self):
         return self.title
@@ -556,6 +615,7 @@ class Book(models.Model):
             book.cover_thumb.build_delay()
             book.cover_api_thumb.build_delay()
             book.simple_cover.build_delay()
+            book.cover_ebookpoint.build_delay()
 
         # Build HTML and ebooks.
         book.html_file.build_delay()
@@ -574,9 +634,53 @@ class Book(models.Model):
             child.parent_cover_changed()
 
         book.update_popularity()
+        tasks.update_references.delay(book.id)
+
         cls.published.send(sender=cls, instance=book)
         return book
 
+    def get_master(self):
+        master_tags = [
+            'opowiadanie',
+            'powiesc',
+            'dramat_wierszowany_l',
+            'dramat_wierszowany_lp',
+            'dramat_wspolczesny', 'liryka_l', 'liryka_lp',
+            'wywiad',
+        ]
+        from librarian.parser import WLDocument
+        wld = WLDocument.from_file(self.xml_file.path, parse_dublincore=False)
+        root = wld.edoc.getroot()
+        for master in root.iter():
+            if master.tag in master_tags:
+                return master
+    
+    def update_references(self):
+        from references.models import Entity, Reference
+        master = self.get_master()
+        found = set()
+        for i, sec in enumerate(master):
+            for ref in sec.findall('.//ref'):
+                href = ref.attrib.get('href', '')
+                if not href or href in found:
+                    continue
+                found.add(href)
+                entity, created = Entity.objects.get_or_create(
+                    uri=href
+                )
+                ref, created = Reference.objects.get_or_create(
+                    book=self,
+                    entity=entity
+                )
+                ref.first_section = 'sec%d' % (i + 1)
+                entity.populate()
+                entity.save()
+        Reference.objects.filter(book=self).exclude(entity__uri__in=found).delete()
+    
+    @property
+    def references(self):
+        return self.reference_set.all().select_related('entity')
+
     @classmethod
     @transaction.atomic
     def repopulate_ancestors(cls):
@@ -836,6 +940,8 @@ def add_file_fields():
             blank=True,
             default=''
         ).contribute_to_class(Book, field_name)
+        if format_ != 'xml':
+            models.CharField(max_length=255, editable=False, default='', db_index=True).contribute_to_class(Book, f'{field_name}_etag')
 
 
 add_file_fields()