From d1a6d405c4b90823231d2d12365cc133fc0edfa8 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Thu, 27 Oct 2011 12:00:17 +0200 Subject: [PATCH 1/1] nicer mobi --- librarian/cover.py | 7 +++ librarian/epub.py | 87 ++++++++++++++++++++++------------ librarian/epub/toc.html | 11 +++++ librarian/epub/xsltContent.xsl | 3 ++ librarian/mobi.py | 31 ++++++------ 5 files changed, 95 insertions(+), 44 deletions(-) create mode 100755 librarian/epub/toc.html diff --git a/librarian/cover.py b/librarian/cover.py index 9070344..f7d8f7d 100644 --- a/librarian/cover.py +++ b/librarian/cover.py @@ -118,6 +118,13 @@ class Cover(object): return self.image().save(format=self.format, *args, **kwargs) +class WLCover(Cover): + author_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Italic.ttf'), 40) + title_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Italic.ttf'), 50) + logo_width = 250 + logo_bottom = 20 + + class VirtualoCover(Cover): width = 600 diff --git a/librarian/epub.py b/librarian/epub.py index 85c51c0..c5942a2 100644 --- a/librarian/epub.py +++ b/librarian/epub.py @@ -158,19 +158,23 @@ def add_to_spine(spine, partno): class TOC(object): - def __init__(self, name=None, part_number=None): + def __init__(self, name=None, part_href=None): self.children = [] self.name = name - self.part_number = part_number + self.part_href = part_href self.sub_number = None - def add(self, name, part_number, level=0, is_part=True): + def add(self, name, part_href, level=0, is_part=True, index=None): + assert level == 0 or index is None if level > 0 and self.children: - return self.children[-1].add(name, part_number, level-1, is_part) + return self.children[-1].add(name, "part%d.html" % part_href, level-1, is_part) else: t = TOC(name) - t.part_number = part_number - self.children.append(t) + t.part_href = part_href + if index is not None: + self.children.insert(index, t) + else: + self.children.append(t) if not is_part: t.sub_number = len(self.children) + 1 return t.sub_number @@ -187,7 +191,13 @@ class TOC(object): else: return 0 - def write_to_xml(self, nav_map, counter): + def href(self): + src = self.part_href + if self.sub_number is not None: + src += '#sub%d' % self.sub_number + return src + + def write_to_xml(self, nav_map, counter=1): for child in self.children: nav_point = nav_map.makeelement(NCXNS('navPoint')) nav_point.set('id', 'NavPoint-%d' % counter) @@ -200,15 +210,26 @@ class TOC(object): nav_point.append(nav_label) content = nav_map.makeelement(NCXNS('content')) - src = 'part%d.html' % child.part_number - if child.sub_number is not None: - src += '#sub%d' % child.sub_number - content.set('src', src) + content.set('src', child.href()) nav_point.append(content) nav_map.append(nav_point) counter = child.write_to_xml(nav_point, counter + 1) return counter + def html_part(self, depth=0): + texts = [] + for child in self.children: + texts.append( + "
%s
" % + (depth, child.href(), child.name)) + texts.append(child.html_part(depth+1)) + return "\n".join(texts) + + def html(self): + with open(get_resource('epub/toc.html')) as f: + t = unicode(f.read(), 'utf-8') + return t % self.html_part() + def used_chars(element): """ Lists characters used in an ETree Element """ @@ -248,9 +269,9 @@ def transform_chunk(chunk_xml, chunk_no, annotations, empty=False, _empty_html_s toc = TOC() for element in chunk_xml[0]: if element.tag in ("naglowek_czesc", "naglowek_rozdzial", "naglowek_akt", "srodtytul"): - toc.add(node_name(element), chunk_no) + toc.add(node_name(element), "part%d.html" % chunk_no) elif element.tag in ('naglowek_podrozdzial', 'naglowek_scena'): - subnumber = toc.add(node_name(element), chunk_no, level=1, is_part=False) + subnumber = toc.add(node_name(element), "part%d.html" % chunk_no, level=1, is_part=False) element.set('sub', str(subnumber)) if empty: if not _empty_html_static: @@ -267,7 +288,7 @@ def transform_chunk(chunk_xml, chunk_no, annotations, empty=False, _empty_html_s def transform(provider, slug=None, file_path=None, output_file=None, output_dir=None, make_dir=False, verbose=False, - style=None, + style=None, html_toc=False, sample=None, cover=None, flags=None): """ produces a EPUB file @@ -298,6 +319,8 @@ def transform(provider, slug=None, file_path=None, output_file=None, output_dir= chars = used_chars(html_tree.getroot()) zip.writestr('OPS/title.html', etree.tostring(html_tree, method="html", pretty_print=True)) + # add a title page TOC entry + toc.add(u"Strona tytułowa", "title.html") elif children: # write title page for every parent if sample is not None and sample <= 0: @@ -404,6 +427,7 @@ def transform(provider, slug=None, file_path=None, output_file=None, output_dir= opf = xslt(metadata, get_resource('epub/xsltContent.xsl')) manifest = opf.find('.//' + OPFNS('manifest')) + guide = opf.find('.//' + OPFNS('guide')) spine = opf.find('.//' + OPFNS('spine')) if cover: @@ -423,9 +447,9 @@ def transform(provider, slug=None, file_path=None, output_file=None, output_dir= '')) manifest.append(etree.fromstring( '' % (c_name, c.mime_type()))) - spine.insert(0, etree.fromstring('')) + spine.insert(0, etree.fromstring('')) opf.getroot()[0].append(etree.fromstring('')) - opf.getroot().append(etree.fromstring('')) + guide.append(etree.fromstring('')) annotations = etree.Element('annotations') @@ -434,23 +458,24 @@ def transform(provider, slug=None, file_path=None, output_file=None, output_dir= '"-//NISO//DTD ncx 2005-1//EN" "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">' \ '' \ - '' \ - 'Strona tytułowa' \ - '') + '') nav_map = toc_file[-1] + if html_toc: + manifest.append(etree.fromstring( + '')) + spine.append(etree.fromstring( + '')) + guide.append(etree.fromstring('')) + toc, chunk_counter, chars, sample = transform_file(input_xml, sample=sample) - if not toc.children: - toc.add(u"Początek utworu", 1) - toc_counter = toc.write_to_xml(nav_map, 2) + if len(toc.children) < 2: + toc.add(u"Początek utworu", "part1.html") # Last modifications in container files and EPUB creation if len(annotations) > 0: - nav_map.append(etree.fromstring( - 'Przypisy'\ - '' % {'i': toc_counter})) - toc_counter += 1 + toc.add("Przypisy", "annotations.html") manifest.append(etree.fromstring( '')) spine.append(etree.fromstring( @@ -461,9 +486,7 @@ def transform(provider, slug=None, file_path=None, output_file=None, output_dir= zip.writestr('OPS/annotations.html', etree.tostring( html_tree, method="html", pretty_print=True)) - nav_map.append(etree.fromstring( - 'Strona redakcyjna'\ - '' % {'i': toc_counter})) + toc.add("Strona redakcyjna", "last.html") manifest.append(etree.fromstring( '')) spine.append(etree.fromstring( @@ -505,5 +528,11 @@ def transform(provider, slug=None, file_path=None, output_file=None, output_dir= toc_file[0][0].set('content', ''.join((title, 'WolneLektury.pl'))) toc_file[0][1].set('content', str(toc.depth())) set_inner_xml(toc_file[1], ''.join(('', title, ''))) + + # write TOC + if html_toc: + toc.add(u"Spis treści", "toc.html", index=1) + zip.writestr('OPS/toc.html', toc.html().encode('utf-8')) + toc.write_to_xml(nav_map) zip.writestr('OPS/toc.ncx', etree.tostring(toc_file, pretty_print=True)) zip.close() diff --git a/librarian/epub/toc.html b/librarian/epub/toc.html new file mode 100755 index 0000000..69d8724 --- /dev/null +++ b/librarian/epub/toc.html @@ -0,0 +1,11 @@ + + + + + WolneLektury.pl + + +

Spis treści

+ %s + + diff --git a/librarian/epub/xsltContent.xsl b/librarian/epub/xsltContent.xsl index c443a15..83eb376 100644 --- a/librarian/epub/xsltContent.xsl +++ b/librarian/epub/xsltContent.xsl @@ -35,6 +35,9 @@ + + + diff --git a/librarian/mobi.py b/librarian/mobi.py index 62b275c..a1f5127 100755 --- a/librarian/mobi.py +++ b/librarian/mobi.py @@ -3,23 +3,13 @@ # 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 subprocess -from StringIO import StringIO -from copy import deepcopy -from lxml import etree -import zipfile from tempfile import NamedTemporaryFile -from shutil import rmtree - -import sys -from librarian import epub - -from librarian import functions, get_resource +from librarian.cover import WLCover +from librarian import epub, get_resource def transform(provider, slug=None, file_path=None, output_file=None, output_dir=None, make_dir=False, verbose=False, @@ -30,7 +20,7 @@ def transform(provider, slug=None, file_path=None, output_file=None, output_dir= slug: slug of file to process, available by provider output_file: path to output file output_dir: path to directory to save output file to; either this or output_file must be present - make_dir: writes output to //.epub instead of /.epub + make_dir: writes output to //.mobi instead of /.mobi sample=n: generate sample e-book (with at least n paragraphs) cover: a cover.Cover object flags: less-advertising, @@ -50,11 +40,22 @@ def transform(provider, slug=None, file_path=None, output_file=None, output_dir= else: output_file = os.path.join(output_dir, os.path.splitext(os.path.basename(file_path))[0] + '.mobi') + # provide a cover by default + if not cover: + cover = WLCover + epub_file = NamedTemporaryFile(suffix='.epub', delete=False) if not flags: flags = [] flags = list(flags) + ['without-fonts'] epub.transform(provider, file_path=file_path, output_file=epub_file, verbose=verbose, - sample=sample, cover=None, flags=flags, style=get_resource('mobi/style.css')) - subprocess.check_call(['ebook-convert', epub_file.name, output_file]) + sample=sample, html_toc=True, cover=cover, flags=flags, style=get_resource('mobi/style.css')) + + if verbose: + kwargs = {} + else: + devnull = open("/dev/null", 'w') + kwargs = {"stdout": devnull, "stderr": devnull} + subprocess.check_call(['ebook-convert', epub_file.name, output_file, + '--no-inline-toc'], **kwargs) os.unlink(epub_file.name) -- 2.20.1