From 4edcff3a9e2a4bb2ecb7ab228e5bf37dd28d7e14 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Mon, 5 Jul 2010 13:48:18 +0200 Subject: [PATCH] initial epub support --- librarian/epub.py | 359 +++++++++++++++++++++++++++ librarian/epub/logo_wolnelektury.png | Bin 0 -> 9286 bytes librarian/epub/style.css | 317 +++++++++++++++++++++++ librarian/epub/xsltAnnotations.xsl | 77 ++++++ librarian/epub/xsltContent.xsl | 46 ++++ librarian/epub/xsltScheme.xsl | 342 +++++++++++++++++++++++++ librarian/epub/xsltTitle.xsl | 91 +++++++ 7 files changed, 1232 insertions(+) create mode 100644 librarian/epub.py create mode 100644 librarian/epub/logo_wolnelektury.png create mode 100644 librarian/epub/style.css create mode 100644 librarian/epub/xsltAnnotations.xsl create mode 100644 librarian/epub/xsltContent.xsl create mode 100644 librarian/epub/xsltScheme.xsl create mode 100644 librarian/epub/xsltTitle.xsl diff --git a/librarian/epub.py b/librarian/epub.py new file mode 100644 index 0000000..50f9562 --- /dev/null +++ b/librarian/epub.py @@ -0,0 +1,359 @@ +# -*- coding: utf-8 -*- +# +# This file is part of Librarian, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# +from __future__ import with_statement + +import os +import os.path +import shutil +import sys +from copy import deepcopy +from lxml import etree +import zipfile + +from librarian import XMLNamespace, RDFNS, DCNS, WLNS, XHTMLNS + +NCXNS = XMLNamespace("http://www.daisy.org/z3986/2005/ncx/") +OPFNS = XMLNamespace("http://www.idpf.org/2007/opf") + + +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) 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) + xyz + """ + + + p = etree.fromstring('%s' % text) + node.text = p.text + node[:] = p[:] + + +def node_name(node): + """ Find out a node's name + + >>> print node_name(etree.fromstring('XYZ')) + XYZ + """ + + tempnode = deepcopy(node) + + for p in ('pe', 'pa', 'pt', 'pr', 'motyw'): + for e in tempnode.findall('.//%s' % p): + t = e.tail + e.clear() + e.tail = t + etree.strip_tags(tempnode, '*') + return tempnode.text + + +def xslt(xml, sheet): + if isinstance(xml, etree._Element): + xml = etree.ElementTree(xml) + with open(sheet) as xsltf: + return xml.xslt(etree.parse(xsltf)) + + +_resdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'epub') +def res(fname): + return os.path.join(_resdir, fname) + + +def replace_characters(node): + def replace_chars(text): + if text is None: + return None + return text.replace("&", "&")\ + .replace("---", "—")\ + .replace("--", "–")\ + .replace(",,", "„")\ + .replace('"', "”")\ + .replace("'", "’") + if node.tag == 'extra': + node.clear() + else: + node.text = replace_chars(node.text) + node.tail = replace_chars(node.tail) + for child in node: + replace_characters(child) + + +def find_annotations(annotations, source, part_number): + for child in source: + if child.tag in ('pe', 'pa', 'pt', 'pr'): + annotation = deepcopy(child) + annotation.set('number', str(len(annotations)+1)) + annotation.set('part', str(part_number)) + annotation.tail = '' + annotations.append(annotation) + tail = child.tail + child.clear() + child.tail = tail + child.text = str(len(annotations)) + if child.tag not in ('extra', 'podtytul'): + find_annotations(annotations, child, part_number) + + +def replace_by_verse(tree): + """ Find stanzas and create new verses in place of a '/' character """ + stanzas = tree.findall('.//' + WLNS('strofa')) + for node in stanzas: + for child_node in node: + if child_node.tag in ('slowo_obce', 'wyroznienie'): + foreign_verses = inner_xml(child_node).split('/\n') + if len(foreign_verses) > 1: + new_foreign = '' + for foreign_verse in foreign_verses: + if foreign_verse.startswith('', foreign_verse, '')) + set_inner_xml(child_node, new_foreign) + verses = inner_xml(node).split('/\n') + if len(verses) > 1: + modified_inner_xml = '' + for verse in verses: + if verse.startswith('', verse, '')) + set_inner_xml(node, modified_inner_xml) + + +def add_to_manifest(manifest, partno): + """ Adds a node to the manifest section in content.opf file """ + partstr = 'part%d' % partno + e = manifest.makeelement(OPFNS('item'), attrib={ + 'id': partstr, + 'href': partstr + '.html', + 'media-type': 'application/xhtml+xml', + }) + manifest.append(e) + + +def add_to_spine(spine, partno): + """ Adds a node to the spine section in content.opf file """ + e = spine.makeelement(OPFNS('itemref'), attrib={'idref': 'part%d' % partno}); + spine.append(e) + + +def add_nav_point(nav_map, counter, title, part_counter): + nav_point = nav_map.makeelement(NCXNS('navPoint')) + nav_point.set('id', 'NavPoint-%d' % counter) + nav_point.set('playOrder', str(counter)) + + nav_label = nav_map.makeelement(NCXNS('navLabel')) + text = nav_map.makeelement(NCXNS('text')) + text.text = title + nav_label.append(text) + nav_point.append(nav_label) + + content = nav_map.makeelement(NCXNS('content')) + content.set('src', 'part%d.html' % part_counter) + nav_point.append(content) + + nav_map.append(nav_point) + + +def add_nav_point2(nav_map, counter, title, part_counter, subcounter): + nav_point = nav_map.makeelement(NCXNS('navPoint')) + nav_point.set('id', 'NavPoint-%d' % counter) + nav_point.set('playOrder', str(counter)) + + nav_label = nav_map.makeelement(NCXNS('navLabel')) + text = nav_map.makeelement(NCXNS('text')) + text.text = title + nav_label.append(text) + nav_point.append(nav_label) + + content = nav_map.makeelement(NCXNS('content')) + content.set('src', 'part%d.html#sub%d' % (part_counter, subcounter)) + nav_point.append(content) + + nav_map[-1].append(nav_point) + + +def transform(input_file, output_file): + """ produces an epub + + input_file and output_file should be filelike objects + """ + + input_xml = etree.parse(input_file) + + zip = zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED) + + mime = zipfile.ZipInfo() + mime.filename = 'mimetype' + mime.compress_type = zipfile.ZIP_STORED + mime.extra = '' + zip.writestr(mime, 'application/epub+zip') + + zip.writestr('META-INF/container.xml', '' \ + '' \ + '') + + metadata_el = input_xml.find('.//'+RDFNS('Description')) + metadatasource = etree.ElementTree(metadata_el) + + opf = xslt(metadatasource, res('xsltContent.xsl')) + + manifest = opf.find('.//' + OPFNS('manifest')) + spine = opf.find('.//' + OPFNS('spine')) + + for fname in 'style.css', 'logo_wolnelektury.png': + zip.write(res(fname), os.path.join('OPS', fname)) + + annotations = etree.Element('annotations') + part_xml = etree.Element('utwor') + etree.SubElement(part_xml, 'master') + + toc_file = etree.fromstring('' \ + '' \ + '' \ + 'Strona tytułowa' \ + '' \ + 'Początek utworu' \ + '') + + main_xml_part = part_xml[0] # było [0][0], master + nav_map = toc_file[-1] # było [-1][-1] + depth = 1 # navmap + + if len(input_xml.getroot()) > 1: + # rdf before style master + main_text = input_xml.getroot()[1] + else: + # rdf in style master + main_text = input_xml.getroot()[0] + + replace_characters(main_text) + zip.writestr('OPS/title.html', + etree.tostring(xslt(input_xml, res('xsltTitle.xsl')), pretty_print=True)) + + # Search for table of contents elements and book division + + stupid_i = stupid_j = stupid_k = 1 + last_node_part = False + for one_part in main_text: + name = one_part.tag + if name in ("naglowek_czesc", "naglowek_rozdzial", "naglowek_akt", "srodtytul"): + if name == "naglowek_czesc": + stupid_k = 1 + last_node_part = True + find_annotations(annotations, part_xml, stupid_j) + replace_by_verse(part_xml) + zip.writestr('OPS/part%d.html' % stupid_j, + etree.tostring(xslt(part_xml, res('xsltScheme.xsl')), pretty_print=True)) + main_xml_part[:] = [deepcopy(one_part)] + # add to manifest and spine + add_to_manifest(manifest, stupid_j) + add_to_spine(spine, stupid_j) + name_toc = node_name(one_part) + # build table of contents + # i+2 because of title page + add_nav_point(nav_map, stupid_i+2, name_toc, stupid_j + 1) + stupid_i += 1 + stupid_j += 1 + else: + if last_node_part: + main_xml_part.append(one_part) + last_node_part = False + name_toc = node_name(one_part) + add_nav_point(nav_map, stupid_i + 1, name_toc, stupid_j) + else: + stupid_k = 1 + find_annotations(annotations, part_xml, stupid_j) + replace_by_verse(part_xml) + zip.writestr('OPS/part%d.html' % stupid_j, + etree.tostring(xslt(part_xml, res('xsltScheme.xsl')), pretty_print=True)) + # start building a new part + main_xml_part[:] = [deepcopy(one_part)] + add_to_manifest(manifest, stupid_j) + add_to_spine(spine, stupid_j) + name_toc = node_name(one_part) + add_nav_point(nav_map, stupid_i + 2, name_toc, stupid_j + 1) # title page + stupid_j += 1 + stupid_i += 1 + else: + if name in ('naglowek_podrozdzial', 'naglowek_scena'): + depth = 2 + name_toc = node_name(one_part) + add_nav_point2(nav_map, stupid_i + 2, name_toc, stupid_j, stupid_k) + one_part.set('sub', str(stupid_k)) + stupid_k += 1 + stupid_i += 1 + main_xml_part.append(deepcopy(one_part)) + last_node_part = False + find_annotations(annotations, part_xml, stupid_j) + replace_by_verse(part_xml) + add_to_manifest(manifest, stupid_j) + add_to_spine(spine, stupid_j) + + zip.writestr('OPS/part%d.html' % stupid_j, + etree.tostring(xslt(part_xml, res('xsltScheme.xsl')), pretty_print=True)) + + # Last modifications in container files and EPUB creation + if len(annotations) > 0: + nav_map.append(etree.fromstring( + 'Przypisy'\ + '' % {'i':stupid_i+2})) + manifest.append(etree.fromstring( + '')) + spine.append(etree.fromstring( + '')) + replace_by_verse(annotations) + zip.writestr('OPS/annotations.html', etree.tostring( + xslt(annotations, res("xsltAnnotations.xsl")), pretty_print=True)) + + zip.writestr('OPS/content.opf', etree.tostring(opf, pretty_print=True)) + contents = [] + title = node_name(etree.ETXPath('.//'+DCNS('title'))(input_xml)[0]) + attributes = "dtb:uid", "dtb:depth", "dtb:totalPageCount", "dtb:maxPageNumber" + for st in attributes: + meta = toc_file.makeelement(NCXNS('meta')) + meta.set('name', st) + meta.set('content', '0') + toc_file[0].append(meta) + toc_file[0][0].set('content', ''.join((title, 'WolneLektury.pl'))) + toc_file[0][1].set('content', str(depth)) + set_inner_xml(toc_file[1], ''.join(('', title, ''))) + zip.writestr('OPS/toc.ncx', etree.tostring(toc_file, pretty_print=True)) + zip.close() + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print >> sys.stderr, 'Usage: wl2epub [output file]' + sys.exit(1) + + input = sys.argv[1] + if len(sys.argv) > 2: + output = sys.argv[2] + else: + basename, ext = os.path.splitext(input) + output = basename + '.epub' + + wl2epub(open(input, 'r'), open(output, 'w')) + + + diff --git a/librarian/epub/logo_wolnelektury.png b/librarian/epub/logo_wolnelektury.png new file mode 100644 index 0000000000000000000000000000000000000000..104d56ae9689e39163bc31a177651e5f9354b9ac GIT binary patch literal 9286 zcmV-MB)Qv(P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L00R;L00R;M?;&9$00007bV*G`2igW1 z3nd27<>GGu03ZNKL_t(|+U=cZU|iL;?|)~ydhf-uBzGCPR~a|lFyI1&9z#OEaODtM@KhT{D^)O+W9$8ILqpxBbj@nDxb) z<6YKX`+wG6Ywfl75kyfGxk_p`R`7B0y#%S^iT0mCtj~0!{iorh2;usYh+SU@raI)I z%K!ln-8dv%3oz;|4Q#xy5FbSZ-L`fdSOEx9k0#c44xb}brtfa|#o8BuJ_lIBAc`c<$@~YuEnZ$l<1$#4C}#P5n_C&5ulDIxAl|3U3fvx#E`X=b{xcRw-N6@AAs`quX@1M zU5nV6foz!0h@tOYPyc$uZkpCokY3r zNRQ*vvK>(qhdgBA@W9w{2!}crneTYdta`xc1X<{MEDk-TZTkl;7ph4n(kqqo%^w4h z;GagV?l=z7CTYgz9mpacWXQm^!-Bo_AhhmB9(0RmMm=EcA%9gg@qTkT)BFL|y5qpW zG4+)2yD8Tmrn9?_c>j4gu+m~ILhNn;?I~nY5AR8$7mfMYTR(?@xyXEy z+?|xJbJz=?#hN)9NB)C|+Dv3o4L+;6gHMsHwJ{Qqb)$}g1-DLZL47E{=^ zgS^&H$ZC9-IKSCU3R%zCkX5K;-Y8@$=0!crS2h1de87BUf&x*rL(3jy(GN)gw3)Ft ze2Cca0fI3fQ5B64^$feE-3BuPPkA56k@B$YAMN>VFhJPSx zv!J^KA?Oz56aM6xRSy`456pU9Hl>~WDepMM^3ksl=Rb!k?JQK!tX*6c^{}lJu~S6<8alX z155UKZ0U!w9zKG-un0kPINk36e7A2ynUv&K-kOz)U@Gqcs5}UQ7a z3W8UhXSO_G9KrHiSBH7?$Jk3su;u1MOAA6=JnHppQKT(EF?%L5A0M#UFz?=t@egky zi;qXSRI>9-77LXPO~i$TAjsuB_}W>fPe^9z30|F_lGW8U&FtXsF@(CSd%doP-2p8;bxVstbce)ASZ)pd-D4COD+ zKShUL&lee|*`IY52e4@BB$myb%AAyO9$)zKen@HK@d>RpO5D4KcZN%0=Y)h1J=(!M=^Ug zDlh2_OK6ZkKY8#@o_%X08&)r7Ok4~qg@UCsQ&~DQl~!#R`?AimGvgFn4<2PyWEfAZ zTg8gmQ$4fk(Tu%(7NZfvqfcNvaRN~kkx!X|^41loRxJhDIDV9X&p*Ta@y7=QqUFpP?A5iXmP-k-_OXz2o7XU%2>WUddf4K9x(QDRx&bBEm|Y(+)T(t_gV;bmr9_U;3V z1@-DxI6DaWO;$1(KCp1i*^fQz@*fqqMeu(6$y%pG=^y4||3ITn~K^ zfhY(l(&i7Vy!o@wP%K`A5D>r-UZxiDm#vs1=V*W5;JQ}Y$^|4H$8`B%|>RA@6i zNV*2}(%=8ZkKXy<8vvujfi3$S%GooA25oL0-7mk25DS)1asmla z5$tv@xl3lGQs2@>an0aM^_+=g0LU(`xS}E0MGFA+x^K=AI(=~?UseD5-vW${t?d+6 z)nT#Ot}hs^g@p(P1Bz+W`p0T}JEjl*j&{W=^mnYqnsWi~U;kfFNjF5uWCA9O6`S1- zz|?W0DXf%^DJ+~e8M#cxSEmL)iyh$S%Y=kD&J>ql(HH_Xi2$^lE3R4|X1jq_W9f+N z<+N<&e9K3D&X3=SBo`!TY4yfo*SRJ;Ft#&N_(eW-N)JE_3a}kLhV95vtfx2GgN75AnSP#WP%KEpwk-&4)7;AI*J|XSs08ae7!X+NS(m@I}ebVTgcqW<4Bu4 zfs~|#KKs)%CM0tp>)aKMAw-=(HAiUeF28Ddlyw{=v;Hj}PfZ`0c6LbjTAFQoP~F&I zR4AnR?a~_w3-rH^U_5;q0s^q^-G}kyDePHUh;8kNayjyuGw^=(Wt1ydAouJ4vQU{! zI!2%~b`u=n&!TB5G<9_1rIBXj*H1ji7e`NWJg1P4_aEWIU0>m&Q8RPG7^Y85=BCl3 z7@H8wjB&|)wD&Nz%`L=*hmB|qL0$>cn{2MeZnq(qU%6uEL=5biT^_|}fo zRIu5*Z+Ok9aLTV;-$f#k*AI;L;u6qmF~0O0%4N~!O1?bjm$qun9dS2ip+JQ)4Fy#VO!GF;zf+UNJL;xHOf zPMs>{D~>e2B$K-|<4~klshE>8o;fMwfjcl5O?`!EEnBEg$+~{Z3O2cF}?$2%K;Em`dGYEOs+ChY5#hWlH${BnB?J;WT4MSJw>& zMyJiF)qk_gQ;<4Q0;Ad8qqf>id{Oo!)%r}g=fxd+DCyYW?|tNc%5aRf7CKDTMEaz- zo_AY15wS_y6R6c@aj51c+RbGyIn;C=gRaY05BUuR#$cyrY}egjV7#_s9}v-`w&ATMiz>HI)#j zbl-jQQA(Px%~b4qmRa{E-F7LnNN;T-)GLX*#{C0@Oi8%c1patdvU?K)7cn#Pu^R$( z4u^y0_D&Q^C7}U5=18Egj|(HBD7v)%h`{*V+wb$#`c;gH8~TGj?`+#iVO1T4RduYM zJDn-xBoFk^>GSM4eulF}73jO&m)?)|r1RDfzt804(Y?_qEn#NKfH#=TJod`FJbK4+ zo?O35^2)SbWai{!wc1!YZw9_zeL?#1!6R(ipYHlSeOw|ItApH%DssxI*t9pDN7oE| znW#n{==xi4X+`4|KvBmoNx14nZXNvwa+v~$Xyau4dmuRQR)i4cb5lRz9SMvrh7##t zV+na}pMe1WsyO2PW&sf6+jCsv(xjPfL+@JTwru08n%{6!*u5-?|G7(x11J?S6|m?C>ID!W-}*pd)|5<=MwmrPxtV_ zu7dz1L`CqOrD^QTI!i-qyJV>A4gCDCo7wW47x2-jomdo{no$B{m)?K~oX9KUiFGS^ z_mf@xW6#&FzW%V~3*Pv_Bg{|jiQ(mxRq@uAF93)R4d(S9Ji_=Fie1++8RMN~UCY<#XsQjdYl*F*!OAkh3uEMHDi1-|&t~ig~s; zHRF-m-+>@$>jlyOiA+%R<3h;+2UfemDmMuIoX&+ik17Fv?M60RDRi{>ef*{Q(43<{%+CC*Ia4E@`-D#QE`Wf|I zXP6)RBYc&8FG{FsY$iS`oUI2kcy04`m&UU@9DI57B(=>gZ2ajn#Ds+q=<7qL-oUAX zl3{_d&)&2sisV<-xc&bAEAQ~|%kS{&hyQXt&&n%yZGuluPGC%I6nSM;yub4R0ITOt z=aW}{%zxZ@0YLfMMjnc#$KAy zXl=t=6$GNhTx)kRrJZ|eG@i#~*AnGDg?q+tVPeP~g9g6!)<#O&_EFs>UA!ORHHq<| zw+&!BOYv5#({`-ao#S-VMhe%lF^VBhkES=Hw{T8jhZ)D!=)QozQ*{K)c z*o6YuO1^sTbbP&}C8(ykmCT&NUTV^pLLd}Uw@CRJZYJH_B*#Z1LYFE zw_`7_Z{9&kZ6jL`W;iutu$yL7$$bd*9t(gR6>F0J%7YVj@XVCc+&}RXw>dX|-mzr$Y>jnWCm+O8~D8#afT{nbBpwcBLK@9UHV1t5wdN6zK5 zeAX1UzWig-rcA`&$D7;JW)tGH8S^S7oGh6x-ItkHQA1%>?a09>mkHE1wbIh5!(cM= zr)|4>ywvs%Oco3Ov-@jGY8$2H$lHtMGo?xCZ~{yeMGl{F&$6j+X=7in^DMEEVZCR; zWnTaUc=h#qUwZU@e*MIQ%$Ypa^{l+Uu?O5nNt={6G_mXlzu?99HgUeR5`|pGcULXu zySFZN1LDRn4!C|le47;DR?*Y1(ISC6(O*h)vt!|K&C7J#b*Pp8eE^u#yoG<}ujSqB zDV%8d3nAXgCYHmhC=X0YpG>R@m;hSi~5-i35+&T0;7*S#Myoa7n(n%u`7r4 zn%}ag;yJf^?dEbW8uEzrb^ln?s?o2rBH#F z>BNMG(9qgWSxr4RC5__vg(6Pm7g5*TMpK6b!m;r&PP0MAbN8;{={MfPVzaR~OUl?! zj)@$eX1uhN9y*i5;j>bP_4rY-TsmI;>DMQ)*&VJW@u@pky6VP+h4Ax-zvBw=G<9hC z;^;}vmsYxfI4UxXSDt>bkLfPij1m}qG#Y%odYpoXZe7yjWT<;SI8@O~Gv1aq3$?Q6 z-O{L)v}tu@oX_RseMk7^#?9RJ{L5}YT#!1E|8w_kZW{X1I8DywRxVd?d(t~ZdiQ9Z zHd86p`b;Wxhbikk=mH`@q<1Qd;(q4(`w}f5^(uj0vD}gL7XnmqSR8sjDf%w0PH!8) zfn)>sBuWUZ9Q_)h8uzVEjVy?z@h|bf_)ncq57-5%?yShi@Kr>xDE21|bgQpY;l=vo z_X$w-+{U30yqOj8BnkdEJDmjqr9wkyZXutgXSqz7$RJ5k6xTLz@N^E(zO|992aj?r zr$>|CKELM$n=^Sl8-Ml#(o!cfAt8?M-?ofbpV}}y&A5KiJSyrhvgM#;aHrigk=LHt zz+2mPvF%XL*RQ6IOXRhuH=w>OZg+dyY{rj@<-P5DIiB0&i}i|6jWgEcqLaeJr?v|Z36kvAx<*#cneG-tj0_3n7Z2Yu(2`_fsnV3sRf)7jO<>B4emPa5k6-n{Y}HvHyI*Y8cgdd}^>9c`DM z-+%NOC-RE>WC6v5g)n>4Se{z9lHh>;6F!gEzs>238~M)I%|!Y2^W|32j@HzO!FmzB zwHb{fm9D0%!belxEBww`F?aNX}*zbA#P@3)*vE_XRm zI)mYw@}S@bq!|;(@bcpiP~FsW)p?Bnn`mbA<4g!$>)O4!o|IYtCN14kY%x$Zs$UZY za5J@Z`fdXK{Jz~_1nGSBzaxDUK&;kgakBAm2!iB{-7@M|0|TblvaG$v`KJmz^sOZa z4ze$P$kDn#xZ;&*(a$m}AZ@@pa%GQZG<18w=%K45t+|fUjsq07eeOyG0Z0m1&YYP4 z7_@HhG%>T)<^iLJh7onJYuS{)4z0N!g-nTn0*7do4t)vk0Tcl_^JAW4cGP1G_4&Kl zuuy!xy)awMB*sKsQ=V_Q(2j?ONA2Aee3-vt&@!SZ66ZIYwAknSP5Ky!DjO~$2m%RF z9x!@nm{i=pkE+fiw3te0>n=qhQ{$_Oz(*NLjL&o?h1`L^Cgy()zgG;#Q>Sw&E~;e3 z$~3~mf`=@B{KR>RiYi#LWHt$-u3P}ScORis+r{$bX@vDksIXY9h@yyEts1aQZyutf z!d>OBmPRUz-qf4#Z#!La(7U;*jq-|G48y$Gr?s_%nwmz8hO0YtWwY5SEv=^Gvb+EG z?mNowe*ZpavI_<*)0>ChnN~>A8Xcie6X9x`mWZn8(2nh5i=UgG#=L%_QZfE(* zG-gce|E`*hqh}~9t06orn1>%;M|pV-dP6s%p+Ph>wDeo1H}x(L^vm<1Lnp}1l~TOU zWfwALYy!c7{+vHwMCS2xL`H zE9P_f>ys>5GKcD#hJM=&2@dR2|J146e*5W9HvjzS3w(UMxpVz8HgDcVSXdCtm(SU z+r(#|9>COX#!I87prD-7r}GF63qlk{cJE53@nVZxr)sqdv&G7>qi0D-h^DT-iTu1W z4j#y4=dN@tW(#Qxrm<`1VUC~Z|C1VJWi`y7Kb7`&Em>JPAd1x2H(}_tE6}HmyDRA` zKM>D}iLuD!l8CG}8tnc>VUy{_sxb4YneB13Ob#hkl+B;uj{#oX5YS}=(-FnUObzyuwY6{rCh&d%jPk2 zMhXs5q^72^-_E_gH7r~xWpL{aMs8U;m-XvzVe#VGWIJuB^0JzK>n>O@omsPP!e+PA z*6X0SN~IjKOm9-Dlmqgdm>5UuP10fdrAy{8ecD8-D(Y~EBFk=(&i!Su9 zGY4(6-*JpUHX%+kEkC~uwMvQEV&z=6w3{<-T*4KN-AywpRZ1RtcpWyooo)Zx=bF4- zyVB9=^ekOEhv+Ex^RE%%A&8>L_8o^1MbWi{o6HtEwbF!!IPJ2_DK5500Ct<5jEpnn z=a(^W?v!CMUsu-zKxAa-Rh1bD&zG`R)~;E?Baf^nVN~>hvKZ-j29nE2`B=DcW}iI6 z%iA2R{%~Xy5h;A{GE`HKn%ui&YdqL zJG+4V{4%_~H8@0(J$o|T-quyOE@0f)1Zrv;*}W%&205b0Jqp{ zH=wejj>w2m^m^lf%c@JDb{iKi6yxLV#n>?kh{Gt;U%!_?G!W01x0{?C?`+#adip8$ z?LX%7QZJXqaKnvD+Q^ z`g#)<8aSf4>=%p+7tJET-`8dAhlB)DSSX?0Xf$!?&Pd@|6Mx#~{ z6eO8(5fLFoMN8nkv~mt-?EURex{<|V70b$N#fFAvQ4~e7OK%XfPUeW!)eT}thgR%1 znMF|)MYGu=78I0=-Q6ZvIlJ91ilQi*OlGmXyhc2AI#=xI(2AlciUwo1c=~L<*s1Lj zjol`(th`pV+U=sl;SlTUo5bdp4p9_Ev8kz5tgdcw@zSa7a^tVPT`Oj0W{b78jpBt1 z#iH44ag{ADsT5mUI|eM%n}^=z2jck>Ro66#dcD!@S$#vZSX*~-NLdUup5A;6CYRyx zVYS=Eipn}stJAywf2cNl*B_{#fn=lC8^xTQBGGKNh$gdHEGQ@!OUtTV|3B2&FDK95 ow1;l|?LZHC$OA?X{oB(214ThC5Fda4sQ>@~07*qoM6N<$g62t0NdN!< literal 0 HcmV?d00001 diff --git a/librarian/epub/style.css b/librarian/epub/style.css new file mode 100644 index 0000000..652d903 --- /dev/null +++ b/librarian/epub/style.css @@ -0,0 +1,317 @@ +body +{ + font-size: 12pt; + font: Georgia, "Times New Roman" , serif; + line-height: 1.5em; + margin: 0; +} + +a +{ + color: black; + text-decoration: none; +} + +#book-text +{ + margin: 2em; + /*margin-right: 9em;*/ +} + +/* =================================================== */ +/* = Common elements: headings, paragraphs and lines = */ +/* =================================================== */ + + +.h2 +{ + size: big; + font-size: 2em; + margin: 0; + margin-top: 1.5em; + font-weight: bold; + line-height: 1.5em; +} + +.h3 +{ + text-align:left; + font-size: 1.5em; + margin-top: 1.5em; + font-weight: normal; + line-height: 1.5em; +} + +.h4 +{ + font-size: 1em; + margin: 0; + margin-top: 1.5em; + line-height: 1.5em; +} + +p +{ + margin: 0; +} + +/* ======================== */ +/* = Footnotes and themes = */ +/* ======================== */ + +.theme-begin +{ + border-left: 0.1em solid #DDDDDD; + color: #777; + padding: 0 0.5em; + width: 7.5em; + font-style: normal; + font-weight: normal; + font-size: 0.875em; + float: right; + margin-right: -9.5em; + clear: both; + left: 40em; + line-height: 1.5em; + text-align: left; +} + +.annotation +{ + font-style: normal; + font-weight: normal; + font-size: 0.875em; +} + +#footnotes .annotation +{ + display: block; + float: left; + width: 2.5em; + clear: both; +} + +#footnotes div +{ + margin: 0; + margin-top: 1.5em; +} + +#footnotes p +{ + margin-left: 2.5em; + font-size: 0.875em; +} + +.block +{ + font-size: 0.875em; + padding: 1em; +} + +/* ============= */ +/* = Numbering = */ +/* ============= */ + +.anchor +{ + margin: -0.25em -0.5em; + color: #777; + font-size: 0.875em; + width: 2em; + text-align: center; + padding: 0.25em 0.5em; + line-height: 1.5em; +} + +/* =================== */ +/* = Custom elements = */ +/* =================== */ + +.title-page +{ + margin-top: 1.5em; +} + +.title +{ + font-size: 3em; + margin-bottom: 1.5em; + text-align: center; + line-height: 1.5em; + font-weight: bold; +} + +.author +{ + margin: 0; + text-align: center; + font-weight: bold; + + font-size: 1.5em; + line-height: 1.5em; + margin-bottom: 0.25em; +} + +.collection +{ + margin: 0; + text-align: center; + font-weight: bold; + + font-size: 1.125em; + line-height: 1.5em; + margin-bottom: -0.25em; +} + +.subtitle +{ + margin: 0; + text-align: center; + font-weight: bold; + + font-size: 1.5em; + line-height: 1.5em; + margin-top: -0.25em; +} + +div.didaskalia +{ + font-style: italic; + margin-top: 0.5em; + margin-left: 1.5em; +} + +div.kwestia +{ + margin-top: 0.5em; +} + +div.stanza +{ + margin-top: 1.5em; +} + +.paragraph +{ + text-align: justify; + margin-top: 1.5em; +} + +.motto +{ + text-align: justify; + font-style: italic; + margin-top: 1.5em; +} + +.motto_podpis +{ + font-size: 0.875em; + text-align: right; +} + +div.fragment +{ + border-bottom: 0.1em solid #999; + padding-bottom: 1.5em; +} + +div.note +{ + text-align: right; + font-style: italic; +} +div.note div.paragraph +{ + text-align: right; + font-style: italic; +} +div.dedication +{ + text-align: right; + font-style: italic; +} +div.dedication div.paragaph +{ + text-align: right; + font-style: italic; +} + + +hr.spacer +{ + height: 3em; + visibility: hidden; +} + +hr.spacer-line +{ + margin: 0; + margin-top: 1.5em; + margin-bottom: 1.5em; + border: none; + border-bottom: 0.1em solid #000; +} + +.spacer-asterisk +{ + padding: 0; + margin: 0; + margin-top: 1.5em; + margin-bottom: 1.5em; + text-align: center; +} + +div.person-list ol +{ + list-style: none; + padding: 0; + padding-left: 1.5em; +} + +.place-and-time +{ + font-style: italic; +} + +em.math +{ + font-style: italic; +} +em.foreign-word +{ + font-style: italic; +} +em.book-title +{ + font-style: italic; +} +em.didaskalia +{ + font-style: italic; +} + +em.author-emphasis +{ + letter-spacing: 0.1em; +} + +em.person +{ + font-style: normal; + font-variant: small-caps; +} + +p.info +{ + text-align: center; + margin-bottom: 1em; +} + +p.info img +{ + margin: 0; + margin-left: 2em; + margin-right: 2em; +} diff --git a/librarian/epub/xsltAnnotations.xsl b/librarian/epub/xsltAnnotations.xsl new file mode 100644 index 0000000..d0af8ab --- /dev/null +++ b/librarian/epub/xsltAnnotations.xsl @@ -0,0 +1,77 @@ + + + + + + + + + + + + + <xsl:text>Przypisy</xsl:text> + + + +
+
+

