Basic biblical tools.
[librarian.git] / src / librarian / builders / fb2.py
1 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
3 #
4 from lxml import etree
5 from librarian import FB2NS, XLINKNS, OutputFile
6 from .html import TreeBuilder
7
8
9 class FB2Builder(TreeBuilder):
10     file_extension = 'fb2'
11     build_method_fn = 'fb2_build'
12     orphans = False
13     
14     def __init__(self, base_url=None):
15         self.tree = etree.Element(
16             FB2NS('FictionBook'),
17             nsmap={
18                 None: FB2NS.uri,
19                 'l': XLINKNS.uri,
20             }
21         )
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')
27
28         self.footnotes = etree.Element(FB2NS('body'), name="notes")
29         self.sections = []
30
31         self.cursors = {
32             None: self.text,
33             'meta': description,
34             'header': self.header,
35             'epigraph': self.epigraph,
36             'footnotes': self.footnotes,
37             #'nota_red': self.nota_red,
38         }
39         self.current_cursors = [self.text]
40         self.add_epigraph()
41
42     def start_section(self, precedence):
43         while self.sections and self.sections[-1] >= precedence:
44             self.end_element()
45             self.sections.pop()
46         self.start_element('section')
47         self.sections.append(precedence)
48
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')
55         self.end_element()
56         self.push_text(' przez ')
57         self.start_element(FB2NS('a'), {XLINKNS('href'): 'https://fundacja.wolnelektury.pl/'})
58         self.push_text('fundację Wolne Lektury')
59         self.end_element()
60         self.push_text('.')
61         self.end_element()
62         self.exit_fragment()
63
64     def add_meta(self, doc):
65         self.enter_fragment('meta')
66
67         self.start_element('title-info')
68
69         self.start_element('genre')
70         self.push_text('literature')
71         self.end_element()
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)
76             self.end_element()
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)
81         
82         self.end_element()
83
84         self.start_element('document-info')
85         # contributor.editor
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')
91         
92         self.end_element()
93         self.start_element('publish-info')
94         self.simple_element('publisher', '; '.join(doc.meta.publisher))
95         self.end_element()
96         self.exit_fragment()
97
98     def build(self, doc, mp3=None):
99         self.add_meta(doc)
100         doc.tree.getroot().fb2_build(self)
101         return self.output()
102
103     def output(self):
104         return OutputFile.from_bytes(
105             etree.tostring(
106                 self.tree,
107                 encoding='utf-8',
108                 pretty_print=True,
109                 xml_declaration=True,
110             )
111         )
112
113
114
115
116 '''
117 import os.path
118 from copy import deepcopy
119 from lxml import etree
120
121 from librarian import functions, OutputFile
122 from .epub import replace_by_verse
123
124
125 functions.reg_substitute_entities()
126 functions.reg_person_name()
127
128
129 def sectionify(tree):
130     """Finds section headers and adds a tree of _section tags."""
131     sections = [
132         'naglowek_czesc',
133         'naglowek_akt', 'naglowek_rozdzial', 'naglowek_scena',
134         'naglowek_podrozdzial']
135     section_level = dict((v, k) for (k, v) in enumerate(sections))
136
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()
148
149
150 def transform(wldoc, verbose=False,
151               cover=None, flags=None):
152     document = deepcopy(wldoc)
153     del wldoc
154
155     if flags:
156         for flag in flags:
157             document.edoc.getroot().set(flag, 'yes')
158
159     document.clean_ed_note()
160     document.clean_ed_note('abstrakt')
161
162     style_filename = os.path.join(os.path.dirname(__file__), 'fb2/fb2.xslt')
163     style = etree.parse(style_filename)
164
165     replace_by_verse(document.edoc)
166     sectionify(document.edoc)
167
168     result = document.transform(style)
169
170     return OutputFile.from_bytes(str(result).encode('utf-8'))
171
172 # vim:et
173 '''