1 from datetime import date
3 from django.conf import settings
4 from django.utils.html import escape
5 from django.utils.safestring import mark_safe
6 from librarian.functions import lang_code_3to2
7 from librarian.builders import EpubBuilder, MobiBuilder
8 from librarian.covers.marquise import MarquiseCover, LabelMarquiseCover
9 from .base import BasePublisher
12 class Legimi(BasePublisher):
13 BASE_URL = 'https://panel.legimi.pl'
14 LOGIN_URL = BASE_URL + '/publishers/membership'
15 UPLOAD_URL = BASE_URL + '/administration/upload/start'
16 CREATE_URL = BASE_URL + '/publishers/publications/create'
17 EDIT_URL = BASE_URL + '/publishers/publications/edit/%s'
18 EDIT_FILES_URL = BASE_URL + '/publishers/publications/editfiles/%s'
19 EDIT_SALE_URL = BASE_URL + '/publishers/publications/editsale/%s'
22 'Dla dzieci i młodzieży': 94,
23 'Książki dla dzieci': 15,
24 'Literatura młodzieżowa': 24,
26 'Kryminał klasyczny': 31,
27 'Kryminał współczesny': 32,
28 'Kryminał historyczny': 30,
31 'Słowniki i leksykony': 14,
37 'Dwudziestolecie międzywojenne': 88,
46 'Fantastyka i sci-fi': 25,
48 'Science fiction': 27,
50 'Antyki i kolekcjonerstwo': 53,
51 'Astrologia i wróżbiarstwo': 54,
52 'Zdrowie i rodzina': 57,
54 'Medycyna i zdrowie': 58,
58 'Kultura i sztuka': 64,
61 'Eseje literackie': 49,
64 'Wakacje i podróże': 69,
67 'Obyczajowe i romanse': 93,
71 'Powieść przygodowa': 42,
72 'Współczesna powieść przygodowa': 44,
73 'Historyczna powieść przygodowa': 43,
74 'Powieść historyczna': 46,
75 'Powieść psychologiczna': 47,
76 'Powieść religijna': 45,
78 'Romans klasyczny': 38,
79 'Romans współczesny': 39,
80 'Literatura erotyczna': 40,
81 'Romans historyczny': 37,
83 'Sensacja, thriller, horror': 91,
89 'Literatura faktu, reportaże, biografie': 92,
90 'Literatura faktu': 16,
95 'Historia literatury i krytyka literacka': 23,
96 'Literatura popularnonaukowa': 22,
98 'Społeczno-polityczne': 72,
99 'Poezja i dramat': 95,
102 'Religia i duchowość': 51,
103 'Nauka i nowe technologie': 98,
104 'Nauka i technika': 61,
106 'Nauki humanistyczne': 63,
107 'Technologia i Internet': 75,
108 'Specjalistyczne': 99,
109 'Biznes i finanse': 1,
114 'Rozwój osobisty': 7,
115 'Kariera i sukces zawodowy': 8,
116 'Psychologia, motywacja': 9,
126 'ValidationTrue': 'true',
127 'UserName': self.username,
128 'Password': self.password,
131 def can_publish(self, shop, book):
132 meta = book.wldocument(librarian2=True).meta
138 if meta.thema_main or meta.thema:
140 comment = "w kategorii <b><tt>{code}</tt></b>".format(
141 code=escape(meta.thema_main)
144 comment += " oraz: " + ", ".join(
145 "<b><tt>{code}</tt></b>".format(code=escape(t))
148 d['info'].append(mark_safe(comment))
150 d['info'].append(mark_safe(
151 "w kategorii " + ", ".join(
152 "<b><tt>{code}</tt></b>".format(code=escape(t))
156 d['warnings'].append('Brak głównej kategorii Thema')
158 d['errors'].append('Brak kategorii Thema.')
162 return self.session.get('https://wydawca.legimi.com/publishers/publications')
164 def upload(self, content):
165 response = self.session.post(
170 model = response.json()['model']
172 "name": model['Name'],
173 "token": model['Token'],
177 def send_book(self, shop, book, changes=None):
178 wlbook = book.wldocument(librarian2=True, changes=changes)
181 cover = LabelMarquiseCover(meta, width=1200).output_file()
182 texts = shop.get_texts()
183 epub_file = EpubBuilder(
186 base_url='file://' + book.gallery_path() + '/'
187 ).build(wlbook).get_file()
188 mobi_file = MobiBuilder(
191 base_url='file://' + book.gallery_path() + '/'
192 ).build(wlbook).get_file()
196 thema.append(meta.thema_main)
197 thema.extend(meta.thema)
201 "Author": ", ".join(p.readable() for p in meta.authors),
202 "Year": str(date.today().year),
204 'GenreId': str(self.get_genre(wlbook)),
205 'themaCategories': ';'.join(thema),
208 'LanguageLocale': lang_code_3to2(meta.language),
210 'Description': self.get_description(wlbook, shop.description_add),
213 isbn = meta.isbn_html
214 if isbn.upper().startswith(('ISBN ', 'ISBN-')):
217 book_data['Isbn'] = isbn
221 cover_data = self.upload(
222 (meta.url.slug + '.jpg', cover.get_file(), 'image/jpeg')
225 "Cover.Name": cover_data['name'],
226 "Cover.Token": cover_data['token'],
227 "Cover.Url": cover_data['url'],
230 epub_data = self.upload(
231 (meta.url.slug + '.epub', epub_file, 'application/epub+zip')
234 'BookEpub.Token': epub_data['token'],
235 'BookEpub.Name': epub_data['name'],
236 'SampleEpubType': 'Generation',
239 mobi_data = self.upload(
240 (meta.url.slug + '.mobi', mobi_file, 'application/x-mobipocket-ebook')
243 'BookMobi.Token': mobi_data['token'],
244 'BookMobi.Name': mobi_data['name'],
257 legimi_id = self.create_book(book_data, files_data)
259 book.legimi_id = legimi_id
260 book.save(update_fields=['legimi_id'])
264 def get_genre(self, wlbook):
265 if wlbook.meta.legimi and wlbook.meta.legimi in self.CATEGORIES:
266 return self.CATEGORIES[wlbook.meta.legimi]
267 for epoch in wlbook.meta.epochs:
268 if epoch in self.CATEGORIES:
269 return self.CATEGORIES[epoch]
270 return self.CATEGORIES['Lektury']
272 def create_book(self, book_data, files_data):
274 'createValidationTrue': 'true',
275 'PublisherId': self.publisher_handle,
276 'IsLibraryPass': 'False',
278 'SamplesGenerationType': 'Quantity',
279 'SamplesGenerationPercent': '10',
281 'EnterToTheMarketType': 'No',
282 'EnterToTheMarketDate': '',
284 'SalesNoLimitOption': 'false',
285 'SalesNoLimitKindle': 'false',
286 'SalesInStoreEbookGrossValue': '0,00',
287 'SalesPromotion': 'False',
288 'SalesPromotionGrossValue': '0,00',
289 'SalesPromotionDatesRange.DateStart': '',
290 'SalesPromotionDatesRange.DateEnd': '',
293 for form in 'Epub', 'Mobi', 'Pdf':
295 f'Book{form}.Token': '',
296 f'Book{form}.Name': '',
297 f'Book{form}.StorageName': '',
298 f'Book{form}.Order': '',
300 f'Sample{form}Type': 'Files',
301 f'Sample{form}.Token': '',
302 f'Sample{form}.Name': '',
303 f'Sample{form}.StorageName': '',
304 f'Sample{form}.Order': '',
307 data.update(book_data)
308 data.update(files_data)
310 response = self.session.post(self.CREATE_URL, data=data)
311 m = re.search(r'/(\d+)$', response.url)
315 def edit(self, legimi_id, data):
317 'ValidationTrue': 'true',
324 self.EDIT_URL % legimi_id,
328 def edit_files(self, legimi_id, files_data):
330 'ValidationTrue': 'true',
332 'SamplesGenerationType': 'Quantity',
333 'SamplesGenerationPercent': '10',
336 for form in 'Epub', 'Mobi', 'Pdf':
338 f'Book{form}.Token': '',
339 f'Book{form}.Name': '',
340 f'Book{form}.StorageName': '',
341 f'Book{form}.Order': '',
343 f'Sample{form}.Type': 'Files',
344 f'Sample{form}.Token': '',
345 f'Sample{form}.Name': '',
346 f'Sample{form}.StorageName': '',
347 f'Sample{form}.Order': '',
350 current.update(files_data)
352 response = self.session.post(
353 self.EDIT_FILES_URL % legimi_id,
357 def edit_sale(self, book):
358 assert book.legimi_id
360 words = book.wldocument().get_statistics()['total']['words_with_fn']
362 price = settings.LEGIMI_SMALL_PRICE
363 if words > settings.LEGIMI_SMALL_WORDS:
364 price = settings.LEGIMI_BIG_PRICE
366 abo = 'true' if words > settings.LEGIMI_BIG_WORDS else 'false'
369 'ValidationTrue': 'true',
370 'Id': book.legimi_id,
371 'SalesPromotionId': "0",
372 'IsLibraryPass': "False",
373 'OriginalEnterToTheMarketType': "No",
374 'OriginalHidingDate': "",
375 'OriginalEnterToTheMarketDate': "",
376 'EnterToTheMarketType': "Yes",
377 'EnterToTheMarketDate': "",
379 'SalesNoLimitOption': abo,
380 'SalesNoLimitKindle': abo,
381 'SalesInStoreEbookGrossValue': f'{price},00',
382 'SalesPromotion': "False",
383 'SalesPromotionGrossValue': "0,00",
384 'SalesPromotionDatesRange.DateStart': "",
385 'SalesPromotionDatesRange.DateEnd': "",
389 self.EDIT_SALE_URL % book.legimi_id,