From: Radek Czajka Date: Mon, 5 Jul 2021 09:47:09 +0000 (+0200) Subject: New EPUB builder, other minor changes. X-Git-Tag: 2.0~2 X-Git-Url: https://git.mdrn.pl/librarian.git/commitdiff_plain/db91f942ce46e3af1420f3469a83257ef5aca4c2 New EPUB builder, other minor changes. --- diff --git a/src/librarian/builders/__init__.py b/src/librarian/builders/__init__.py index dc5bdee..e359cd6 100644 --- a/src/librarian/builders/__init__.py +++ b/src/librarian/builders/__init__.py @@ -3,6 +3,8 @@ from .txt import TxtBuilder from .html import HtmlBuilder, StandaloneHtmlBuilder, DaisyHtmlBuilder from .sanitize import Sanitizer from .daisy import DaisyBuilder +from .epub import EpubBuilder +from .pdf import PdfBuilder builders = OrderedDict([ @@ -12,4 +14,7 @@ builders = OrderedDict([ ("html-daisy", DaisyHtmlBuilder), ("daisy", DaisyBuilder), ("sanitizer", Sanitizer), + + ("epub", EpubBuilder), + ("pdf", PdfBuilder), ]) diff --git a/src/librarian/builders/epub.py b/src/librarian/builders/epub.py new file mode 100644 index 0000000..91405c3 --- /dev/null +++ b/src/librarian/builders/epub.py @@ -0,0 +1,690 @@ +from datetime import date +import os +import tempfile +from ebooklib import epub +from lxml import etree +import six +from librarian import functions, OutputFile, get_resource, XHTMLNS +from librarian.cover import make_cover +from librarian.embeds.mathml import MathML +import librarian.epub +from librarian.fonts import strip_font +from librarian.fundraising import FUNDRAISING + + + + +class Xhtml: + def __init__(self): + self.element = etree.XML('''WolneLektury.pl''') + + @property + def title(self): + return self.element.find('.//' + XHTMLNS('title')) + + @property + def body(self): + return self.element.find('.//' + XHTMLNS('body')) + + +class Builder: + file_extension = None + + def __init__(self, base_url=None): + self._base_url = base_url or 'file:///home/rczajka/for/fnp/librarian/temp~/maly/img/' + self.footnotes = etree.Element('div', id='footnotes') + + self.cursors = { +# None: None, +# 'header': self.header, + 'footnotes': self.footnotes, + } + self.current_cursors = [] + + self.toc_base = 0 + + @property + def cursor(self): + return self.current_cursors[-1] + + def enter_fragment(self, fragment): + self.current_cursors.append(self.cursors[fragment]) + + def exit_fragment(self): + self.current_cursors.pop() + + def create_fragment(self, name, element): + assert name not in self.cursors + self.cursors[name] = element + + def forget_fragment(self, name): + del self.cursors[name] + + + + @property + def base_url(self): + if self._base_url is not None: + return self._base_url + else: + return 'https://wolnelektury.pl/media/book/pictures/{}/'.format(self.document.meta.url.slug) + + + # Base URL should be on Document level, not builder. + def build(self, document, **kwargs): + """Should return an OutputFile with the output.""" + raise NotImplementedError() + + +class EpubBuilder(Builder): + file_extension = 'epub' + + def __init__(self, *args, **kwargs): + self.chars = set() + self.fundr = 0 + super().__init__(*args, **kwargs) + + def build(self, document, **kwargs): + # replace_characters -- nie, robimy to na poziomie elementów + + # hyphenator (\00ad w odp. miejscach) -- jeśli już, to też powinno to się dziać na poziomie elementów + # spójniki (\u00a0 po)-- jeśli już, to na poziomie elementów + # trick na dywizy: ­⁠- + + # do toc trafia: + # początek z KAÅ»DEGO PLIKU xml + + # zliczamy zbiór użytych znaków + + # flagi: + # mieliśmy taką flagę less-advertising, używaną tylko dla Prestigio; już nie używamy. + + # @editors = document.editors() (jako str) + # @funders = join(meta.funders) + # @thanks = meta.thanks + + + self.output = output = epub.EpubBook() + self.document = document + + self.set_metadata() + + + self.add_cover() + + self.add_title_page() + self.add_toc() + + + + self.start_chunk() + + self.add_toc_entry( + None, + 'Początek utworu', # i18n + 0 + ) + self.output.guide.append({ + "type": "text", + "title": "Początek", + "href": "part1.xhtml" + }) + + + self.build_document(self.document) + + + self.close_chunk() + + self.add_annotations() + self.add_support_page() + self.add_last_page() + + + e = len(self.output.spine) - 3 - 3 + nfunds = len(FUNDRAISING) + if e > 16: + nfunds *= 2 + + # COUNTING CHARACTERS? + for f in range(nfunds): + spine_index = int(4 + (f / nfunds * e) + f) + + h = Xhtml() + h.body.append( + etree.XML('
' + FUNDRAISING[f % len(FUNDRAISING)] + '
') + ) + self.add_html(h.element, file_name='fund%d.xhtml' % f, spine=spine_index) + + self.add_fonts() + + output_file = tempfile.NamedTemporaryFile( + prefix='librarian', suffix='.epub', + delete=False) + output_file.close() + epub.write_epub(output_file.name, output, {'epub3_landmark': False}) + return OutputFile.from_filename(output_file.name) + + def build_document(self, document): + self.toc_precedences = [] + + self.start_chunk() + + + document.tree.getroot().epub_build(self) + if document.meta.parts: + self.start_chunk() + + self.start_element('div', {'class': 'title-page'}) + self.start_element('h1', {'class': 'title'}) + self.push_text(document.meta.title) + self.end_element() + self.end_element() + + ###### + # 160 + # translators + # working copy? + # ta lektura + # tanks + # utwor opracowany + # isbn + # logo + + for child in document.children: + self.start_chunk() + self.add_toc_entry(None, child.meta.title, 0) + self.build_document(child) + + self.shift_toc_base() + + + def add_title_page(self): + html = Xhtml() + html.title.text = "Strona tytułowa" + bt = etree.SubElement(html.body, 'div', **{'class': 'book-text'}) + tp = etree.SubElement(bt, 'div', **{'class': 'title-page'}) + + # Tak jak jest teraz – czy może być jednocześnie + # no „autor_utworu” + # i „dzieło nadrzędne” + # wcześniej mogło być dzieło nadrzędne, + + e = self.document.tree.find('//autor_utworu') + if e is not None: + etree.SubElement(tp, 'h2', **{'class': 'author'}).text = e.raw_printable_text() + e = self.document.tree.find('//nazwa_utworu') + if e is not None: + etree.SubElement(tp, 'h1', **{'class': 'title'}).text = e.raw_printable_text() + + if not len(tp): + for author in self.document.meta.authors: + etree.SubElement(tp, 'h2', **{'class': 'author'}).text = author.readable() + etree.SubElement(tp, 'h1', **{'class': 'title'}).text = self.document.meta.title + +# +# else: +# +# + + etree.SubElement(tp, 'p', **{"class": "info"}).text = '\u00a0' + + if self.document.meta.translators: + p = etree.SubElement(tp, 'p', **{'class': 'info'}) + p.text = 'tłum. ' + ', '.join(t.readable() for t in self.document.meta.translators) + + #

[Kopia robocza]