+ Przypisy: +

+ +
+
+ + +
+ + + + + + +
+

+ + [] + +

+ +

+
+
+ + + + + + + + +

+ +

+
+ + +
+ +
+
+ + + + „ + + ” + + + + +

+ +

+
+ +
\ No newline at end of file diff --git a/librarian/epub/xsltContent.xsl b/librarian/epub/xsltContent.xsl new file mode 100644 index 0000000..548bcb7 --- /dev/null +++ b/librarian/epub/xsltContent.xsl @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/librarian/epub/xsltScheme.xsl b/librarian/epub/xsltScheme.xsl new file mode 100644 index 0000000..109b1cc --- /dev/null +++ b/librarian/epub/xsltScheme.xsl @@ -0,0 +1,342 @@ + + + + + + + + + + + + + WolneLektury.pl + + + + + book-text + + + + + + + + + + + + + + + + +
+ +
+
+ + +
+
+ +
+
    + +
+
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + + + + + +

+ +

+
+ + + + +

+ +

+
+ + + + +

+ +

+
+ + + + +

+ +

+
+ + + + +

+ +

+
+ + +

+ +

+
+ + + +

+ +

+
+ + + +

+ +

+
+ + +

+ +

+
+ + +

+ +

+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + „ + + ” + + + + + + + + + + + + + + + + + + + + +
  • + +
  • +
    + + + + + + +
    +
    + + +

    *

    +
    + + +
    +
    + + + + + + + + + + + + + + + + + + [] + + + + + + + + + + + + + + + + + + + +
    \ No newline at end of file diff --git a/librarian/epub/xsltTitle.xsl b/librarian/epub/xsltTitle.xsl new file mode 100644 index 0000000..c69db26 --- /dev/null +++ b/librarian/epub/xsltTitle.xsl @@ -0,0 +1,91 @@ + + + + + + + + + + + + + <xsl:text>Strona tytułowa</xsl:text> + + + +
    +
    + + + + + + + + +
    +

    Publikacja zrealizowana w ramach projektu WolneLektury.pl

    +

    + WolneLektury.pl +

    +
    + + +
    + + + + + + + + + + +
    + +
    +
    + + +
    + +
    +
    + + +
    + +
    +
    + + +

    + +

    +
    + + +

    + +

    +
    + + +
    + +
    +
    + + + + + + + + + + + +
    \ No newline at end of file -- 2.20.1