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:
parent
f1bd28e942
commit
25312736d4
2 changed files with 41 additions and 44 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")], {})
|
||||
|
|
|
|||
Loading…
Reference in a new issue