From 32b86ab224867f78e5df2922d2a7f851856e126f Mon Sep 17 00:00:00 2001 From: gryf Date: Mon, 13 Apr 2020 12:52:36 +0200 Subject: [PATCH] Added support for epub output format. --- README.rst | 9 ++-- ebook_converter/ebooks/covers.py | 22 ++++----- ebook_converter/ebooks/epub/__init__.py | 2 +- ebook_converter/ebooks/oeb/polish/css.py | 16 +++---- ebook_converter/ebooks/oeb/polish/replace.py | 26 +++++----- ebook_converter/ebooks/oeb/polish/split.py | 14 +++--- .../ebooks/oeb/transforms/cover.py | 48 ++++--------------- .../ebooks/oeb/transforms/filenames.py | 4 +- .../ebooks/oeb/transforms/rescale.py | 2 +- .../ebooks/oeb/transforms/split.py | 14 +++--- 10 files changed, 62 insertions(+), 95 deletions(-) diff --git a/README.rst b/README.rst index 69195eb..0a66401 100644 --- a/README.rst +++ b/README.rst @@ -52,7 +52,7 @@ Currently, I've tested following input formats: - Palm pdb - rtf - mobi - +- fb2 Note, that old Microsoft doc format is not supported, although old documents can be fairly easy converted using text processors programs, lik Word or @@ -62,11 +62,10 @@ LibreOffice to supported formats. Output formats ~~~~~~~~~~~~~~ -Currenlty, the only format which is supported is BBeB (lrf) mainly because it -is the only one I care for now ;) I'm happy user of Sony PRS-505, and I have no -zero motivation to change that reader to something more fancy. Or plastic. +Currently, following formats are supported: -I'm going to enable others pretty soon. +- lrf (for Sony readers) +- epub Installation diff --git a/ebook_converter/ebooks/covers.py b/ebook_converter/ebooks/covers.py index 62ccad0..95f490d 100644 --- a/ebook_converter/ebooks/covers.py +++ b/ebook_converter/ebooks/covers.py @@ -9,7 +9,7 @@ import re, random, unicodedata, numbers from collections import namedtuple from contextlib import contextmanager from math import ceil, sqrt, cos, sin, atan2 -from polyglot.builtins import iteritems, itervalues, map, zip, string_or_bytes +from ebook_converter.polyglot.builtins import iteritems, itervalues, map, zip, string_or_bytes from itertools import chain from PyQt5.Qt import ( @@ -18,14 +18,14 @@ from PyQt5.Qt import ( QPainterPath, QPen, QRectF, QTransform, QRadialGradient ) -from calibre import force_unicode, fit_image -from calibre.constants import __appname__, __version__ -from calibre.ebooks.metadata import fmt_sidx -from calibre.ebooks.metadata.book.base import Metadata -from calibre.ebooks.metadata.book.formatter import SafeFormat -from calibre.gui2 import ensure_app, config, load_builtin_fonts, pixmap_to_data -from calibre.utils.cleantext import clean_ascii_chars, clean_xml_chars -from calibre.utils.config import JSONConfig +from ebook_converter import force_unicode, fit_image +from ebook_converter.constants import __appname__, __version__ +from ebook_converter.ebooks.metadata import fmt_sidx +from ebook_converter.ebooks.metadata.book.base import Metadata +from ebook_converter.ebooks.metadata.book.formatter import SafeFormat +from ebook_converter.gui2 import ensure_app, config, load_builtin_fonts, pixmap_to_data +from ebook_converter.utils.cleantext import clean_ascii_chars, clean_xml_chars +from ebook_converter.utils.config import JSONConfig # Default settings {{{ cprefs = JSONConfig('cover_generation') @@ -492,7 +492,7 @@ class Ornamental(Style): def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block): if not self.PATH_CACHE: - from calibre.utils.speedups import svg_path_to_painter_path + from ebook_converter.utils.speedups import svg_path_to_painter_path try: self.__class__.PATH_CACHE['corner'] = svg_path_to_painter_path(self.CORNER_VECTOR) except Exception: @@ -728,7 +728,7 @@ def generate_masthead(title, output_path=None, width=600, height=60, as_qimage=F def test(scale=0.25): from PyQt5.Qt import QLabel, QPixmap, QMainWindow, QWidget, QScrollArea, QGridLayout - from calibre.gui2 import Application + from ebook_converter.gui2 import Application app = Application([]) mi = Metadata('Unknown', ['Kovid Goyal', 'John & Doe', 'Author']) mi.series = 'A series & styles' diff --git a/ebook_converter/ebooks/epub/__init__.py b/ebook_converter/ebooks/epub/__init__.py index 4629218..df450e5 100644 --- a/ebook_converter/ebooks/epub/__init__.py +++ b/ebook_converter/ebooks/epub/__init__.py @@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en' ''' Conversion to EPUB. ''' -from calibre.utils.zipfile import ZipFile, ZIP_STORED +from ebook_converter.utils.zipfile import ZipFile, ZIP_STORED def rules(stylesheets): diff --git a/ebook_converter/ebooks/oeb/polish/css.py b/ebook_converter/ebooks/oeb/polish/css.py index cb84f20..16f8484 100644 --- a/ebook_converter/ebooks/oeb/polish/css.py +++ b/ebook_converter/ebooks/oeb/polish/css.py @@ -9,15 +9,15 @@ from collections import defaultdict from functools import partial from css_parser.css import CSSRule, CSSStyleDeclaration -from css_selectors import parse, SelectorSyntaxError +from ebook_converter.css_selectors import parse, SelectorSyntaxError -from calibre import force_unicode -from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS, XHTML, css_text -from calibre.ebooks.oeb.normalize_css import normalize_filter_css, normalizers -from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style, pretty_xml_tree, serialize -from calibre.utils.icu import numeric_sort_key -from css_selectors import Select, SelectorError -from polyglot.builtins import iteritems, itervalues, unicode_type, filter +from ebook_converter import force_unicode +from ebook_converter.ebooks.oeb.base import OEB_STYLES, OEB_DOCS, XHTML, css_text +from ebook_converter.ebooks.oeb.normalize_css import normalize_filter_css, normalizers +from ebook_converter.ebooks.oeb.polish.pretty import pretty_script_or_style, pretty_xml_tree, serialize +from ebook_converter.utils.icu import numeric_sort_key +from ebook_converter.css_selectors import Select, SelectorError +from ebook_converter.polyglot.builtins import iteritems, itervalues, unicode_type, filter def filter_used_rules(rules, log, select): diff --git a/ebook_converter/ebooks/oeb/polish/replace.py b/ebook_converter/ebooks/oeb/polish/replace.py index 08fdbaa..90991ee 100644 --- a/ebook_converter/ebooks/oeb/polish/replace.py +++ b/ebook_converter/ebooks/oeb/polish/replace.py @@ -7,16 +7,16 @@ __copyright__ = '2013, Kovid Goyal ' __docformat__ = 'restructuredtext en' import codecs, shutil, os, posixpath -from polyglot.builtins import iteritems, itervalues, map +from ebook_converter.polyglot.builtins import iteritems, itervalues, map from functools import partial from collections import Counter, defaultdict -from calibre import sanitize_file_name -from calibre.ebooks.chardet import strip_encoding_declarations -from calibre.ebooks.oeb.base import css_text -from calibre.ebooks.oeb.polish.css import iter_declarations, remove_property_value -from calibre.ebooks.oeb.polish.utils import extract -from polyglot.urllib import urlparse, urlunparse +from ebook_converter import sanitize_file_name +from ebook_converter.ebooks.chardet import strip_encoding_declarations +from ebook_converter.ebooks.oeb.base import css_text +from ebook_converter.ebooks.oeb.polish.css import iter_declarations, remove_property_value +from ebook_converter.ebooks.oeb.polish.utils import extract +from ebook_converter.polyglot.urllib import urlparse, urlunparse class LinkReplacer(object): @@ -151,7 +151,7 @@ def replace_ids(container, id_map): def smarten_punctuation(container, report): - from calibre.ebooks.conversion.preprocess import smarten_punctuation + from ebook_converter.ebooks.conversion.preprocess import smarten_punctuation smartened = False for path in container.spine_items: name = container.abspath_to_name(path) @@ -230,9 +230,9 @@ def replace_file(container, name, path, basename, force_mt=None): def mt_to_category(container, mt): - from calibre.ebooks.oeb.polish.utils import guess_type - from calibre.ebooks.oeb.polish.container import OEB_FONTS - from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES + from ebook_converter.ebooks.oeb.polish.utils import guess_type + from ebook_converter.ebooks.oeb.polish.container import OEB_FONTS + from ebook_converter.ebooks.oeb.base import OEB_DOCS, OEB_STYLES if mt in OEB_DOCS: category = 'text' elif mt in OEB_STYLES: @@ -253,7 +253,7 @@ def get_recommended_folders(container, names): recommendation is based on where the majority of files of the same type are located in the container. If no files of a particular type are present, the recommended folder is assumed to be the folder containing the OPF file. ''' - from calibre.ebooks.oeb.polish.utils import guess_type + from ebook_converter.ebooks.oeb.polish.utils import guess_type counts = defaultdict(Counter) for name, mt in iteritems(container.mime_map): folder = name.rpartition('/')[0] if '/' in name else '' @@ -347,7 +347,7 @@ def remove_links_in_declaration(href_to_name, style, predicate): def remove_links_to(container, predicate): ''' predicate must be a function that takes the arguments (name, href, fragment=None) and returns True iff the link should be removed ''' - from calibre.ebooks.oeb.base import iterlinks, OEB_DOCS, OEB_STYLES, XPath, XHTML + from ebook_converter.ebooks.oeb.base import iterlinks, OEB_DOCS, OEB_STYLES, XPath, XHTML stylepath = XPath('//h:style') styleattrpath = XPath('//*[@style]') changed = set() diff --git a/ebook_converter/ebooks/oeb/polish/split.py b/ebook_converter/ebooks/oeb/polish/split.py index e24440a..910d7d5 100644 --- a/ebook_converter/ebooks/oeb/polish/split.py +++ b/ebook_converter/ebooks/oeb/polish/split.py @@ -6,14 +6,14 @@ __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal ' import copy, os, re -from polyglot.builtins import map, string_or_bytes, range +from ebook_converter.polyglot.builtins import map, string_or_bytes, range -from calibre.ebooks.oeb.base import barename, XPNSMAP, XPath, OPF, XHTML, OEB_DOCS -from calibre.ebooks.oeb.polish.errors import MalformedMarkup -from calibre.ebooks.oeb.polish.toc import node_from_loc -from calibre.ebooks.oeb.polish.replace import LinkRebaser -from polyglot.builtins import iteritems, unicode_type -from polyglot.urllib import urlparse +from ebook_converter.ebooks.oeb.base import barename, XPNSMAP, XPath, OPF, XHTML, OEB_DOCS +from ebook_converter.ebooks.oeb.polish.errors import MalformedMarkup +from ebook_converter.ebooks.oeb.polish.toc import node_from_loc +from ebook_converter.ebooks.oeb.polish.replace import LinkRebaser +from ebook_converter.polyglot.builtins import iteritems, unicode_type +from ebook_converter.polyglot.urllib import urlparse class AbortError(ValueError): diff --git a/ebook_converter/ebooks/oeb/transforms/cover.py b/ebook_converter/ebooks/oeb/transforms/cover.py index 4409f0c..059811c 100644 --- a/ebook_converter/ebooks/oeb/transforms/cover.py +++ b/ebook_converter/ebooks/oeb/transforms/cover.py @@ -8,11 +8,11 @@ __docformat__ = 'restructuredtext en' import textwrap -from calibre import guess_type -from calibre.utils.imghdr import identify -from calibre.utils.xml_parse import safe_xml_fromstring -from polyglot.builtins import unicode_type -from polyglot.urllib import unquote +from ebook_converter import guess_type +from ebook_converter.utils.imghdr import identify +from ebook_converter.utils.xml_parse import safe_xml_fromstring +from ebook_converter.polyglot.builtins import unicode_type +from ebook_converter.polyglot.urllib import unquote class CoverManager(object): @@ -84,39 +84,8 @@ class CoverManager(object): self.log = log self.insert_cover() - def default_cover(self): - ''' - Create a generic cover for books that dont have a cover - ''' - if self.no_default_cover: - return None - self.log('Generating default cover') - m = self.oeb.metadata - title = unicode_type(m.title[0]) - authors = [unicode_type(x) for x in m.creator if x.role == 'aut'] - try: - from calibre.ebooks.covers import create_cover - series = series_index = None - if m.series: - try: - series, series_index = unicode_type(m.series[0]), m.series_index[0] - except IndexError: - pass - img_data = create_cover(title, authors, series, series_index) - id, href = self.oeb.manifest.generate('cover', - 'cover_image.jpg') - item = self.oeb.manifest.add(id, href, guess_type('t.jpg')[0], - data=img_data) - m.clear('cover') - m.add('cover', item.id) - - return item.href - except: - self.log.exception('Failed to generate default cover') - return None - def inspect_cover(self, href): - from calibre.ebooks.oeb.base import urlnormalize + from ebook_converter.ebooks.oeb.base import urlnormalize for x in self.oeb.manifest: if x.href == urlnormalize(href): try: @@ -127,14 +96,13 @@ class CoverManager(object): return -1, -1 def insert_cover(self): - from calibre.ebooks.oeb.base import urldefrag + from ebook_converter.ebooks.oeb.base import urldefrag g, m = self.oeb.guide, self.oeb.manifest item = None + href = None if 'titlepage' not in g: if 'cover' in g: href = g['cover'].href - else: - href = self.default_cover() if href is None: return width, height = self.inspect_cover(href) diff --git a/ebook_converter/ebooks/oeb/transforms/filenames.py b/ebook_converter/ebooks/oeb/transforms/filenames.py index 1539663..ad56221 100644 --- a/ebook_converter/ebooks/oeb/transforms/filenames.py +++ b/ebook_converter/ebooks/oeb/transforms/filenames.py @@ -10,8 +10,8 @@ import posixpath from lxml import etree -from calibre.ebooks.oeb.base import rewrite_links, urlnormalize -from polyglot.urllib import urldefrag, urlparse +from ebook_converter.ebooks.oeb.base import rewrite_links, urlnormalize +from ebook_converter.polyglot.urllib import urldefrag, urlparse class RenameFiles(object): # {{{ diff --git a/ebook_converter/ebooks/oeb/transforms/rescale.py b/ebook_converter/ebooks/oeb/transforms/rescale.py index 214c895..cb9ba5e 100644 --- a/ebook_converter/ebooks/oeb/transforms/rescale.py +++ b/ebook_converter/ebooks/oeb/transforms/rescale.py @@ -6,7 +6,7 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from calibre import fit_image +from ebook_converter import fit_image class RescaleImages(object): diff --git a/ebook_converter/ebooks/oeb/transforms/split.py b/ebook_converter/ebooks/oeb/transforms/split.py index 3124561..3d5b02d 100644 --- a/ebook_converter/ebooks/oeb/transforms/split.py +++ b/ebook_converter/ebooks/oeb/transforms/split.py @@ -15,14 +15,14 @@ from collections import OrderedDict from lxml.etree import XPath as _XPath from lxml import etree -from calibre import as_unicode, force_unicode -from calibre.ebooks.epub import rules -from calibre.ebooks.oeb.base import (OEB_STYLES, XPNSMAP as NAMESPACES, +from ebook_converter import as_unicode, force_unicode +from ebook_converter.ebooks.epub import rules +from ebook_converter.ebooks.oeb.base import (OEB_STYLES, XPNSMAP as NAMESPACES, urldefrag, rewrite_links, XHTML, urlnormalize) -from calibre.ebooks.oeb.polish.split import do_split -from polyglot.builtins import iteritems, range, map, unicode_type -from polyglot.urllib import unquote -from css_selectors import Select, SelectorError +from ebook_converter.ebooks.oeb.polish.split import do_split +from ebook_converter.polyglot.builtins import iteritems, range, map, unicode_type +from ebook_converter.polyglot.urllib import unquote +from ebook_converter.css_selectors import Select, SelectorError XPath = functools.partial(_XPath, namespaces=NAMESPACES)