1
0
Fork 0
mirror of https://github.com/kemayo/leech synced 2026-01-03 22:26:52 +01:00

Use namedtuple in the epub generator so it's easier to understand

This commit is contained in:
David Lynch 2021-07-21 10:32:55 -05:00
parent f1bd28e942
commit 25312736d4
2 changed files with 41 additions and 44 deletions

View file

@ -1,4 +1,4 @@
from .epub import make_epub
from .epub import make_epub, EpubFile
from .cover import make_cover
from .cover import make_cover_from_url
@ -89,13 +89,13 @@ def chapter_html(story, titleprefix=None, normalize=False):
if normalize:
title = unicodedata.normalize('NFKC', title)
contents = unicodedata.normalize('NFKC', contents)
chapters.append((
title,
f'{story.id}/chapter{i + 1}.html',
html_template.format(title=html.escape(title), text=contents)
chapters.append(EpubFile(
title=title,
path=f'{story.id}/chapter{i + 1}.html',
contents=html_template.format(title=html.escape(title), text=contents)
))
if story.footnotes:
chapters.append(("Footnotes", f'{story.id}/footnotes.html', html_template.format(title="Footnotes", text='\n\n'.join(story.footnotes))))
chapters.append(EpubFile(title="Footnotes", path=f'{story.id}/footnotes.html', contents=html_template.format(title="Footnotes", text='\n\n'.join(story.footnotes))))
return chapters
@ -124,7 +124,7 @@ def generate_epub(story, cover_options={}, output_filename=None, normalize=False
cover_options = attr.asdict(cover_options, filter=lambda k, v: v is not None, retain_collection_types=True)
# The cover is static, and the only change comes from the image which we generate
html = [('Cover', 'cover.html', cover_template)]
files = [EpubFile(title='Cover', path='cover.html', contents=cover_template)]
if cover_options and "cover_url" in cover_options:
image = make_cover_from_url(cover_options["cover_url"], story.title, story.author)
@ -133,16 +133,18 @@ def generate_epub(story, cover_options={}, output_filename=None, normalize=False
else:
image = make_cover(story.title, story.author, **cover_options)
cover_image = ('images/cover.png', image.read(), 'image/png')
cover_image = EpubFile(path='images/cover.png', contents=image.read(), filetype='image/png')
html.append(('Front Matter', 'frontmatter.html', frontmatter_template.format(now=datetime.datetime.now(), **metadata)))
files.append(EpubFile(title='Front Matter', path='frontmatter.html', contents=frontmatter_template.format(now=datetime.datetime.now(), **metadata)))
html.extend(chapter_html(story, normalize=normalize))
files.extend(chapter_html(story, normalize=normalize))
css = ('Styles/base.css', requests.Session().get('https://raw.githubusercontent.com/mattharrison/epub-css-starter-kit/master/css/base.css').text, 'text/css')
css = EpubFile(path='Styles/base.css', contents=requests.Session().get('https://raw.githubusercontent.com/mattharrison/epub-css-starter-kit/master/css/base.css').text, filetype='text/css')
files.extend((css, cover_image))
output_filename = output_filename or story.title + '.epub'
output_filename = make_epub(output_filename, html, metadata, extra_files=(css, cover_image))
output_filename = make_epub(output_filename, files, metadata)
return output_filename

View file

@ -5,6 +5,7 @@ import zipfile
import xml.etree.ElementTree as etree
import uuid
import string
from collections import namedtuple
"""
So, an epub is approximately a zipfile of HTML files, with
@ -14,6 +15,9 @@ This totally started from http://www.manuel-strehl.de/dev/simple_epub_ebooks_wit
"""
EpubFile = namedtuple('EbookFile', 'path, contents, title, filetype', defaults=(False, False, "application/xhtml+xml"))
def sanitize_filename(s):
"""Take a string and return a valid filename constructed from the string.
Uses a whitelist approach: any characters not present in valid_chars are
@ -31,7 +35,7 @@ def sanitize_filename(s):
return filename
def make_epub(filename, html_files, meta, extra_files=False, compress=True):
def make_epub(filename, files, meta, compress=True):
unique_id = meta.get('unique_id', False)
if not unique_id:
unique_id = 'leech_book_' + str(uuid.uuid4())
@ -90,49 +94,40 @@ def make_epub(filename, html_files, meta, extra_files=False, compress=True):
navmap = etree.SubElement(ncx, 'navMap')
# Write each HTML file to the ebook, collect information for the index
for i, html in enumerate(html_files):
for i, file in enumerate(files):
file_id = 'file_%d' % (i + 1)
etree.SubElement(manifest, 'item', {
'id': file_id,
'href': html[1],
'media-type': "application/xhtml+xml",
'href': file.path,
'media-type': file.filetype,
})
itemref = etree.SubElement(spine, 'itemref', idref=file_id)
point = etree.SubElement(navmap, 'navPoint', {
'class': "h1",
'id': file_id,
})
etree.SubElement(etree.SubElement(point, 'navLabel'), 'text').text = html[0]
etree.SubElement(point, 'content', src=html[1])
if file.filetype == "application/xhtml+xml":
itemref = etree.SubElement(spine, 'itemref', idref=file_id)
point = etree.SubElement(navmap, 'navPoint', {
'class': "h1",
'id': file_id,
})
etree.SubElement(etree.SubElement(point, 'navLabel'), 'text').text = file.title
etree.SubElement(point, 'content', src=file.path)
if 'cover.html' == os.path.basename(html[1]):
if 'cover.html' == os.path.basename(file.path):
etree.SubElement(guide, 'reference', {
'type': 'cover',
'title': 'Cover',
'href': html[1],
'href': file.path,
})
itemref.set('linear', 'no')
if 'images/cover.png' == file.path:
etree.SubElement(metadata, 'meta', {
'name': 'cover',
'content': file_id,
})
# and add the actual html to the zip
if html[2]:
epub.writestr('OEBPS/' + html[1], html[2])
if file.contents:
epub.writestr('OEBPS/' + file.path, file.contents)
else:
epub.write(html[1], 'OEBPS/' + html[1])
if extra_files:
for i, data in enumerate(extra_files):
file_id = 'extrafile_%d' % (i + 1)
etree.SubElement(manifest, 'item', {
'id': file_id,
'href': data[0],
'media-type': data[2],
})
if 'images/cover.png' == data[0]:
etree.SubElement(metadata, 'meta', {
'name': 'cover',
'content': file_id,
})
epub.writestr('OEBPS/' + data[0], data[1])
epub.write(file.path, 'OEBPS/' + file.path)
# ...and add the ncx to the manifest
etree.SubElement(manifest, 'item', {
@ -151,4 +146,4 @@ def make_epub(filename, html_files, meta, extra_files=False, compress=True):
if __name__ == '__main__':
make_epub('test.epub', [('Chapter 1', 'test/a.html'), ('Chapter 2', 'test/b.html')], {})
make_epub('test.epub', [EpubFile(title='Chapter 1', path='a.html', contents="Test"), EpubFile(title='Chapter 2', path='test/b.html', contents="Still a test")], {})