update
[redakcja.git] / src / depot / models.py
1 import json
2 import os
3 import tempfile
4 import zipfile
5 from datetime import datetime
6 from django.db import models
7 from librarian.cover import make_cover
8 from librarian.builders import EpubBuilder, MobiBuilder
9
10
11 class Package(models.Model):
12     created_at = models.DateTimeField(auto_now_add=True)
13     placed_at = models.DateTimeField(null=True, blank=True)
14     finished_at = models.DateTimeField(null=True, blank=True)
15     definition_json = models.TextField(blank=True)
16     books = models.ManyToManyField('documents.Book')
17     status_json = models.TextField(blank=True)
18     logo = models.FileField(blank=True, upload_to='depot/logo')
19     file = models.FileField(blank=True, upload_to='depot/package/')
20
21     def save(self, *args, **kwargs):
22         try:
23             self.set_status(self.get_status())
24         except:
25             pass
26         
27         try:
28             self.set_definition(self.get_definition())
29         except:
30             pass
31
32         super().save(*args, **kwargs)
33     
34     def get_status(self):
35         return json.loads(self.status_json)
36
37     def set_status(self, status):
38         self.status_json = json.dumps(status, indent=4, ensure_ascii=False)
39
40     def get_definition(self):
41         return json.loads(self.definition_json)
42
43     def set_definition(self, definition):
44         self.definition_json = json.dumps(definition, indent=4, ensure_ascii=False)
45
46     def build(self):
47         f = tempfile.NamedTemporaryFile(prefix='depot-', suffix='.zip', mode='wb', delete=False)
48         book_count = self.books.all().count()
49         with zipfile.ZipFile(f, 'w') as z:
50             for i, book in enumerate(self.books.all()):
51                 print(f'{i}/{book_count} {book.slug}')
52                 self.build_for(book, z)
53         f.close()
54         with open(f.name, 'rb') as ff:
55             self.file.save('package-{}.zip'.format(datetime.now().isoformat(timespec='seconds')), ff)
56         os.unlink(f.name)
57
58     def build_for(self, book, z):
59         wldoc2 = book.wldocument(librarian2=True)
60         slug = wldoc2.meta.url.slug
61         for item in self.get_definition():
62             wldoc = book.wldocument()
63             wldoc2 = book.wldocument(librarian2=True)
64             base_url = 'file://' + book.gallery_path() + '/'
65
66             ext = item['type']
67
68             if item['type'] == 'cover':
69                 kwargs = {}
70                 if self.logo:
71                     kwargs['cover_logo'] = self.logo.path
72                 for k in 'format', 'width', 'height', 'cover_class':
73                     if k in item:
74                         kwargs[k] = item[k]
75                 cover = make_cover(wldoc.book_info, **kwargs)
76                 output = cover.output_file()
77                 ext = cover.ext()
78
79             elif item['type'] == 'pdf':
80                 cover_kwargs = {}
81                 if 'cover_class' in item:
82                     cover_kwargs['cover_class'] = item['cover_class']
83                 if self.logo:
84                     cover_kwargs['cover_logo'] = self.logo.path
85                 cover = lambda *args, **kwargs: make_cover(*args, **kwargs, **cover_kwargs)
86                 output = wldoc.as_pdf(cover=cover, base_url=base_url)
87
88             elif item['type'] == 'epub':
89                 cover_kwargs = {}
90                 if 'cover_class' in item:
91                     cover_kwargs['cover_class'] = item['cover_class']
92                 if self.logo:
93                     cover_kwargs['cover_logo'] = self.logo.path
94                 cover = lambda *args, **kwargs: make_cover(*args, **kwargs, **cover_kwargs)
95
96                 output = EpubBuilder(
97                     cover=cover,
98                     base_url=base_url,
99                     fundraising=item.get('fundraising', []),
100                 ).build(wldoc2)
101
102             elif item['type'] == 'mobi':
103                 output = MobiBuilder(
104                     cover=cover,
105                     base_url=base_url,
106                     fundraising=item.get('fundraising', []),
107                 ).build(wldoc2)
108
109             fname = f'{slug}/{slug}.'
110             if 'slug' in item:
111                 fname += item['slug'] + '.'
112             fname += ext
113
114             z.writestr(
115                 fname,
116                 output.get_bytes()
117             )