1 from datetime import date
3 from urllib.parse import urljoin
4 from django.conf import settings
5 from django.utils.html import escape
6 from django.utils.safestring import mark_safe
7 from librarian.functions import lang_code_3to2
8 from librarian.builders import EpubBuilder, MobiBuilder
9 from librarian.covers.marquise import MarquiseCover, LabelMarquiseCover
11 from catalogue.models import Audience, Thema
12 from .base import BasePublisher
15 class Legimi(BasePublisher):
16 BASE_URL = 'https://wydawca.legimi.pl'
17 UPLOAD_URL = BASE_URL + '/upload/start'
18 CREATE_URL = BASE_URL + '/publishers/publications/create'
19 EDIT_URL = BASE_URL + '/publishers/publications/edit/%s'
20 EDIT_FILES_URL = BASE_URL + '/publishers/publications/editfiles/%s'
21 EDIT_SALE_URL = BASE_URL + '/publishers/publications/editsale/%s'
24 'Dla dzieci i młodzieży': 94,
25 'Książki dla dzieci': 15,
26 'Literatura młodzieżowa': 24,
28 'Kryminał klasyczny': 31,
29 'Kryminał współczesny': 32,
30 'Kryminał historyczny': 30,
33 'Słowniki i leksykony': 14,
39 'Dwudziestolecie międzywojenne': 88,
48 'Fantastyka i sci-fi': 25,
50 'Science fiction': 27,
52 'Antyki i kolekcjonerstwo': 53,
53 'Astrologia i wróżbiarstwo': 54,
54 'Zdrowie i rodzina': 57,
56 'Medycyna i zdrowie': 58,
60 'Kultura i sztuka': 64,
63 'Eseje literackie': 49,
66 'Wakacje i podróże': 69,
69 'Obyczajowe i romanse': 93,
73 'Powieść przygodowa': 42,
74 'Współczesna powieść przygodowa': 44,
75 'Historyczna powieść przygodowa': 43,
76 'Powieść historyczna': 46,
77 'Powieść psychologiczna': 47,
78 'Powieść religijna': 45,
80 'Romans klasyczny': 38,
81 'Romans współczesny': 39,
82 'Literatura erotyczna': 40,
83 'Romans historyczny': 37,
85 'Sensacja, thriller, horror': 91,
91 'Literatura faktu, reportaże, biografie': 92,
92 'Literatura faktu': 16,
97 'Historia literatury i krytyka literacka': 23,
98 'Literatura popularnonaukowa': 22,
100 'Społeczno-polityczne': 72,
101 'Poezja i dramat': 95,
104 'Religia i duchowość': 51,
105 'Nauka i nowe technologie': 98,
106 'Nauka i technika': 61,
108 'Nauki humanistyczne': 63,
109 'Technologia i Internet': 75,
110 'Specjalistyczne': 99,
111 'Biznes i finanse': 1,
116 'Rozwój osobisty': 7,
117 'Kariera i sukces zawodowy': 8,
118 'Psychologia, motywacja': 9,
125 r = self._session.get(self.BASE_URL)
126 h = html.fromstring(r.text)
127 form = h.findall('.//form')[0]
128 login_url = urljoin(r.url, form.action)
129 data = {e.name: e.value for e in form.findall('.//input')}
130 data['Login'] = self.username
131 data['Password'] = self.password
132 self._session.post(login_url, data=data)
134 def can_publish(self, site, book):
141 meta = book.wldocument(librarian2=True).meta
143 d['errors'].append('Nieprawidłowy dokument.')
145 thema = self.get_thema(meta)
147 d['info'].append(mark_safe(
148 "w kategorii " + ", ".join(
149 "<b><tt>{code}</tt></b>".format(code=escape(t))
153 if not meta.thema_main:
154 d['warnings'].append('Brak głównej kategorii Thema')
156 d['errors'].append('Brak kategorii Thema.')
160 return self.session.get('https://wydawca.legimi.com/publishers/publications')
162 def upload(self, content):
163 response = self.session.post(
168 model = response.json()['model']
170 "name": model['Name'],
171 "token": model['Token'],
175 def get_thema(self, meta):
178 thema.append(meta.thema_main)
179 thema.extend(meta.thema)
182 Audience.objects.filter(code__in=meta.audiences).exclude(
183 thema=None).values_list('thema', flat=True)
185 thema = [Thema.standardize(t) for t in thema]
188 def send_book(self, site_book_publish, changes=None):
189 site_book = site_book_publish.site_book
190 site = site_book.site
191 book = site_book.book
192 wlbook = book.wldocument(librarian2=True, changes=changes)
195 cover = LabelMarquiseCover(meta, width=1200).output_file()
196 texts = site.get_texts()
197 epub_file = EpubBuilder(
200 base_url='file://' + book.gallery_path() + '/'
201 ).build(wlbook).get_file()
202 mobi_file = MobiBuilder(
205 base_url='file://' + book.gallery_path() + '/'
206 ).build(wlbook).get_file()
210 "Author": ", ".join(p.readable() for p in meta.authors),
211 "Year": str(date.today().year),
213 'GenreId': str(self.get_genre(wlbook)),
214 'themaCategories': ';'.join(self.get_thema(meta)),
217 'LanguageLocale': lang_code_3to2(meta.language),
219 'Description': self.get_description(wlbook, site.description_add),
222 isbn = meta.isbn_html
223 if isbn.upper().startswith(('ISBN ', 'ISBN-')):
226 book_data['Isbn'] = isbn
230 cover_data = self.upload(
231 (meta.url.slug + '.jpg', cover.get_file(), 'image/jpeg')
234 "Cover.Name": cover_data['name'],
235 "Cover.Token": cover_data['token'],
236 "Cover.Url": cover_data['url'],
239 epub_data = self.upload(
240 (meta.url.slug + '.epub', epub_file, 'application/epub+zip')
243 'BookEpub.Token': epub_data['token'],
244 'BookEpub.Name': epub_data['name'],
245 'SampleEpubType': 'Generation',
248 mobi_data = self.upload(
249 (meta.url.slug + '.mobi', mobi_file, 'application/x-mobipocket-ebook')
252 'BookMobi.Token': mobi_data['token'],
253 'BookMobi.Name': mobi_data['name'],
256 if site_book.external_id:
258 site_book.external_id,
262 site_book.external_id,
266 legimi_id = self.create_book(book_data, files_data)
268 site_book.external_id = legimi_id
269 site_book.save(update_fields=['external_id'])
271 self.edit_sale(site_book)
273 def get_genre(self, wlbook):
274 if wlbook.meta.legimi and wlbook.meta.legimi in self.CATEGORIES:
275 return self.CATEGORIES[wlbook.meta.legimi]
276 for epoch in wlbook.meta.epochs:
277 if epoch in self.CATEGORIES:
278 return self.CATEGORIES[epoch]
279 return self.CATEGORIES['Lektury']
281 def create_book(self, book_data, files_data):
283 'createValidationTrue': 'true',
284 'PublisherId': self.publisher_handle,
285 'IsLibraryPass': 'False',
287 'SamplesGenerationType': 'Quantity',
288 'SamplesGenerationPercent': '10',
290 'EnterToTheMarketType': 'No',
291 'EnterToTheMarketDate': '',
293 'SalesNoLimitOption': 'false',
294 'SalesNoLimitKindle': 'false',
295 'SalesInStoreEbookGrossValue': '0,00',
296 'SalesPromotion': 'False',
297 'SalesPromotionGrossValue': '0,00',
298 'SalesPromotionDatesRange.DateStart': '',
299 'SalesPromotionDatesRange.DateEnd': '',
302 for form in 'Epub', 'Mobi', 'Pdf':
304 f'Book{form}.Token': '',
305 f'Book{form}.Name': '',
306 f'Book{form}.StorageName': '',
307 f'Book{form}.Order': '',
309 f'Sample{form}Type': 'Files',
310 f'Sample{form}.Token': '',
311 f'Sample{form}.Name': '',
312 f'Sample{form}.StorageName': '',
313 f'Sample{form}.Order': '',
316 data.update(book_data)
317 data.update(files_data)
319 response = self.session.post(self.CREATE_URL, data=data)
320 m = re.search(r'/(\d+)$', response.url)
321 assert m is not None, 'Legimi.create_book: ' + response.text
324 def edit(self, legimi_id, data):
326 'ValidationTrue': 'true',
333 self.EDIT_URL % legimi_id,
337 def edit_files(self, legimi_id, files_data):
339 'ValidationTrue': 'true',
341 'SamplesGenerationType': 'Quantity',
342 'SamplesGenerationPercent': '10',
345 for form in 'Epub', 'Mobi', 'Pdf':
347 f'Book{form}.Token': '',
348 f'Book{form}.Name': '',
349 f'Book{form}.StorageName': '',
350 f'Book{form}.Order': '',
352 f'Sample{form}.Type': 'Files',
353 f'Sample{form}.Token': '',
354 f'Sample{form}.Name': '',
355 f'Sample{form}.StorageName': '',
356 f'Sample{form}.Order': '',
359 current.update(files_data)
361 response = self.session.post(
362 self.EDIT_FILES_URL % legimi_id,
366 def edit_sale(self, site_book):
367 book = site_book.book
368 assert site_book.external_id
370 words = book.wldocument(librarian2=True).get_statistics()['total']['words_with_fn']
372 price = settings.LEGIMI_SMALL_PRICE
373 if words > settings.LEGIMI_SMALL_WORDS:
374 price = settings.LEGIMI_BIG_PRICE
376 abo = 'true' if words > settings.LEGIMI_BIG_WORDS else 'false'
379 'ValidationTrue': 'true',
380 'Id': site_book.external_id,
381 'SalesPromotionId': "0",
382 'IsLibraryPass': "False",
383 'OriginalEnterToTheMarketType': "No",
384 'OriginalHidingDate': "",
385 'OriginalEnterToTheMarketDate': "",
386 'EnterToTheMarketType': "Yes",
387 'EnterToTheMarketDate': "",
389 'SalesNoLimitOption': abo,
390 'SalesNoLimitKindle': abo,
391 'SalesInStoreEbookGrossValue': f'{price},00',
392 'SalesPromotion': "False",
393 'SalesPromotionGrossValue': "0,00",
394 'SalesPromotionDatesRange.DateStart': "",
395 'SalesPromotionDatesRange.DateEnd': "",
399 self.EDIT_SALE_URL % site_book.external_id,