+ + p = etree.XML("""

+ Ta lektura, podobnie jak tysiące innych, jest dostępna on-line na stronie + wolnelektury.pl. +

""") + p[0].attrib['href'] = str(self.document.meta.url) + tp.append(p) + + if self.document.meta.thanks: + etree.SubElement(tp, 'p', **{'class': 'info'}).text = self.document.meta.thanks + + tp.append(etree.XML(""" +

+ Utwór opracowany został w ramach projektu Wolne Lektury przez fundację Nowoczesna Polska. +

+ """)) + + if self.document.meta.isbn_epub: + etree.SubElement(tp, 'p', **{"class": "info"}).text = self.document.meta.isbn_epub + + tp.append(etree.XML("""""")) + + self.add_html( + html.element, + file_name='title.xhtml', + spine=True, + toc='Strona tytułowa' # TODO: i18n + ) + + self.add_file( + get_resource('res/wl-logo-small.png'), + file_name='logo_wolnelektury.png', + media_type='image/png' + ) + + def set_metadata(self): + self.output.set_identifier( + str(self.document.meta.url)) + self.output.set_language( + functions.lang_code_3to2(self.document.meta.language) + ) + self.output.set_title(self.document.meta.title) + + for i, author in enumerate(self.document.meta.authors): + self.output.add_author( + author.readable(), + file_as=six.text_type(author), + uid='creator{}'.format(i) + ) + for translator in self.document.meta.translators: + self.output.add_author( + translator.readable(), + file_as=six.text_type(translator), + role='trl', + uid='translator{}'.format(i) + ) + for publisher in self.document.meta.publisher: + self.output.add_metadata("DC", "publisher", publisher) + + self.output.add_metadata("DC", "date", self.document.meta.created_at) + + + + + def add_toc(self): + item = epub.EpubNav() + self.output.add_item(item) + self.output.spine.append(item) + self.output.add_item(epub.EpubNcx()) + + self.output.toc.append( + epub.Link( + "nav.xhtml", + "Spis treści", + "nav" + ) + ) + + + + def add_support_page(self): + self.add_file( + get_resource('epub/support.xhtml'), + spine=True, + toc='Wesprzyj Wolne Lektury' + ) + + self.add_file( + get_resource('res/jedenprocent.png'), + media_type='image/png' + ) + self.add_file( + get_resource('epub/style.css'), + media_type='text/css' + ) + + + def add_file(self, path=None, content=None, + media_type='application/xhtml+xml', + file_name=None, uid=None, + spine=False, toc=None): + + # update chars? + # jakieś tam ścieśnianie białych znaków? + + if content is None: + with open(path, 'rb') as f: + content = f.read() + if file_name is None: + file_name = path.rsplit('/', 1)[-1] + + if uid is None: + uid = file_name.split('.', 1)[0] + + item = epub.EpubItem( + uid=uid, + file_name=file_name, + media_type=media_type, + content=content + ) + + self.output.add_item(item) + if spine: + if spine is True: + self.output.spine.append(item) + else: + self.output.spine.insert(spine, item) + + if toc: + self.output.toc.append( + epub.Link( + file_name, + toc, + uid + ) + ) + + def add_html(self, html_tree, **kwargs): + html = etree.tostring( + html_tree, pretty_print=True, xml_declaration=True, + encoding="utf-8", + doctype='' + ) + + html = librarian.epub.squeeze_whitespace(html) + + self.add_file( + content=html, + **kwargs + ) + + + def add_fonts(self): + print("".join(sorted(self.chars))) + # TODO: optimizer + for fname in ('DejaVuSerif.ttf', 'DejaVuSerif-Bold.ttf', + 'DejaVuSerif-Italic.ttf', 'DejaVuSerif-BoldItalic.ttf'): + self.add_file( + content=strip_font( + get_resource('fonts/' + fname), + self.chars + ), + file_name=fname, + media_type='font/ttf' + ) + + def start_chunk(self): + if getattr(self, 'current_chunk', None) is not None: + if not len(self.current_chunk): + return + self.close_chunk() + self.current_chunk = etree.Element( + 'div', + id="book-text" + ) + self.cursors[None] = self.current_chunk + self.current_cursors.append(self.current_chunk) + + self.section_number = 0 + + + def close_chunk(self): + assert self.cursor is self.current_chunk + ###### -- what if we're inside? + + chunk_no = getattr( + self, + 'chunk_counter', + 1 + ) + self.chunk_counter = chunk_no + 1 + + html = Xhtml() + html.body.append(self.current_chunk) + + self.add_html( + ## html container from template. + #self.current_chunk, + html.element, + file_name='part%d.xhtml' % chunk_no, + spine=True, + + ) + self.current_chunk = None + self.current_cursors.pop() + + def start_element(self, tag, attr): + self.current_cursors.append( + etree.SubElement(self.cursor, tag, **attr) + ) + + def end_element(self): + self.current_cursors.pop() + + def push_text(self, text): + self.chars.update(text) + if len(self.cursor): + self.cursor[-1].tail = (self.cursor[-1].tail or '') + text + else: + self.cursor.text = (self.cursor.text or '') + text + + + def assign_image_number(self): + image_number = getattr(self, 'image_number', 0) + self.image_number = image_number + 1 + return image_number + + def assign_footnote_number(self): + number = getattr(self, 'footnote_number', 1) + self.footnote_number = number + 1 + return number + + def assign_section_number(self): + number = getattr(self, 'section_number', 1) + self.section_number = number + 1 + return number + + def assign_mathml_number(self): + number = getattr(self, 'mathml_number', 0) + self.mathml_number = number + 1 + return number + + + def add_toc_entry(self, fragment, name, precedence): + if precedence: + while self.toc_precedences and self.toc_precedences[-1] >= precedence: + self.toc_precedences.pop() + else: + self.toc_precedences = [] + + real_level = self.toc_base + len(self.toc_precedences) + if precedence: + self.toc_precedences.append(precedence) + else: + self.toc_base += 1 + + part_number = getattr( + self, + 'chunk_counter', + 1 + ) + filename = 'part%d.xhtml' % part_number + uid = filename.split('.')[0] + if fragment: + filename += '#' + fragment + uid += '-' + fragment + + toc = self.output.toc + for l in range(1, real_level): + if isinstance(toc[-1], epub.Link): + toc[-1] = [toc[-1], []] + toc = toc[-1][1] + + toc.append( + epub.Link( + filename, + name, + uid + ) + ) + + def shift_toc_base(self): + self.toc_base -= 1 + + + def add_last_page(self): + html = Xhtml() + m = self.document.meta + + html.title.text = 'Strona redakcyjna' + d = etree.SubElement(html.body, 'div', id='book-text') + + newp = lambda: etree.SubElement(d, 'p', {'class': 'info'}) + + p = newp() + if m.license: + p.text = """ + Ten utwór jest udostępniony na licencji + """ + etree.SubElement(p, 'a', href=m.license).text = m.license_description + else: + p.text = """ + Ten utwór nie jest objęty majątkowym prawem autorskim i znajduje się w domenie + publicznej, co oznacza że możesz go swobodnie wykorzystywać, publikować + i rozpowszechniać. Jeśli utwór opatrzony jest dodatkowymi materiałami + (przypisy, motywy literackie etc.), które podlegają prawu autorskiemu, to + te dodatkowe materiały udostępnione są na licencji + """ + a = etree.SubElement(p, "a", href="http://creativecommons.org/licenses/by-sa/3.0/") + a.text = """Creative Commons + Uznanie Autorstwa – Na Tych Samych Warunkach 3.0 PL""" + a.tail = "." + + + p = newp() + p.text = 'Źródło: ' + etree.SubElement( + p, 'a', href=str(m.url), + title=', '.join(( + ', '.join(p.readable() for p in m.authors), + m.title + )) + ).text = str(m.url) + + newp().text = 'Tekst opracowany na podstawie: ' + m.source_name + + newp().text = """ + Wydawca: + """ + ", ".join(p for p in m.publisher) + + if m.description: + newp().text = m.description + + + if m.editors: + newp().text = 'Opracowanie redakcyjne i przypisy: %s.' % ( + ', '.join(e.readable() for e in sorted(self.document.editors()))) + + if m.funders: + etree.SubElement(d, 'p', {'class': 'minor-info'}).text = '''Publikację wsparli i wsparły: + %s.''' % (', '.join(m.funders)) + + if m.cover_by: + p = newp() + p.text = 'Okładka na podstawie: ' + if m.cover_source: + etree.SubElement( + p, + 'a', + href=m.cover_source + ).text = m.cover_by + else: + p.text += m.cover_by + + if m.isbn_epub: + newp().text = m.isbn_epub + + newp().text = '\u00a0' + + p = newp() + p.attrib['class'] = 'minor-info' + p.text = ''' + Plik wygenerowany dnia ''' + span = etree.SubElement(p, 'span', id='file_date') + span.text = str(date.today()) + span.tail = '''. + ''' + + self.add_html( + html.element, + file_name='last.xhtml', + toc='Strona redakcyjna', + spine=True + ) + + + def add_annotations(self): + if not len(self.footnotes): + return + + html = Xhtml() + html.title.text = 'Przypisy' + d = etree.SubElement( + etree.SubElement( + html.body, + 'div', + id='book-text' + ), + 'div', + id='footnotes' + ) + + etree.SubElement( + d, + 'h2', + ).text = 'Przypisy:' + + d.extend(self.footnotes) + + self.add_html( + html.element, + file_name='annotations.xhtml', + spine=True, + toc='Przypisy' + ) + + def add_cover(self): + # TODO: allow other covers + + cover_maker = make_cover + + cover_file = six.BytesIO() + cover = cover_maker(self.document.meta) + cover.save(cover_file) + cover_name = 'cover.%s' % cover.ext() + + self.output.set_cover( + file_name=cover_name, + content=cover_file.getvalue(), + create_page = False + ) + ci = (''' + + + + Okładka + + + + Okładka + +''' % cover.ext()).encode('utf-8') + self.add_file(file_name='cover.xhtml', content=ci) + + self.output.spine.append('cover') + self.output.guide.append({ + 'type': 'cover', + 'href': 'cover.xhtml', + 'title': 'Okładka' + }) + + def mathml(self, element): + name = "math%d.png" % self.assign_mathml_number() + self.add_file( + content=MathML(element).to_latex().to_png().data, + media_type='image/png', + file_name=name + ) + return name diff --git a/src/librarian/builders/pdf.py b/src/librarian/builders/pdf.py new file mode 100644 index 0000000..6b2501e --- /dev/null +++ b/src/librarian/builders/pdf.py @@ -0,0 +1,12 @@ +from librarian import OutputFile + + +class PdfBuilder: + # Obowiązkowe + file_extension = 'pdf' + def build(self, document, mp3): + # stub + return OutputFile.from_bytes(b'') + + + diff --git a/src/librarian/builders/txt.py b/src/librarian/builders/txt.py index 3f19346..8dba4ae 100644 --- a/src/librarian/builders/txt.py +++ b/src/librarian/builders/txt.py @@ -50,20 +50,40 @@ class TxtBuilder: default_license_description = { "pol": ( - "Ten utwór nie jest objęty majątkowym prawem autorskim " - "i znajduje się w domenie publicznej, co oznacza że " - "możesz go swobodnie wykorzystywać, publikować " - "i rozpowszechniać. Jeśli utwór opatrzony jest " - "dodatkowymi materiałami (przypisy, motywy literackie " - "etc.), które podlegają prawu autorskiemu, to te " - "dodatkowe materiały udostępnione są na licencji " - "Creative Commons Uznanie Autorstwa – Na Tych Samych " - "Warunkach 3.0 PL " - "(http://creativecommons.org/licenses/by-sa/3.0/)" + "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, " + "publikować i rozpowszechniać pod warunkiem zachowania warunków " + "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur.\n" + "Ten utwór jest w domenie publicznej. " + "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są " + "udostępnione na Licencji Wolnej Sztuki 1.3 " + "(https://artlibre.org/licence/lal/pl/).\n" + "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania " + "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich " + "i prawach pokrewnych. Wykorzystując zasoby z Wolnych Lektur, " + "należy pamiętać o zapisach licencji oraz zasadach, które " + "spisaliśmy w Zasadach wykorzystania Wolnych Lektur " + "(https://wolnelektury.pl/info/zasady-wykorzystania/). Zapoznaj " + "się z nimi, zanim udostępnisz dalej nasze książki." ) } license_description = { - "pol": "Ten utwór jest udostępniony na licencji {meta.license_description}: \n{meta.license}", + "pol": ( + #"Ten utwór jest udostępniony na licencji {meta.license_description}: \n{meta.license}", + "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, " + "publikować i rozpowszechniać pod warunkiem zachowania warunków " + "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur.\n" + "Ten utwór jest jest udostępniony na licencji {meta.license_description} ({meta.license}). " + "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są " + "udostępnione na Licencji Wolnej Sztuki 1.3 " + "(https://artlibre.org/licence/lal/pl/).\n" + "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania " + "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich " + "i prawach pokrewnych. Wykorzystując zasoby z Wolnych Lektur, " + "należy pamiętać o zapisach licencji oraz zasadach, które " + "spisaliśmy w Zasadach wykorzystania Wolnych Lektur " + "(https://wolnelektury.pl/info/zasady-wykorzystania/). Zapoznaj " + "się z nimi, zanim udostępnisz dalej nasze książki." + ) } def __init__(self): diff --git a/src/librarian/cover.py b/src/librarian/cover.py index 1873be9..7d7964d 100644 --- a/src/librarian/cover.py +++ b/src/librarian/cover.py @@ -363,10 +363,10 @@ class WLCover(Cover): box_img = box.image() # Find box position. - if self.box_position == 'top': - box_top = metr.box_top_margin - elif self.box_position == 'bottom': + if self.box_position == 'bottom' or box_img.size[1] + metr.box_top_margin + metr.box_bottom_margin > metr.height: box_top = metr.height - metr.box_bottom_margin - box_img.size[1] + elif self.box_position == 'top': + box_top = metr.box_top_margin else: # Middle. box_top = (metr.height - box_img.size[1]) // 2 @@ -470,6 +470,7 @@ class WLNoBoxCover(WLCover): class LogoWLCover(WLCover): gradient_height = 90 gradient_logo_height = 60 + gradient_logo_max_width = 1000 gradient_logo_margin_right = 30 gradient_logo_spacing = 40 gradient_color = '#000' @@ -478,6 +479,8 @@ class LogoWLCover(WLCover): 'res/wl-logo-white.png', 'res/fnp-logo-white.png', ] + annotation = None + annotation_height = 10 def __init__(self, book_info, *args, **kwargs): super(LogoWLCover, self).__init__(book_info, *args, **kwargs) @@ -537,7 +540,10 @@ class LogoWLCover(WLCover): - 2 * metr.gradient_logo_margin_right ) widths = [ - logo.size[0] * metr.gradient_logo_height / logo.size[1] + min( + metr.gradient_logo_max_width, + logo.size[0] * metr.gradient_logo_height / logo.size[1] + ) for logo in logos] taken_space = ( sum(widths) @@ -553,13 +559,36 @@ class LogoWLCover(WLCover): logo = logo.resize( ( int(round(widths[i] * logo_scale)), - int(round(metr.gradient_logo_height * logo_scale)) + int(round( + logo.size[1] * widths[i] / logo.size[0] * logo_scale + )) ), Image.ANTIALIAS) cursor -= logo.size[0] - img.paste(logo, (cursor, logo_top), mask=logo) + img.paste( + logo, + ( + cursor, + int(round(logo_top + (metr.gradient_logo_height - logo.size[1]) * logo_scale / 2)) + ), + mask=logo + ) cursor -= int(round(metr.gradient_logo_spacing * logo_scale)) + if self.annotation: + img2 = Image.new('RGBA', (metr.height, metr.height), color=None) + draw = ImageDraw.Draw(img2) + author_font = ImageFont.truetype( + self.author_font_ttf, metr.annotation_height, + layout_engine=ImageFont.LAYOUT_BASIC) + draw.text((self.annotation_height, self.annotation_height), self.annotation, font=author_font, fill='#FFFFFF') + img2.show() + img2 = img2.rotate(90) + img2.show() + img.putalpha(0) + img.alpha_composite(img2, (0, 0)) + img = img.convert('RGB') + return img @@ -676,11 +705,22 @@ class AtriumCover(LogoWLCover): ] +class BNCover(LogoWLCover): + gradient_logos = [ + 'res/dofinansowano.png', + 'res/MKIDN.jpg', + 'res/BN.png', + 'res/wl-logo-white.png', + ] +# annotation = 'Zadanie „Udostępnienie publikacji w formatach cyfrowych” w ramach Narodowego Programu Rozwoju Czytelnictwa. Dofinansowano ze środków Ministra Kultury, Dziedzictwa Narodowego i Sportu.' + + COVER_CLASSES = { 'default': LogoWLCover, 'kmlu': KMLUCover, 'mpw': MPWCover, 'atrium': AtriumCover, + 'bn': BNCover, } diff --git a/src/librarian/document.py b/src/librarian/document.py index 6e94ff2..0dbb14f 100644 --- a/src/librarian/document.py +++ b/src/librarian/document.py @@ -4,12 +4,12 @@ import re from lxml import etree import six from .parser import parser -from . import dcparser, DCNS +from . import dcparser, DCNS, DirDocProvider from .functions import lang_code_3to2 class WLDocument: - def __init__(self, filename=None, url=None): + def __init__(self, filename=None, url=None, provider=None): source = filename or six.moves.urllib.request.urlopen(url) tree = etree.parse(source, parser=parser) self.tree = tree @@ -18,6 +18,8 @@ class WLDocument: DCNS('language'): ["pol"], }, validate_required=False) + self.provider = provider if provider is not None else DirDocProvider('.') + @property def meta(self): # Allow metadata of the master element as document meta. @@ -25,6 +27,15 @@ class WLDocument: return self.tree.getroot().meta return master.meta + @property + def children(self): + for part_uri in self.meta.parts or []: + yield type(self)( + filename=self.provider.by_uri(part_uri), + provider=self.provider + ) + + def build(self, builder, **kwargs): return builder().build(self, **kwargs) @@ -66,3 +77,13 @@ class WLDocument: _compat_assigns_section_ids_in_elem(child, idfier + '-') _compat_assigns_section_ids_in_elem(self.tree.getroot().master) + + def editors(self): + persons = set(self.meta.editors + + self.meta.technical_editors) + #for child in self.parts(): + # persons.update(child.editors()) + #if None in persons: + # persons.remove(None) + return persons + diff --git a/src/librarian/elements/__init__.py b/src/librarian/elements/__init__.py index f3a8521..c3a55fb 100644 --- a/src/librarian/elements/__init__.py +++ b/src/librarian/elements/__init__.py @@ -82,7 +82,7 @@ WL_ELEMENTS = { "naglowek_czesc": headers.NaglowekCzesc, "naglowek_akt": headers.NaglowekCzesc, - "naglowek_scena": headers.NaglowekRozdzial, + "naglowek_scena": headers.NaglowekScena, "naglowek_rozdzial": headers.NaglowekRozdzial, "naglowek_podrozdzial": headers.NaglowekPodrozdzial, "srodtytul": headers.NaglowekCzesc, diff --git a/src/librarian/elements/base.py b/src/librarian/elements/base.py index b9df185..5317268 100644 --- a/src/librarian/elements/base.py +++ b/src/librarian/elements/base.py @@ -3,10 +3,13 @@ import re from lxml import etree from librarian import dcparser, RDFNS +from librarian.html import raw_printable_text from librarian.util import get_translation class WLElement(etree.ElementBase): + SECTION_PRECEDENCE = None + TXT_TOP_MARGIN = 0 TXT_BOTTOM_MARGIN = 0 TXT_PREFIX = "" @@ -15,17 +18,24 @@ class WLElement(etree.ElementBase): HTML_TAG = None HTML_ATTR = {} HTML_CLASS = None - + + EPUB_TAG = None + EPUB_ATTR = {} + EPUB_CLASS = None + EPUB_START_CHUNK = False + CAN_HAVE_TEXT = True STRIP = False text_substitutions = [ (u'---', u'—'), (u'--', u'–'), - (u'...', u'…'), + #(u'...', u'…'), # Temporary turnoff for epub (u',,', u'„'), (u'"', u'”'), ('\ufeff', ''), + + ("'", "\u2019"), # This was enabled for epub. ] @property @@ -52,11 +62,25 @@ class WLElement(etree.ElementBase): def gettext(self): return get_translation(self.meta.language).gettext + def raw_printable_text(self): + # TODO: podtagi, wyroznienia, etc + t = '' + t += self.normalize_text(self.text) + for c in self: + if c.tag not in ('pe', 'pa', 'pt', 'pr', 'motyw'): + t += c.raw_printable_text() + t += self.normalize_text(c.tail) + return t + def normalize_text(self, text): text = text or '' for e, s in self.text_substitutions: text = text.replace(e, s) - text = re.sub(r'\s+', ' ', text) + # FIXME: TEmporary turnoff +# text = re.sub(r'\s+', ' ', text) +### TODO: Added now for epub + text = re.sub(r'(?<=\s\w)\s+', u'\u00A0', text) + return text def _build_inner(self, builder, build_method): @@ -118,6 +142,48 @@ class WLElement(etree.ElementBase): if self.HTML_TAG: builder.end_element() + def _epub_build_inner(self, builder): + self._build_inner(builder, 'epub_build') + + def get_epub_attr(self, builder): + attr = self.EPUB_ATTR.copy() + if self.EPUB_CLASS: + attr['class'] = self.EPUB_CLASS + return attr + + def epub_build(self, builder): + # TEMPORARY + self.CAN_HAVE_TEXT = True + self.STRIP = False + + if self.EPUB_START_CHUNK: + builder.start_chunk() + + fragment = None + if self.SECTION_PRECEDENCE: + if not self.EPUB_START_CHUNK: + fragment = 'sub%d' % builder.assign_section_number() + self.attrib['id'] = fragment + + builder.add_toc_entry( + fragment, + self.raw_printable_text(), + self.SECTION_PRECEDENCE + ) + + if self.EPUB_TAG: + attr = self.get_epub_attr(builder) + if fragment: + attr['id'] = fragment + builder.start_element( + self.EPUB_TAG, + attr + ) + + self._epub_build_inner(builder) + if self.EPUB_TAG: + builder.end_element() + def sanitize(self): # TODO: Remove insanity here. for e in self: diff --git a/src/librarian/elements/blocks/dedykacja.py b/src/librarian/elements/blocks/dedykacja.py index 5436271..7ac809d 100644 --- a/src/librarian/elements/blocks/dedykacja.py +++ b/src/librarian/elements/blocks/dedykacja.py @@ -4,5 +4,5 @@ from ..base import WLElement class Dedykacja(WLElement): TXT_LEGACY_TOP_MARGIN = 2 - HTML_TAG = "div" - HTML_CLASS = "dedication" + EPUB_TAG = HTML_TAG = "div" + EPUB_CLASS = HTML_CLASS = "dedication" diff --git a/src/librarian/elements/blocks/dlugi_cytat.py b/src/librarian/elements/blocks/dlugi_cytat.py index c660583..22e98dd 100644 --- a/src/librarian/elements/blocks/dlugi_cytat.py +++ b/src/librarian/elements/blocks/dlugi_cytat.py @@ -10,3 +10,6 @@ class DlugiCytat(WLElement): TXT_LEGACY_BOTTOM_MARGIN = 0 HTML_TAG = 'blockquote' + + EPUB_TAG = 'div' + EPUB_CLASS = 'block' diff --git a/src/librarian/elements/blocks/nota.py b/src/librarian/elements/blocks/nota.py index a01bf29..0e3f61f 100644 --- a/src/librarian/elements/blocks/nota.py +++ b/src/librarian/elements/blocks/nota.py @@ -4,5 +4,5 @@ from ..base import WLElement class Nota(WLElement): CAN_HAVE_TEXT = False - HTML_TAG = "div" - HTML_CLASS = "note" + EPUB_TAG = HTML_TAG = "div" + EPUB_CLASS = HTML_CLASS = "note" diff --git a/src/librarian/elements/blocks/poezja_cyt.py b/src/librarian/elements/blocks/poezja_cyt.py index 0c103b1..14cd539 100644 --- a/src/librarian/elements/blocks/poezja_cyt.py +++ b/src/librarian/elements/blocks/poezja_cyt.py @@ -10,3 +10,6 @@ class PoezjaCyt(WLElement): TXT_LEGACY_BOTTOM_MARGIN = 0 HTML_TAG = 'blockquote' + + EPUB_TAG = 'div' + EPUB_CLASS = 'block' diff --git a/src/librarian/elements/blocks/ramka.py b/src/librarian/elements/blocks/ramka.py index d8dd5f0..b85f83f 100644 --- a/src/librarian/elements/blocks/ramka.py +++ b/src/librarian/elements/blocks/ramka.py @@ -5,3 +5,5 @@ class Ramka(WLElement): HTML_TAG = "div" HTML_CLASS = "ramka" + EPUB_TAG = "div" + EPUB_CLASS = "frame" diff --git a/src/librarian/elements/comments/abstrakt.py b/src/librarian/elements/comments/abstrakt.py index 9b43dc3..887712b 100644 --- a/src/librarian/elements/comments/abstrakt.py +++ b/src/librarian/elements/comments/abstrakt.py @@ -7,3 +7,6 @@ class Abstrakt(WLElement): def html_build(self, builder): pass + + def epub_build(self, builder): + pass diff --git a/src/librarian/elements/comments/nota_red.py b/src/librarian/elements/comments/nota_red.py index faa5dd1..0ce970e 100644 --- a/src/librarian/elements/comments/nota_red.py +++ b/src/librarian/elements/comments/nota_red.py @@ -9,3 +9,6 @@ class NotaRed(WLElement): builder.enter_fragment('nota_red') super(NotaRed, self).html_build(builder) builder.exit_fragment() + + def epub_build(self, builder): + pass diff --git a/src/librarian/elements/comments/uwaga.py b/src/librarian/elements/comments/uwaga.py index adf908b..1bdeb39 100644 --- a/src/librarian/elements/comments/uwaga.py +++ b/src/librarian/elements/comments/uwaga.py @@ -7,3 +7,6 @@ class Uwaga(WLElement): def html_build(self, builder): pass + + def epub_build(self, builder): + pass diff --git a/src/librarian/elements/drama/didask_tekst.py b/src/librarian/elements/drama/didask_tekst.py index 7227c17..088e373 100644 --- a/src/librarian/elements/drama/didask_tekst.py +++ b/src/librarian/elements/drama/didask_tekst.py @@ -5,5 +5,5 @@ class DidaskTekst(WLElement): TXT_PREFIX = "/ " TXT_SUFFIX = " /" - HTML_TAG = "em" - HTML_CLASS = "didaskalia" + EPUB_TAG = HTML_TAG = "em" + EPUB_CLASS = HTML_CLASS = "didaskalia" diff --git a/src/librarian/elements/drama/didaskalia.py b/src/librarian/elements/drama/didaskalia.py index af0520f..bf81b69 100644 --- a/src/librarian/elements/drama/didaskalia.py +++ b/src/librarian/elements/drama/didaskalia.py @@ -9,5 +9,5 @@ class Didaskalia(WLElement): TXT_PREFIX = "/ " TXT_SUFFIX = " /" - HTML_TAG = "div" - HTML_CLASS = "didaskalia" + EPUB_TAG =_HTML_TAG = "div" + EPUB_CLASS = HTML_CLASS = "didaskalia" diff --git a/src/librarian/elements/drama/kwestia.py b/src/librarian/elements/drama/kwestia.py index 27dca30..56463d6 100644 --- a/src/librarian/elements/drama/kwestia.py +++ b/src/librarian/elements/drama/kwestia.py @@ -4,5 +4,5 @@ from ..base import WLElement class Kwestia(WLElement): CAN_HAVE_TEXT = False - HTML_TAG = "div" - HTML_CLASS = "kwestia" + EPUB_TAG = HTML_TAG = "div" + EPUB_CLASS = HTML_CLASS = "kwestia" diff --git a/src/librarian/elements/drama/lista_osob.py b/src/librarian/elements/drama/lista_osob.py index 5beca64..269b05c 100644 --- a/src/librarian/elements/drama/lista_osob.py +++ b/src/librarian/elements/drama/lista_osob.py @@ -19,3 +19,10 @@ class ListaOsob(WLElement): super(ListaOsob, self)._html_build_inner(builder) builder.cursor.append(ol) builder.forget_fragment('list') + + def _epub_build_inner(self, builder): + ol = etree.Element('ol') + builder.create_fragment('list', ol) + super(ListaOsob, self)._epub_build_inner(builder) + builder.cursor.append(ol) + builder.forget_fragment('list') diff --git a/src/librarian/elements/drama/lista_osoba.py b/src/librarian/elements/drama/lista_osoba.py index fe55838..c5770ee 100644 --- a/src/librarian/elements/drama/lista_osoba.py +++ b/src/librarian/elements/drama/lista_osoba.py @@ -8,10 +8,14 @@ class ListaOsoba(WLElement): TXT_LEGACY_BOTTOM_MARGIN = 0 TXT_PREFIX = " * " - HTML_TAG = "li" + EPUB_TAG = HTML_TAG = "li" def html_build(self, builder): builder.enter_fragment('list') super(ListaOsoba, self).html_build(builder) builder.exit_fragment() + def epub_build(self, builder): + builder.enter_fragment('list') + super(ListaOsoba, self).epub_build(builder) + builder.exit_fragment() diff --git a/src/librarian/elements/drama/miejsce_czas.py b/src/librarian/elements/drama/miejsce_czas.py index a4e9453..cf47ed2 100644 --- a/src/librarian/elements/drama/miejsce_czas.py +++ b/src/librarian/elements/drama/miejsce_czas.py @@ -2,4 +2,7 @@ from ..paragraphs import Akap class MiejsceCzas(Akap): - HTML_CLASS = 'place-and-time' + EPUB_CLASS = HTML_CLASS = 'place-and-time' + + EPUB_TAG = "div" + diff --git a/src/librarian/elements/drama/naglowek_listy.py b/src/librarian/elements/drama/naglowek_listy.py index 4db9111..1f164a4 100644 --- a/src/librarian/elements/drama/naglowek_listy.py +++ b/src/librarian/elements/drama/naglowek_listy.py @@ -3,3 +3,6 @@ from ..base import WLElement class NaglowekListy(WLElement): HTML_TAG = "h3" + + EPUB_TAG = "div" + EPUB_CLASS = "h3" diff --git a/src/librarian/elements/drama/naglowek_osoba.py b/src/librarian/elements/drama/naglowek_osoba.py index 5ab78fd..afa16ce 100644 --- a/src/librarian/elements/drama/naglowek_osoba.py +++ b/src/librarian/elements/drama/naglowek_osoba.py @@ -8,3 +8,6 @@ class NaglowekOsoba(WLElement): TXT_LEGACY_BOTTOM_MARGIN = 0 HTML_TAG = "h4" + + EPUB_TAG = "h2" + EPUB_CLASS = "h4" diff --git a/src/librarian/elements/drama/osoba.py b/src/librarian/elements/drama/osoba.py index b0fb793..ffd9494 100644 --- a/src/librarian/elements/drama/osoba.py +++ b/src/librarian/elements/drama/osoba.py @@ -2,6 +2,6 @@ from ..base import WLElement class Osoba(WLElement): - HTML_TAG = "em" - HTML_CLASS = "person" + EPUB_TAG = HTML_TAG = "em" + EPUB_CLASS = HTML_CLASS = "person" diff --git a/src/librarian/elements/figures/ilustr.py b/src/librarian/elements/figures/ilustr.py index 3c3026c..ab7c2b7 100644 --- a/src/librarian/elements/figures/ilustr.py +++ b/src/librarian/elements/figures/ilustr.py @@ -1,12 +1,51 @@ +import six.moves +from PIL import Image from ..base import WLElement class Ilustr(WLElement): - HTML_TAG = 'img' + EPUB_TAG = HTML_TAG = 'img' def get_html_attr(self, builder): + ## TODO: thumbnail. + + url = six.moves.urllib.parse.urljoin( + builder.base_url, + self.get('src') + ) + + imgfile = six.moves.urllib.request.urlopen(url) + img = Image.open(imgfile) + th_format, ext, media_type = { + 'GIF': ('GIF', 'gif', 'image/gif'), + 'PNG': ('PNG', 'png', 'image/png'), + }.get(img.format, ('JPEG', 'jpg', 'image/jpeg')) + + width = 1200 + if img.size[0] < width: + th = img + else: + th = img.resize((width, round(width * img.size[1] / img.size[0]))) + + imgfile.close() + buffer = six.BytesIO() + th.save(buffer, format=th_format) + ## TODO: Counter + file_name = 'image%d.%s' % ( + builder.assign_image_number(), + ext + ) + + builder.add_file( + content=buffer.getvalue(), + file_name=file_name, + media_type=media_type, + ) + return { - 'src': builder.base_url + self.attrib['src'], + 'src': file_name, 'alt': self.attrib['alt'], 'title': self.attrib['alt'], } + + get_epub_attr = get_html_attr diff --git a/src/librarian/elements/figures/kol.py b/src/librarian/elements/figures/kol.py index e0dae02..c94f20d 100644 --- a/src/librarian/elements/figures/kol.py +++ b/src/librarian/elements/figures/kol.py @@ -2,4 +2,4 @@ from ..base import WLElement class Kol(WLElement): - HTML_TAG = 'td' + EPUB_TAG = HTML_TAG = 'td' diff --git a/src/librarian/elements/figures/tabela.py b/src/librarian/elements/figures/tabela.py index af4a436..7da7877 100644 --- a/src/librarian/elements/figures/tabela.py +++ b/src/librarian/elements/figures/tabela.py @@ -2,7 +2,7 @@ from ..base import WLElement class Tabela(WLElement): - HTML_TAG = 'table' + EPUB_TAG = HTML_TAG = 'table' def get_html_attr(self, builder): if self.attrib.get('ramka', '') == '1': @@ -10,3 +10,7 @@ class Tabela(WLElement): 'class': 'border' } return {} + + get_epub_attr = get_html_attr + + diff --git a/src/librarian/elements/figures/wiersz.py b/src/librarian/elements/figures/wiersz.py index bc61f9d..2c7d91a 100644 --- a/src/librarian/elements/figures/wiersz.py +++ b/src/librarian/elements/figures/wiersz.py @@ -2,4 +2,4 @@ from ..base import WLElement class Wiersz(WLElement): - HTML_TAG = 'tr' + EPUB_TAG = HTML_TAG = 'tr' diff --git a/src/librarian/elements/footnotes/__init__.py b/src/librarian/elements/footnotes/__init__.py index 0f30747..433e881 100644 --- a/src/librarian/elements/footnotes/__init__.py +++ b/src/librarian/elements/footnotes/__init__.py @@ -49,6 +49,49 @@ class Footnote(WLElement): builder.end_element() builder.exit_fragment() + def epub_build(self, builder): + fn_no = builder.assign_footnote_number() + part_number = getattr( + builder, + 'chunk_counter', + 1 + ) + + builder.start_element( + 'a', + { + 'class': 'anchor', + 'id': f'anchor-{fn_no}', + 'href': f'annotations.xhtml#annotation-{fn_no}', + } + ) + builder.start_element('sup', {}) + builder.push_text(str(fn_no)) + builder.end_element() + builder.end_element() + + + builder.enter_fragment('footnotes') + builder.start_element('p', { + 'id': f'annotation-{fn_no}', + 'class': "annotation" + }) + builder.start_element('a', { + 'href': f"part{part_number}.xhtml#anchor-{fn_no}" + }) + builder.push_text(str(fn_no)) + builder.end_element() + builder.push_text('. ') + + super().epub_build(builder) + builder.push_text(' [' + self.qualifier + ']') + builder.end_element() + + builder.push_text('\n') + + builder.exit_fragment() + + class PA(Footnote): """Przypis autorski.""" diff --git a/src/librarian/elements/front/autor_utworu.py b/src/librarian/elements/front/autor_utworu.py index fd6b2e8..736a24c 100644 --- a/src/librarian/elements/front/autor_utworu.py +++ b/src/librarian/elements/front/autor_utworu.py @@ -6,3 +6,6 @@ class AutorUtworu(HeaderElement): TXT_LEGACY_BOTTOM_MARGIN = 2 HTML_CLASS = 'author' + + def epub_build(self, builder): + return diff --git a/src/librarian/elements/front/dzielo_nadrzedne.py b/src/librarian/elements/front/dzielo_nadrzedne.py index a034ae7..5f114bc 100644 --- a/src/librarian/elements/front/dzielo_nadrzedne.py +++ b/src/librarian/elements/front/dzielo_nadrzedne.py @@ -6,3 +6,6 @@ class DzieloNadrzedne(HeaderElement): TXT_LEGACY_BOTTOM_MARGIN = 1 HTML_CLASS = "collection" + + def epub_build(self, builder): + return diff --git a/src/librarian/elements/front/motto.py b/src/librarian/elements/front/motto.py index 98c7334..7f23ea6 100644 --- a/src/librarian/elements/front/motto.py +++ b/src/librarian/elements/front/motto.py @@ -5,5 +5,5 @@ class Motto(WLElement): TXT_LEGACY_TOP_MARGIN = 4 TXT_LEGACY_BOTTOM_MARGIN = 2 - HTML_TAG = "div" - HTML_CLASS = "motto" + EPUB_TAG = HTML_TAG = "div" + EPUB_CLASS = HTML_CLASS = "motto" diff --git a/src/librarian/elements/front/motto_podpis.py b/src/librarian/elements/front/motto_podpis.py index 58fc9db..8fee127 100644 --- a/src/librarian/elements/front/motto_podpis.py +++ b/src/librarian/elements/front/motto_podpis.py @@ -3,5 +3,7 @@ from ..base import WLElement class MottoPodpis(WLElement): HTML_TAG = "p" - HTML_CLASS = "motto_podpis" + EPUB_CLASS = HTML_CLASS = "motto_podpis" + EPUB_TAG = "div" + diff --git a/src/librarian/elements/front/nazwa_utworu.py b/src/librarian/elements/front/nazwa_utworu.py index aa68082..4d06b47 100644 --- a/src/librarian/elements/front/nazwa_utworu.py +++ b/src/librarian/elements/front/nazwa_utworu.py @@ -6,3 +6,6 @@ class NazwaUtworu(HeaderElement): TXT_LEGACY_BOTTOM_MARGIN = 1 HTML_CLASS = 'title' + + EPUB_TAG = 'h2' + EPUB_CLASS = 'intitle' diff --git a/src/librarian/elements/front/podtytul.py b/src/librarian/elements/front/podtytul.py index 4431bc2..71e28a8 100644 --- a/src/librarian/elements/front/podtytul.py +++ b/src/librarian/elements/front/podtytul.py @@ -6,3 +6,7 @@ class Podtytul(HeaderElement): TXT_LEGACY_BOTTOM_MARGIN = 1 HTML_CLASS = 'subtitle' + + EPUB_TAG = 'h2' + EPUB_CLASS = 'insubtitle' + diff --git a/src/librarian/elements/headers/__init__.py b/src/librarian/elements/headers/__init__.py index 3389eec..f3bda2b 100644 --- a/src/librarian/elements/headers/__init__.py +++ b/src/librarian/elements/headers/__init__.py @@ -1,6 +1,9 @@ from .naglowek_czesc import NaglowekCzesc from .naglowek_podrozdzial import NaglowekPodrozdzial from .naglowek_rozdzial import NaglowekRozdzial +from .naglowek_scena import NaglowekScena from .podtytul_czesc import PodtytulCzesc from .podtytul_rozdzial import PodtytulRozdzial from .podtytul_podrozdzial import PodtytulPodrozdzial + + diff --git a/src/librarian/elements/headers/naglowek_czesc.py b/src/librarian/elements/headers/naglowek_czesc.py index c7b2d9e..829e4f4 100644 --- a/src/librarian/elements/headers/naglowek_czesc.py +++ b/src/librarian/elements/headers/naglowek_czesc.py @@ -2,9 +2,14 @@ from ..base import WLElement class NaglowekCzesc(WLElement): + SECTION_PRECEDENCE = 1 + TXT_TOP_MARGIN = 5 TXT_BOTTOM_MARGIN = 2 TXT_LEGACY_TOP_MARGIN = 5 TXT_LEGACY_BOTTOM_MARGIN = 0 - HTML_TAG = "h2" + EPUB_TAG = HTML_TAG = "h2" + + EPUB_CLASS = "h2" + EPUB_START_CHUNK = True diff --git a/src/librarian/elements/headers/naglowek_rozdzial.py b/src/librarian/elements/headers/naglowek_rozdzial.py index ded615f..33ff355 100644 --- a/src/librarian/elements/headers/naglowek_rozdzial.py +++ b/src/librarian/elements/headers/naglowek_rozdzial.py @@ -2,9 +2,15 @@ from ..base import WLElement class NaglowekRozdzial(WLElement): + SECTION_PRECEDENCE = 2 + TXT_TOP_MARGIN = 4 TXT_BOTTOM_MARGIN = 2 TXT_LEGACY_TOP_MARGIN = 4 TXT_LEGACY_BOTTOM_MARGIN = 0 HTML_TAG = 'h3' + + EPUB_TAG = 'h2' + EPUB_CLASS = 'h3' + EPUB_START_CHUNK = True diff --git a/src/librarian/elements/headers/naglowek_scena.py b/src/librarian/elements/headers/naglowek_scena.py new file mode 100644 index 0000000..8a52ca2 --- /dev/null +++ b/src/librarian/elements/headers/naglowek_scena.py @@ -0,0 +1,17 @@ +from ..base import WLElement + + +class NaglowekScena(WLElement): + SECTION_PRECEDENCE = 2 + + TXT_TOP_MARGIN = 4 + TXT_BOTTOM_MARGIN = 2 + TXT_LEGACY_TOP_MARGIN = 4 + TXT_LEGACY_BOTTOM_MARGIN = 0 + + HTML_TAG = 'h3' + + EPUB_TAG = 'h2' + EPUB_CLASS = 'h3' + EPUB_START_CHUNK = False + diff --git a/src/librarian/elements/headers/podtytul_czesc.py b/src/librarian/elements/headers/podtytul_czesc.py index 9825211..df8fd5c 100644 --- a/src/librarian/elements/headers/podtytul_czesc.py +++ b/src/librarian/elements/headers/podtytul_czesc.py @@ -7,3 +7,11 @@ class PodtytulCzesc(WLElement): HTML_TAG = "div" HTML_CLASS = "subtitle2" + + EPUB_TAG = "h2" + EPUB_CLASS = "h2" + + def _epub_build_inner(self, builder): + builder.start_element('small', {}) + super()._epub_build_inner(builder) + builder.end_element() diff --git a/src/librarian/elements/headers/podtytul_podrozdzial.py b/src/librarian/elements/headers/podtytul_podrozdzial.py index 74aef13..cc00207 100644 --- a/src/librarian/elements/headers/podtytul_podrozdzial.py +++ b/src/librarian/elements/headers/podtytul_podrozdzial.py @@ -7,3 +7,11 @@ class PodtytulPodrozdzial(WLElement): HTML_TAG = "div" HTML_CLASS = "subtitle4" + + EPUB_TAG = "h2" + EPUB_CLASS = "h4" + + def _epub_build_inner(self, builder): + builder.start_element('small', {}) + super()._epub_build_inner(builder) + builder.end_element() diff --git a/src/librarian/elements/headers/podtytul_rozdzial.py b/src/librarian/elements/headers/podtytul_rozdzial.py index 675e19b..f8db548 100644 --- a/src/librarian/elements/headers/podtytul_rozdzial.py +++ b/src/librarian/elements/headers/podtytul_rozdzial.py @@ -7,3 +7,11 @@ class PodtytulRozdzial(WLElement): HTML_TAG = "div" HTML_CLASS = "subtitle3" + + EPUB_TAG = "h2" + EPUB_CLASS = "h3" + + def _epub_build_inner(self, builder): + builder.start_element('small', {}) + super()._epub_build_inner(builder) + builder.end_element() diff --git a/src/librarian/elements/paragraphs/akap.py b/src/librarian/elements/paragraphs/akap.py index 0a76c52..b0c0329 100644 --- a/src/librarian/elements/paragraphs/akap.py +++ b/src/librarian/elements/paragraphs/akap.py @@ -9,5 +9,5 @@ class Akap(WLElement): TXT_LEGACY_TOP_MARGIN = 2 TXT_LEGACY_BOTTOM_MARGIN = 0 - HTML_TAG = 'p' - HTML_CLASS = 'paragraph' + EPUB_TAG = HTML_TAG = 'p' + EPUB_CLASS = HTML_CLASS = 'paragraph' diff --git a/src/librarian/elements/poetry/strofa.py b/src/librarian/elements/poetry/strofa.py index 7df549f..a843d20 100644 --- a/src/librarian/elements/poetry/strofa.py +++ b/src/librarian/elements/poetry/strofa.py @@ -1,4 +1,5 @@ from copy import copy +import re from ..base import WLElement from .wers import Wers @@ -9,8 +10,19 @@ class Strofa(WLElement): TXT_LEGACY_TOP_MARGIN = 1 TXT_LEGACY_BOTTOM_MARGIN = 0 - HTML_TAG = 'div' - HTML_CLASS = 'stanza' + EPUB_TAG = HTML_TAG = 'div' + EPUB_CLASS = HTML_CLASS = 'stanza' + + def epub_build(self, builder): + super().epub_build(builder) + builder.start_element( + 'div', + { + 'class': 'stanza-spacer' + } + ) + builder.push_text('\u00a0'); + builder.end_element() def get_verses(self): from librarian.parser import parser @@ -20,7 +32,7 @@ class Strofa(WLElement): ] if self.text: # Before any tags. These are text-only verses. - pieces = self.text.split('/') + pieces = re.split(r"/\s+", self.text) for piece in pieces[:-1]: verses[-1].text = piece verses.append(parser.makeelement('wers')) @@ -28,7 +40,7 @@ class Strofa(WLElement): for child in self: if child.tail: - pieces = child.tail.split('/') + pieces = re.split(r"/\s+", child.tail) child_copy = copy(child) child_copy.tail = pieces[0] verses[-1].append(child_copy) diff --git a/src/librarian/elements/poetry/wers.py b/src/librarian/elements/poetry/wers.py index 5c28058..55cf537 100644 --- a/src/librarian/elements/poetry/wers.py +++ b/src/librarian/elements/poetry/wers.py @@ -9,11 +9,16 @@ class Wers(WLElement): TXT_LEGACY_TOP_MARGIN = 1 TXT_LEGACY_BOTTOM_MARGIN = 0 - HTML_TAG = 'div' - HTML_CLASS = 'verse' + EPUB_TAG = HTML_TAG = 'div' + EPUB_CLASS = HTML_CLASS = 'verse' @property def meta(self): if hasattr(self, 'stanza'): return self.stanza.meta return super(Wers, self).meta + + def _epub_build_inner(self, builder): + super()._epub_build_inner(builder) + builder.push_text('''\u00a0''') + diff --git a/src/librarian/elements/poetry/wers_akap.py b/src/librarian/elements/poetry/wers_akap.py index 03b8187..c0d70f4 100644 --- a/src/librarian/elements/poetry/wers_akap.py +++ b/src/librarian/elements/poetry/wers_akap.py @@ -7,3 +7,7 @@ class WersAkap(Wers): HTML_ATTR = { "style": "padding-left: 1em" } + + EPUB_ATTR = { + "style": "margin-left: 1em" + } diff --git a/src/librarian/elements/poetry/wers_cd.py b/src/librarian/elements/poetry/wers_cd.py index a61d5bc..df1f563 100644 --- a/src/librarian/elements/poetry/wers_cd.py +++ b/src/librarian/elements/poetry/wers_cd.py @@ -8,3 +8,7 @@ class WersCd(Wers): HTML_ATTR = { "style": "padding-left: 12em", } + + EPUB_ATTR = { + "style": "margin-left: 12em", + } diff --git a/src/librarian/elements/poetry/wers_do_prawej.py b/src/librarian/elements/poetry/wers_do_prawej.py index 9ab5ff0..81af0d6 100644 --- a/src/librarian/elements/poetry/wers_do_prawej.py +++ b/src/librarian/elements/poetry/wers_do_prawej.py @@ -4,6 +4,6 @@ from .wers import Wers class WersDoPrawej(Wers): TXT_PREFIX = ' ' - HTML_ATTR = { + EPUB_ATTR = HTML_ATTR = { "style": "text-align: right", } diff --git a/src/librarian/elements/poetry/wers_wciety.py b/src/librarian/elements/poetry/wers_wciety.py index 8ac2bb3..662e57a 100644 --- a/src/librarian/elements/poetry/wers_wciety.py +++ b/src/librarian/elements/poetry/wers_wciety.py @@ -18,3 +18,8 @@ class WersWciety(Wers): attr = super(WersWciety, self).get_html_attr(builder) attr['style'] = "padding-left: {}em".format(self.typ) return attr + + def get_epub_attr(self, builder): + attr = super(WersWciety, self).get_html_attr(builder) + attr['style'] = "margin-left: {}em".format(self.typ) + return attr diff --git a/src/librarian/elements/separators/sekcja_asterysk.py b/src/librarian/elements/separators/sekcja_asterysk.py index e68430d..46be85b 100644 --- a/src/librarian/elements/separators/sekcja_asterysk.py +++ b/src/librarian/elements/separators/sekcja_asterysk.py @@ -7,8 +7,8 @@ class SekcjaAsterysk(WLElement): TXT_LEGACY_TOP_MARGIN = 2 TXT_LEGACY_BOTTOM_MARGIN = 2 - HTML_TAG = "p" - HTML_CLASS = "spacer-asterisk" + EPUB_TAG = HTML_TAG = "p" + HTML_CLASS = HTML_CLASS = "spacer-asterisk" def _txt_build_inner(self, builder): builder.push_text('*') @@ -16,3 +16,5 @@ class SekcjaAsterysk(WLElement): def _html_build_inner(self, builder): builder.push_text("*") + _epub_build_inner = _html_build_inner + diff --git a/src/librarian/elements/separators/sekcja_swiatlo.py b/src/librarian/elements/separators/sekcja_swiatlo.py index 7d950da..28ba6e5 100644 --- a/src/librarian/elements/separators/sekcja_swiatlo.py +++ b/src/librarian/elements/separators/sekcja_swiatlo.py @@ -7,3 +7,9 @@ class SekcjaSwiatlo(WLElement): HTML_TAG = "hr" HTML_CLASS = "spacer" + + EPUB_TAG = 'p' + EPUB_CLASS = 'spacer' + + def _epub_build_inner(self, builder): + builder.push_text("\u00a0") diff --git a/src/librarian/elements/separators/separator_linia.py b/src/librarian/elements/separators/separator_linia.py index 5249691..49ea17f 100644 --- a/src/librarian/elements/separators/separator_linia.py +++ b/src/librarian/elements/separators/separator_linia.py @@ -7,8 +7,8 @@ class SeparatorLinia(WLElement): TXT_LEGACY_TOP_MARGIN = 2 TXT_LEGACY_BOTTOM_MARGIN = 2 - HTML_TAG = "hr" - HTML_CLASS = "spacer-line" + EPUB_TAG = HTML_TAG = "hr" + EPUB_CLASS = HTML_CLASS = "spacer-line" def _txt_build_inner(self, builder): builder.push_text('-' * 48) diff --git a/src/librarian/elements/styles/indeks_dolny.py b/src/librarian/elements/styles/indeks_dolny.py index 5d19a44..bac93c0 100644 --- a/src/librarian/elements/styles/indeks_dolny.py +++ b/src/librarian/elements/styles/indeks_dolny.py @@ -4,4 +4,4 @@ from ..base import WLElement class IndeksDolny(WLElement): TXT_PREFIX = "_" - HTML_TAG = "sub" + EPUB_TAG = HTML_TAG = "sub" diff --git a/src/librarian/elements/styles/mat.py b/src/librarian/elements/styles/mat.py index f284695..fa353f9 100644 --- a/src/librarian/elements/styles/mat.py +++ b/src/librarian/elements/styles/mat.py @@ -8,3 +8,7 @@ class Mat(WLElement): e.tag = 'math' e.attrib['xmlns'] = 'http://www.w3.org/1998/Math/MathML' builder.cursor.append(e) + + def epub_build(self, builder): + builder.start_element('img', {"src": builder.mathml(self)}) + builder.end_element() diff --git a/src/librarian/elements/styles/slowo_obce.py b/src/librarian/elements/styles/slowo_obce.py index 3592a1e..5848aa6 100644 --- a/src/librarian/elements/styles/slowo_obce.py +++ b/src/librarian/elements/styles/slowo_obce.py @@ -2,5 +2,5 @@ from ..base import WLElement class SlowoObce(WLElement): - HTML_TAG = 'em' - HTML_CLASS = 'foreign-word' + EPUB_TAG = HTML_TAG = 'em' + EPUB_CLASS = HTML_CLASS = 'foreign-word' diff --git a/src/librarian/elements/styles/tytul_dziela.py b/src/librarian/elements/styles/tytul_dziela.py index ef3618c..906d98c 100644 --- a/src/librarian/elements/styles/tytul_dziela.py +++ b/src/librarian/elements/styles/tytul_dziela.py @@ -3,8 +3,8 @@ from ..base import WLElement class TytulDziela(WLElement): - HTML_TAG = 'em' - HTML_CLASS = 'book-title' + EPUB_TAG = HTML_TAG = 'em' + EPUB_CLASS = HTML_CLASS = 'book-title' def normalize_text(self, text): txt = super(TytulDziela, self).normalize_text(text) diff --git a/src/librarian/elements/styles/wieksze_odstepy.py b/src/librarian/elements/styles/wieksze_odstepy.py index 3229402..953e797 100644 --- a/src/librarian/elements/styles/wieksze_odstepy.py +++ b/src/librarian/elements/styles/wieksze_odstepy.py @@ -5,5 +5,5 @@ class WiekszeOdstepy(WLElement): TXT_PREFIX = "*" TXT_SUFFIX = "*" - HTML_TAG = "em" - HTML_CLASS = "wieksze-odstepy" + EPUB_TAG = HTML_TAG = "em" + EPUB_CLASS = HTML_CLASS = "wieksze-odstepy" diff --git a/src/librarian/elements/styles/wyroznienie.py b/src/librarian/elements/styles/wyroznienie.py index c76b4cf..2a71a29 100644 --- a/src/librarian/elements/styles/wyroznienie.py +++ b/src/librarian/elements/styles/wyroznienie.py @@ -5,5 +5,5 @@ class Wyroznienie(WLElement): TXT_PREFIX = "*" TXT_SUFFIX = "*" - HTML_TAG = "em" - HTML_CLASS = "author-emphasis" + EPUB_TAG = HTML_TAG = "em" + EPUB_CLASS = HTML_CLASS = "author-emphasis" diff --git a/src/librarian/elements/themes/motyw.py b/src/librarian/elements/themes/motyw.py index f9ab197..25369a7 100644 --- a/src/librarian/elements/themes/motyw.py +++ b/src/librarian/elements/themes/motyw.py @@ -18,3 +18,6 @@ class Motyw(WLElement): "fid": fid, "name": "m" + fid, } + + def epub_build(self, builder): + pass diff --git a/src/librarian/epub.py b/src/librarian/epub.py index e2cdae7..0fb91e5 100644 --- a/src/librarian/epub.py +++ b/src/librarian/epub.py @@ -30,6 +30,7 @@ functions.reg_person_name() def squeeze_whitespace(s): + return s return re.sub(b'\\s+', b' ', s) @@ -62,33 +63,6 @@ def hyphenate_and_fix_conjunctions(source_tree, hyph): parent.tail = newt -def inner_xml(node): - """ returns node's text and children as a string - - >>> print(inner_xml(etree.fromstring('xyz'))) - xyz - """ - - nt = node.text if node.text is not None else '' - return ''.join( - [nt] + [etree.tostring(child, encoding='unicode') for child in node] - ) - - -def set_inner_xml(node, text): - """ sets node's text and children from a string - - >>> e = etree.fromstring('bxx') - >>> set_inner_xml(e, 'xyz') - >>> print(etree.tostring(e, encoding='unicode')) - xyz - """ - - p = etree.fromstring('%s' % text) - node.text = p.text - node[:] = p[:] - - def node_name(node): """ Find out a node's name @@ -377,17 +351,8 @@ def remove_empty_lists_from_toc(toc): toc[i] = e[0] -def transform(wldoc, verbose=False, style=None, - sample=None, cover=None, flags=None, hyphenate=False, - base_url='file://./', output_type='epub'): - """ produces a EPUB file - - sample=n: generate sample e-book (with at least n paragraphs) - cover: a cover.Cover factory or True for default - flags: less-advertising, without-fonts, working-copy - """ - def transform_file(wldoc, chunk_counter=1, first=True, sample=None): +def transform_file(wldoc, chunk_counter=1, first=True, sample=None, hyphenate=False, output_type='epub', spine=None, output=None, annotations=None): """ processes one input file and proceeds to its children """ replace_characters(wldoc.edoc.getroot()) @@ -518,12 +483,27 @@ def transform(wldoc, verbose=False, style=None, for child in wldoc.parts(): child_toc, chunk_counter, chunk_chars, sample = transform_file( - child, chunk_counter, first=False, sample=sample) + child, chunk_counter, first=False, sample=sample, + hyphenate=hyphenate, output_type=output_type, + spine=spine, output=output, annotations=annotations, + ) toc[-1][1].extend(child_toc) chars = chars.union(chunk_chars) return toc, chunk_counter, chars, sample + +def transform(wldoc, verbose=False, style=None, + sample=None, cover=None, flags=None, hyphenate=False, + base_url='file://./', output_type='epub'): + """ produces a EPUB file + + sample=n: generate sample e-book (with at least n paragraphs) + cover: a cover.Cover factory or True for default + flags: less-advertising, without-fonts, working-copy + """ + + document = deepcopy(wldoc) del wldoc @@ -584,8 +564,8 @@ def transform(wldoc, verbose=False, style=None, base_url, ilustr.get('src') ) - with six.moves.urllib.request.urlopen(url) as imgfile: - img = Image.open(imgfile) + imgfile = six.moves.urllib.request.urlopen(url) + img = Image.open(imgfile) th_format, ext, media_type = { 'GIF': ('GIF', 'gif', 'image/gif'), @@ -598,6 +578,8 @@ def transform(wldoc, verbose=False, style=None, else: th = img.resize((width, round(width * img.size[1] / img.size[0]))) + imgfile.close() + buffer = six.BytesIO() th.save(buffer, format=th_format) @@ -677,7 +659,11 @@ def transform(wldoc, verbose=False, style=None, annotations = etree.Element('annotations') - toc, chunk_counter, chars, sample = transform_file(document, sample=sample) + toc, chunk_counter, chars, sample = transform_file( + document, sample=sample, + hyphenate=hyphenate, output_type=output_type, + spine=spine, output=output, annotations=annotations + ) output.toc = toc[0][1] # Last modifications in container files and EPUB creation @@ -786,6 +772,7 @@ def transform(wldoc, verbose=False, style=None, os.chdir(cwd) remove_empty_lists_from_toc(output.toc) + print(output.toc) output_file = NamedTemporaryFile(prefix='librarian', suffix='.epub', delete=False) diff --git a/src/librarian/epub/style.css b/src/librarian/epub/style.css index 82ad4b9..a740f85 100644 --- a/src/librarian/epub/style.css +++ b/src/librarian/epub/style.css @@ -387,4 +387,13 @@ table.border th, table.border td { th, td { vertical-align: top; -} \ No newline at end of file +} + +.fundraising { + margin: 2em 1em 0; + border: 2px solid black; + padding: 2em 2em; + text-align: center; + font-size: 1.3em; + line-height: 1.4em; +} diff --git a/src/librarian/epub/xsltAnnotations.xsl b/src/librarian/epub/xsltAnnotations.xsl index cd22462..90f038e 100644 --- a/src/librarian/epub/xsltAnnotations.xsl +++ b/src/librarian/epub/xsltAnnotations.xsl @@ -15,7 +15,7 @@

- Przypisy: + Przypisy:

@@ -29,7 +29,7 @@ -

. [przypis autorski] [przypis tłumacza] [przypis redakcyjny] [przypis edytorski]

+

. [przypis autorski] [przypis tłumacza] [przypis redakcyjny] [przypis edytorski]

diff --git a/src/librarian/epub/xsltScheme.xsl b/src/librarian/epub/xsltScheme.xsl index 93767cf..0fae871 100644 --- a/src/librarian/epub/xsltScheme.xsl +++ b/src/librarian/epub/xsltScheme.xsl @@ -7,9 +7,7 @@ - - WolneLektury.pl - + WolneLektury.pl @@ -79,12 +77,12 @@ - - - + + + @@ -376,7 +374,7 @@ - diff --git a/src/librarian/fonts.py b/src/librarian/fonts.py new file mode 100644 index 0000000..adaeae4 --- /dev/null +++ b/src/librarian/fonts.py @@ -0,0 +1,38 @@ +import os +from shutil import rmtree +import subprocess +from tempfile import mkdtemp + + +def strip_font(path, chars, verbose=False): + tmpdir = mkdtemp('-librarian-epub') + try: + cwd = os.getcwd() + except OSError: + cwd = None + + os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), + 'font-optimizer')) + optimizer_call = [ + 'perl', 'subset.pl', '--chars', + ''.join(chars).encode('utf-8'), + path, + os.path.join(tmpdir, 'font.ttf') + ] + env = {"PERL_USE_UNSAFE_INC": "1"} + if verbose: + print("Running font-optimizer") + subprocess.check_call(optimizer_call, env=env) + else: + dev_null = open(os.devnull, 'w') + subprocess.check_call(optimizer_call, stdout=dev_null, + stderr=dev_null, env=env) + with open(os.path.join(tmpdir, 'font.ttf'), 'rb') as f: + content = f.read() + + rmtree(tmpdir) + + if cwd is not None: + os.chdir(cwd) + + return content diff --git a/src/librarian/fundraising.py b/src/librarian/fundraising.py new file mode 100644 index 0000000..18d7774 --- /dev/null +++ b/src/librarian/fundraising.py @@ -0,0 +1,13 @@ +FUNDRAISING = [ + 'Przyjaciele Wolnych Lektur otrzymują dostęp do nowych tekstów współczesnych autorek i autorów wcześniej niż inni. Kliknij, by przejść do strony płatności. Zadeklaruj stałą wpłatę i dołącz do Towarzystwa Przyjaciół Wolnych Lektur.', + 'Czytaj teksty współczesnych autorek i autorów wcześniej niż inni. Ty decydujesz, ile płacisz! Zadeklaruj stałą wpłatę i dołącz do Towarzystwa Przyjaciół Wolnych Lektur.', + 'Informacje o nowościach w naszej bibliotece w Twojej skrzynce mailowej? Nic prostszego, zapisz się do newslettera.
Kliknij, by pozostawić swój adres e-mail.', + '''Przekaż 1% podatku na Wolne Lektury.
+KRS: 0000070056
+Nazwa organizacji: Fundacja Nowoczesna Polska
+
+Możesz to zrobić w swoim formularzu PIT dostępnym od 15 lutego na stronie: www.podatki.gov.pl/pit.
+
+Każda wpłacona kwota zostanie przeznaczona na rozwój Wolnych Lektur.
+Dziękujemy, że jesteście z nami!''', +] diff --git a/src/librarian/html.py b/src/librarian/html.py index 363286c..f0f11db 100644 --- a/src/librarian/html.py +++ b/src/librarian/html.py @@ -58,9 +58,8 @@ def add_image_sizes(tree, gallery_path, gallery_url, base_url): rel_path = ilustr.attrib['src'] img_url = six.moves.urllib.parse.urljoin(base_url, rel_path) - with six.moves.urllib.request.urlopen(img_url) as f: - img = Image.open(f) - + f = six.moves.urllib.request.urlopen(img_url) + img = Image.open(f) ext = {'GIF': 'gif', 'PNG': 'png'}.get(img.format, 'jpg') srcset = [] @@ -75,10 +74,12 @@ def add_image_sizes(tree, gallery_path, gallery_url, base_url): ] largest = None for w in widths: - height = round(img.size[1] * w / img.size[0]) - th = img.resize((w, height)) fname = '%d.W%d.%s' % (i, w, ext) - th.save(gallery_path + fname) + fpath = gallery_path + fname + if not os.path.exists(fpath): + height = round(img.size[1] * w / img.size[0]) + th = img.resize((w, height)) + th.save(fpath) th_url = gallery_url + fname srcset.append(" ".join(( th_url, @@ -88,6 +89,8 @@ def add_image_sizes(tree, gallery_path, gallery_url, base_url): ilustr.attrib['srcset'] = ", ".join(srcset) ilustr.attrib['src'] = largest_url + f.close() + def transform(wldoc, stylesheet='legacy', options=None, flags=None, css=None, gallery_path='img/', gallery_url='img/', base_url='file://./'): """Transforms the WL document to XHTML. diff --git a/src/librarian/pdf.py b/src/librarian/pdf.py index cad66a4..a025b9b 100644 --- a/src/librarian/pdf.py +++ b/src/librarian/pdf.py @@ -320,8 +320,8 @@ def transform(wldoc, verbose=False, save_tex=None, morefloats=None, base_url, ilustr.get('src') ) - with six.moves.urllib.request.urlopen(url) as imgfile: - img = Image.open(imgfile) + imgfile = six.moves.urllib.request.urlopen(url) + img = Image.open(imgfile) th_format, ext, media_type = { 'GIF': ('GIF', 'gif', 'image/gif'), @@ -338,6 +338,8 @@ def transform(wldoc, verbose=False, save_tex=None, morefloats=None, th.save(os.path.join(temp, file_name)) ilustr.set('src', file_name) + imgfile.close() + for sponsor in book_info.sponsors: ins = etree.Element("data-sponsor", name=sponsor) logo = sponsor_logo(sponsor) diff --git a/src/librarian/pdf/wl.cls b/src/librarian/pdf/wl.cls index f8b7731..c46a0ec 100644 --- a/src/librarian/pdf/wl.cls +++ b/src/librarian/pdf/wl.cls @@ -145,6 +145,8 @@ \usepackage{unicode-math} \setmathfont{Latin Modern Math} +\usepackage{wrapfig} + \usepackage[overload]{textcase} \usepackage{scalefnt} \usepackage[colorlinks=true,linkcolor=black,setpagesize=false,urlcolor=black,xetex]{hyperref} diff --git a/src/librarian/pdf/wl2tex.xslt b/src/librarian/pdf/wl2tex.xslt index 43a3274..820033d 100644 --- a/src/librarian/pdf/wl2tex.xslt +++ b/src/librarian/pdf/wl2tex.xslt @@ -290,10 +290,25 @@
- + + + + + R + 5cm + + width= + + + + + + - + + + diff --git a/src/librarian/res/BN.png b/src/librarian/res/BN.png new file mode 100644 index 0000000..2e6df23 Binary files /dev/null and b/src/librarian/res/BN.png differ diff --git a/src/librarian/res/MKIDN.jpg b/src/librarian/res/MKIDN.jpg new file mode 100644 index 0000000..373062c Binary files /dev/null and b/src/librarian/res/MKIDN.jpg differ diff --git a/src/librarian/res/atrium-logo.png b/src/librarian/res/atrium-logo.png index 35af904..4555c55 100644 Binary files a/src/librarian/res/atrium-logo.png and b/src/librarian/res/atrium-logo.png differ diff --git a/src/librarian/res/dofinansowano.png b/src/librarian/res/dofinansowano.png new file mode 100644 index 0000000..80c531b Binary files /dev/null and b/src/librarian/res/dofinansowano.png differ diff --git a/src/librarian/text.py b/src/librarian/text.py index e425552..5b03525 100644 --- a/src/librarian/text.py +++ b/src/librarian/text.py @@ -51,27 +51,39 @@ def transform(wldoc, flags=None, **options): description = parsed_dc.description url = document.book_info.url - license_description = parsed_dc.license_description + license_name = parsed_dc.license_description license = parsed_dc.license + license_description = [ + ( + "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, " + "publikować i rozpowszechniać pod warunkiem zachowania warunków " + "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur." + ) + ] + if license: - license_description = ( - u"Ten utwór jest udostępniony na licencji %s: \n%s" % ( - license_description, license + license_description.append( + "Ten utwór jest udostępniony na licencji %s: %s" % ( + license_name, license ) ) else: - license_description = ( - "Ten utwór nie jest objęty majątkowym prawem autorskim " - "i znajduje się w domenie publicznej, co oznacza że " - "możesz go swobodnie wykorzystywać, publikować " - "i rozpowszechniać. Jeśli utwór opatrzony jest " - "dodatkowymi materiałami (przypisy, motywy literackie " - "etc.), które podlegają prawu autorskiemu, to te " - "dodatkowe materiały udostępnione są na licencji " - "Creative Commons Uznanie Autorstwa – Na Tych Samych " - "Warunkach 3.0 PL " - "(http://creativecommons.org/licenses/by-sa/3.0/)" + license_description.append( + "Ten utwór jest w domenie publicznej." ) + license_description.append( + "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są " + "udostępnione na Licencji Wolnej Sztuki 1.3: " + "https://artlibre.org/licence/lal/pl/\n" + "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania " + "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich " + "i prawach pokrewnych.\nWykorzystując zasoby z Wolnych Lektur, " + "należy pamiętać o zapisach licencji oraz zasadach, które " + "spisaliśmy w Zasadach wykorzystania Wolnych Lektur: " + "https://wolnelektury.pl/info/zasady-wykorzystania/\nZapoznaj " + "się z nimi, zanim udostępnisz dalej nasze książki" + ) + license_description = "\n".join(license_description) source = parsed_dc.source_name if source: diff --git a/src/librarian/xslt/book2html.xslt b/src/librarian/xslt/book2html.xslt index 04e2658..54f522e 100644 --- a/src/librarian/xslt/book2html.xslt +++ b/src/librarian/xslt/book2html.xslt @@ -24,6 +24,60 @@ + @@ -133,27 +187,47 @@
+
+ + + ilustr + + + oblew + + + - - - - - - - - (min-width: 718px) 600px, - (min-width: 600px) calc(100vw - 118px), - (min-width: 320px) calc(100vw - 75px), - (min-width: 15em) calc(100wv - 60px), - calc(100wv - 40px) - - - - - - + + + + + + + + (min-width: 718px) 600px, + (min-width: 600px) calc(100vw - 118px), + (min-width: 320px) calc(100vw - 75px), + (min-width: 15em) calc(100wv - 60px), + calc(100wv - 40px) + + + + + + + + + + + width: + + + +
+
diff --git a/tests/uat/main.xml b/tests/uat/main.xml index 4b77300..ceae2e7 100644 --- a/tests/uat/main.xml +++ b/tests/uat/main.xml @@ -6,28 +6,29 @@ 2020-01-08 Fundacja Nowoczesna Polska pol - wl-test + main gnu gpl -Wolne Lektury -Testy -Podtytuł - + Dzieło nadrzędnePrzypis w dziele nadrzędnym + WolnePrzypis w nazwie utworu Lektury + TestyPrzypis w tytule utworu + PodtytułPrzypis w podtytule + Testy struktury - + Nagłówek części Podtytuł części - + Nagłówek rozdziału Podtytuł rozdziału - + Nagłówek podrozdziału Podtytuł podrozdziału - + Nagłówek aktu Podtytuł aktu @@ -37,6 +38,210 @@ Śródtytuł Nagłówki powinny tworzyć prawidłową strukturę. Użyte elementy: tytuły i podtytuły części, rozdziału, podrozdziału, aktu i sceny, oraz śródtytuł. + + + + Akapity + + Zwykły akapit. + + Kontynuacja akapitu. + + --- Akapit dialogowy. + + Zastępnik wersu w akapicie: + . . . . . . . . + + Poezja cytowana w akapicie dialogowym (?): + --- Cytat + + + + + + + Dramat + + + + Lista osób + + + Pustelnik --- pustelnik + + + Hesia --- Hesia + + + + + + + + PUSTELNIK + + + + Więc jako dawniej czynili mocarze,/ + Z Lechem się mieniał Scyta na obrączki;/ + A pokochawszy mocniej sercem, w darze/ + Dał mu koronę... stąd nasza korona./ + Zbawiciel niegdyś wyciągając rączki/ + Szedł do niej z matki zadumanej łona/ + I ku rubinom podawał się cały/ + Jako różyczka z liści wychylona,/ + I wołał: caca! i na brylant biały/ + Różanych ustek perełkami świecił. + + + + Słychać głos Hesi. + + GŁOS HESI + + + + Mamuńciu, tak zimno! troszkę ciepłej wody... + + + + DULSKA + + + + Jeszcze czego? Hartujcie się... Felicjan! wstajesz? Wiesz? ten błazen, twój syn, nie wrócił jeszcze do domu! Co? nic nie mówisz? naturalnie. + Ojciec toleruje. Niedaleko padło jabłko od jabłoni. Ale jak będą dłużki małe --- nie zapłacę. + + + + + + + Wyróżnienia + + Wyróżnienia: + didaskalia tekstowe, + didaskalia, + indeks dolny, + osoba, + słowo obce, + tytuł dzieła, + większe odstępny, + wyróżnienie, + https://wolnelektury.pl/. + + + + + + Grupy + + Długi cytat: + + + Długi cytat, akapit. + Kontynuacja akapitu. + --- Akapit dialogowy + + Strofa/ w/ cytacie + + Didaskalia (czy tak?) + + + Cytat w cytacie! + Kontynuacja akapitu w cytacie + --- Akapit dialogowy w cytacie + + + + + Poezja/ cytowana/ w cytacie + + + + + + + ... + + + + Rozdział w cytacie + Podrozdział w cytacie + Śródtytuł w cytacie + + + + + + Nota w cytacie + + + Asterysk: + + + Światło: + + + Separator linia: + + + Koniec cytatu. + + + + Tekst za cytatem. + + + Cytat poetycki: + + + Nagłówek rozdziału + Nagłówek podrozdziału + Śródtytuł + Nagłówek: osoba + + + + Nota + + + + Akapit + + Strofa/ w/ cytacie + + didaskalia? + + + + Strofa/ w/ kwestii/ w cytacie. + + + + + Motto-podpis + + + + + Poezja/ + cytowana/ + w cytacie/ + poetyckim + + + + Asterysk: + + + + + + + + + Strofa w przypisie @@ -95,6 +300,114 @@ + + + + + Wzory + + + Wzór: + + δ + = + + + e + ⁢ + F + ⁢ + l + × + + + l + 2 + + + + h + + + + + m + ⁢ + + v + 2 + + + + + + + + + + + Separatory + + + Asterysk: + + + Światło: + + + Separator linia: + + + + + + Tabele + + Tabela bez ramek: + + + + + Komórka 1 + + + Komórka 2 + + + + + Komórka 3 + + + Komórka 4 + + + + + Tabela z ramkami: + + + + + + Komórka 1 + + + Komórka 2 + + + + + Komórka 3 + + + Komórka 4 + + + + + Ilustracje + + diff --git a/tests/uat/parent.xml b/tests/uat/parent.xml new file mode 100644 index 0000000..544032a --- /dev/null +++ b/tests/uat/parent.xml @@ -0,0 +1,15 @@ + + + + Radek Czajka + Test Parent Document + 2020-01-08 + Fundacja Nowoczesna Polska + pol + wl-test-parent + gnu agpl + main + part2 + + + diff --git a/tests/uat/part2.xml b/tests/uat/part2.xml new file mode 100644 index 0000000..2459748 --- /dev/null +++ b/tests/uat/part2.xml @@ -0,0 +1,25 @@ + + + + Radek Czajka + Test Document, Part 2 + 2020-01-08 + Fundacja Nowoczesna Polska + pol + part2 + gnu gpl + + + + + +Wolne Lektury +Testy +Podtytuł + + + Druga część. Powinna być widoczna + + + +