1 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
5 from librarian import FB2NS, XLINKNS, OutputFile
6 from .html import TreeBuilder
9 class FB2Builder(TreeBuilder):
10 file_extension = 'fb2'
11 build_method_fn = 'fb2_build'
14 def __init__(self, base_url=None):
15 self.tree = etree.Element(
22 description = etree.SubElement(self.tree, 'description')
23 self.body = etree.SubElement(self.tree, 'body')
24 self.header = etree.SubElement(self.body, 'title')
25 self.epigraph = etree.SubElement(self.body, 'epigraph')
26 self.text = etree.SubElement(self.body, 'section')
28 self.footnotes = etree.Element(FB2NS('body'), name="notes")
34 'header': self.header,
35 'epigraph': self.epigraph,
36 'footnotes': self.footnotes,
37 #'nota_red': self.nota_red,
39 self.current_cursors = [self.text]
42 def start_section(self, precedence):
43 while self.sections and self.sections[-1] >= precedence:
46 self.start_element('section')
47 self.sections.append(precedence)
49 def add_epigraph(self):
50 self.enter_fragment('epigraph')
51 self.start_element(FB2NS('p'))
52 self.push_text('Utwór opracowany został w\xa0ramach projektu ')
53 self.start_element(FB2NS('a'), {XLINKNS('href'): 'https://wolnelektury.pl/'})
54 self.push_text('Wolne Lektury')
56 self.push_text(' przez ')
57 self.start_element(FB2NS('a'), {XLINKNS('href'): 'https://fundacja.wolnelektury.pl/'})
58 self.push_text('fundację Wolne Lektury')
64 def add_meta(self, doc):
65 self.enter_fragment('meta')
67 self.start_element('title-info')
69 self.start_element('genre')
70 self.push_text('literature')
72 for author in doc.meta.authors:
73 self.start_element('author')
74 self.simple_element('first-name', ' '.join(author.first_names))
75 self.simple_element('last-name', author.last_name)
77 self.simple_element('book-title', doc.meta.title)
78 if doc.meta.released_to_public_domain_at:
79 self.simple_element('date', doc.meta.released_to_public_domain_at)
80 self.simple_element('lang', doc.meta.language)
84 self.start_element('document-info')
86 # contributor.technical_editor
87 self.simple_element('program-used', 'Wolne Lektury Librarian')
88 self.simple_element('date', doc.meta.created_at)
89 self.simple_element('id', str(doc.meta.url))
90 self.simple_element('version', '0')
93 self.start_element('publish-info')
94 self.simple_element('publisher', '; '.join(doc.meta.publisher))
98 def build(self, doc, mp3=None):
100 doc.tree.getroot().fb2_build(self)
104 return OutputFile.from_bytes(
109 xml_declaration=True,
118 from copy import deepcopy
119 from lxml import etree
121 from librarian import functions, OutputFile
122 from .epub import replace_by_verse
125 functions.reg_substitute_entities()
126 functions.reg_person_name()
129 def sectionify(tree):
130 """Finds section headers and adds a tree of _section tags."""
133 'naglowek_akt', 'naglowek_rozdzial', 'naglowek_scena',
134 'naglowek_podrozdzial']
135 section_level = dict((v, k) for (k, v) in enumerate(sections))
137 # We can assume there are just subelements an no text at section level.
138 for level, section_name in reversed(list(enumerate(sections))):
139 for header in tree.findall('//' + section_name):
140 section = header.makeelement("_section")
141 header.addprevious(section)
142 section.append(header)
143 sibling = section.getnext()
144 while (sibling is not None and
145 section_level.get(sibling.tag, 1000) > level):
146 section.append(sibling)
147 sibling = section.getnext()
150 def transform(wldoc, verbose=False,
151 cover=None, flags=None):
152 document = deepcopy(wldoc)
157 document.edoc.getroot().set(flag, 'yes')
159 document.clean_ed_note()
160 document.clean_ed_note('abstrakt')
162 style_filename = os.path.join(os.path.dirname(__file__), 'fb2/fb2.xslt')
163 style = etree.parse(style_filename)
165 replace_by_verse(document.edoc)
166 sectionify(document.edoc)
168 result = document.transform(style)
170 return OutputFile.from_bytes(str(result).encode('utf-8'))