Skip to content

Instantly share code, notes, and snippets.

@spajak
Created August 27, 2021 17:54
Show Gist options
  • Save spajak/2e8d961da8942477eaa91baf0073478e to your computer and use it in GitHub Desktop.
Save spajak/2e8d961da8942477eaa91baf0073478e to your computer and use it in GitHub Desktop.
Make EPUB e-book file from a given directory. The directory must be a valid EPUB ebook source.
import sys
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED
def main():
usage = f'{sys.argv[0]} source_dir [destination_file]'
if len(sys.argv) > 1:
src = Path(sys.argv[1])
dst = Path(sys.argv[2]) if len(sys.argv) > 2 else Path(src.name + ".epub")
validate(src, dst)
build_epub(src, dst)
print(f'File: {dst}')
print(f'Size: {sizeof(dst)}')
else:
print('Input directory not specified.')
print(usage)
def sizeof(path):
num = path.stat().st_size
for unit in ['', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB']:
if abs(num) < 1024.0:
return f'{num:.1f} {unit}'
num /= 1024.0
return f'{num:.1f} YiB'
def validate(src, dst):
container = 'META-INF/container.xml'
if not src.exists():
raise FileNotFoundError(f'Source directory "{src}" does not exist.')
elif not src.is_dir():
raise NotADirectoryError(f'Source "{src}" is not a directory.')
elif not (src / container).is_file():
raise FileNotFoundError(f'Source lacks "{container}" file.')
if dst.exists():
raise FileExistsError(f'File "{dst}" already exists.')
def build_epub(src, dst):
mimetype = b'application/epub+zip'
src_mimetype = src / 'mimetype'
if src_mimetype.is_file():
mimetype = src_mimetype.read_bytes().strip()
with ZipFile(dst, 'w', compression=ZIP_DEFLATED, compresslevel=4) as epub:
epub.writestr('mimetype', mimetype, compress_type=ZIP_STORED)
for file in (f for f in src.rglob('*') if f != src_mimetype):
epub.write(file, file.relative_to(src))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment