Example #1
0
 def upgrade_to_epub3(self, tdir, opf):
     self.log.info('Upgrading to EPUB 3...')
     from calibre.ebooks.epub import simple_container_xml
     from calibre.ebooks.oeb.polish.cover import fix_conversion_titlepage_links_in_nav
     try:
         os.mkdir(os.path.join(tdir, 'META-INF'))
     except EnvironmentError:
         pass
     with open(os.path.join(tdir, 'META-INF', 'container.xml'), 'wb') as f:
         f.write(
             simple_container_xml(os.path.basename(opf)).encode('utf-8'))
     from calibre.ebooks.oeb.polish.container import EpubContainer
     container = EpubContainer(tdir, self.log)
     from calibre.ebooks.oeb.polish.upgrade import epub_2_to_3
     existing_nav = getattr(self.opts, 'epub3_nav_parsed', None)
     nav_href = getattr(self.opts, 'epub3_nav_href', None)
     previous_nav = (nav_href,
                     existing_nav) if existing_nav and nav_href else None
     epub_2_to_3(container, self.log.info, previous_nav=previous_nav)
     fix_conversion_titlepage_links_in_nav(container)
     container.commit()
     os.remove(f.name)
     try:
         os.rmdir(os.path.join(tdir, 'META-INF'))
     except EnvironmentError:
         pass
Example #2
0
 def upgrade_to_epub3(self, tdir, opf):
     self.log.info('Upgrading to EPUB 3...')
     from calibre.ebooks.epub import simple_container_xml
     try:
         os.mkdir(os.path.join(tdir, 'META-INF'))
     except EnvironmentError:
         pass
     with open(os.path.join(tdir, 'META-INF', 'container.xml'), 'wb') as f:
         f.write(
             simple_container_xml(os.path.basename(opf)).encode('utf-8'))
     from calibre.ebooks.oeb.polish.container import EpubContainer
     container = EpubContainer(tdir, self.log)
     from calibre.ebooks.oeb.polish.upgrade import epub_2_to_3
     epub_2_to_3(container, self.log.info)
     container.commit()
     os.remove(f.name)
     try:
         os.rmdir(os.path.join(tdir, 'META-INF'))
     except EnvironmentError:
         pass
Example #3
0
 def upgrade_to_epub3(self, tdir, opf):
     self.log.info('Upgrading to EPUB 3...')
     from calibre.ebooks.epub import simple_container_xml
     from calibre.ebooks.oeb.polish.cover import fix_conversion_titlepage_links_in_nav
     try:
         os.mkdir(os.path.join(tdir, 'META-INF'))
     except EnvironmentError:
         pass
     with open(os.path.join(tdir, 'META-INF', 'container.xml'), 'wb') as f:
         f.write(simple_container_xml(os.path.basename(opf)).encode('utf-8'))
     from calibre.ebooks.oeb.polish.container import EpubContainer
     container = EpubContainer(tdir, self.log)
     from calibre.ebooks.oeb.polish.upgrade import epub_2_to_3
     existing_nav = getattr(self.opts, 'epub3_nav_parsed', None)
     nav_href = getattr(self.opts, 'epub3_nav_href', None)
     previous_nav = (existing_nav, nav_href) if existing_nav and nav_href else None
     epub_2_to_3(container, self.log.info, previous_nav=previous_nav)
     fix_conversion_titlepage_links_in_nav(container)
     container.commit()
     os.remove(f.name)
     try:
         os.rmdir(os.path.join(tdir, 'META-INF'))
     except EnvironmentError:
         pass
Example #4
0
def modify_epub(container, filename, metadata=None, opts={}):
    print(str(opts))
    # Search for the ePub cover
    found_cover = False
    opf = container.opf
    cover_meta_node = opf.xpath('./opf:metadata/opf:meta[@name="cover"]',
                                namespaces=OPF_NAMESPACES)
    if len(cover_meta_node) > 0:
        cover_meta_node = cover_meta_node[0]
        cover_id = cover_meta_node.attrib[
            "content"] if "content" in cover_meta_node.attrib else None
        if cover_id is not None:
            print(
                "KoboTouchExtended:common:modify_epub:Found cover image ID '{0}'"
                .format(cover_id))
            cover_node = opf.xpath(
                './opf:manifest/opf:item[@id="{0}"]'.format(cover_id),
                namespaces=OPF_NAMESPACES)
            if len(cover_node) > 0:
                cover_node = cover_node[0]
                if "properties" not in cover_node.attrib or cover_node.attrib[
                        "properties"] != "cover-image":
                    print(
                        "KoboTouchExtended:common:modify_epub:Setting cover-image property"
                    )
                    cover_node.set("properties", "cover-image")
                    container.dirty(container.opf_name)
                    found_cover = True
    # It's possible that the cover image can't be detected this way. Try looking for the cover image ID in the OPF manifest.
    if not found_cover:
        print(
            "KoboTouchExtended:common:modify_epub:Looking for cover image in OPF manifest"
        )
        node_list = opf.xpath(
            './opf:manifest/opf:item[(@id="cover" or starts-with(@id, "cover")) and starts-with(@media-type, "image")]',
            namespaces=OPF_NAMESPACES)
        if len(node_list) > 0:
            node = node_list[0]
            if "properties" not in node.attrib or node.attrib[
                    "properties"] != 'cover-image':
                print(
                    "KoboTouchExtended:common:modify_epub:Setting cover-image")
                node.set("properties", "cover-image")
                container.dirty(container.opf_name)
                found_cover = True

    # Because of the changes made to the markup here, cleanup needs to be done before any other content file processing
    container.forced_cleanup()
    if 'clean_markup' in opts and opts['clean_markup'] is True:
        container.clean_markup()

    # Hyphenate files?
    if 'hyphenate' in opts and opts['hyphenate'] is True:
        if ('replace_lang' not in opts or opts['replace_lang']
                is not True) or (metadata is not None and metadata.language
                                 == NULL_VALUES['language']):
            print(
                "KoboTouchExtended:common:modify_epub:WARNING - Hyphenation is enabled but not overriding content file language. Hyphenation may use the wrong dictionary."
            )
        hyphenation_css = PersistentTemporaryFile(suffix='_hyphenate',
                                                  prefix='kepub_')
        hyphenation_css.write(get_resources('css/hyphenation.css'))
        hyphenation_css.close()
        css_path = os.path.basename(
            container.copy_file_to_container(hyphenation_css.name,
                                             name='kte-css/hyphenation.css'))
        container.add_content_file_reference("kte-css/{0}".format(css_path))

    # Override content file language
    if 'replace_lang' in opts and opts['replace_lang'] is True and (
            metadata is not None
            and metadata.language != NULL_VALUES["language"]):
        # First override for the OPF file
        lang_node = container.opf_xpath('//opf:metadata/dc:language')
        if len(lang_node) > 0:
            print(
                "KoboTouchExtended:common:modify_epub:Overriding OPF language")
            lang_node = lang_node[0]
            lang_node.text = metadata.language
        else:
            print("KoboTouchExtended:common:modify_epub:Setting OPF language")
            metadata_node = container.opf_xpath('//opf:metadata')[0]
            lang_node = metadata_node.makeelement("{%s}language" %
                                                  OPF_NAMESPACES['dc'])
            lang_node.text = metadata.language
            container.insert_into_xml(metadata_node, lang_node)
        container.dirty(container.opf_name)

        # Now override for content files
        for name in container.get_html_names():
            print(
                "KoboTouchExtended:common:modify_epub:Overriding content file language :: {0}"
                .format(name))
            root = container.parsed(name)
            root.attrib["{%s}lang" % XML_NAMESPACE] = metadata.language
            root.attrib["lang"] = metadata.language

    # Now smarten punctuation
    if 'smarten_punctuation' in opts and opts['smarten_punctuation'] is True:
        container.smarten_punctuation()

    if 'extended_kepub_features' in opts and opts[
            'extended_kepub_features'] is True:
        if metadata is not None:
            print(
                "KoboTouchExtended:common:modify_epub:Adding extended Kobo features to {0} by {1}"
                .format(metadata.title, ' and '.join(metadata.authors)))
        # Add the Kobo span tags
        container.add_kobo_spans()

        skip_js = False
        # Check to see if there's already a kobo*.js in the ePub
        for name in container.name_path_map:
            if kobo_js_re.match(name):
                skip_js = True
                break
        if not skip_js:
            if os.path.isfile(reference_kepub):
                reference_container = EpubContainer(reference_kepub,
                                                    default_log)
                for name in reference_container.name_path_map:
                    if kobo_js_re.match(name):
                        jsname = container.copy_file_to_container(
                            os.path.join(reference_container.root, name),
                            name='kobo.js')
                        container.add_content_file_reference(jsname)
                        break
    os.unlink(filename)
    container.commit(filename)
def modify_epub(
        container,  # type: EpubContainer
        filename,  # type: str
        metadata=None,  # type: Optional[Metadata]
        opts={},  # type: Dict[str, Union[str, bool]]
):  # type: (...) -> None
    """Modify the ePub file to make it KePub-compliant."""
    _modify_start = time.time()

    # Search for the ePub cover
    # TODO: Refactor out cover detection logic so it can be directly used in
    # metadata/writer.py
    found_cover = False  # type: bool
    opf = container.opf  # type: _Element
    cover_meta_node_list = opf.xpath(
        './opf:metadata/opf:meta[@name="cover"]',
        namespaces=OPF_NAMESPACES)  # List[_Element]

    if len(cover_meta_node_list) > 0:
        cover_meta_node = cover_meta_node_list[0]  # type: _Element
        cover_id = cover_meta_node.attrib.get("content", None)

        log.debug("Found meta node with name=cover")

        if cover_id:
            log.info("Found cover image ID '{0}'".format(cover_id))

            cover_node_list = opf.xpath(
                './opf:manifest/opf:item[@id="{0}"]'.format(cover_id),
                namespaces=OPF_NAMESPACES,
            )  # type: List[_Element]
            if len(cover_node_list) > 0:
                cover_node = cover_node_list[0]  # type: _Element

                log.debug("Found an item node with cover ID")

                if cover_node.attrib.get("properties", "") != "cover-image":
                    log.info("Setting cover-image property")
                    cover_node.set("properties", "cover-image")
                    container.dirty(container.opf_name)
                else:
                    log.warning("Item node is already set as cover-image")
                found_cover = True

    # It's possible that the cover image can't be detected this way. Try
    # looking for the cover image ID in the OPF manifest.
    if not found_cover:
        log.debug("Looking for cover image in OPF manifest")

        node_list = opf.xpath(
            "./opf:manifest/opf:item[(translate(@id, " +
            "'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" +
            '="cover" or starts-with(translate(@id, ' +
            "'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" +
            ', "cover")) and starts-with(@media-type, "image")]',
            namespaces=OPF_NAMESPACES,
        )  # type: List[_Element]
        if len(node_list) > 0:
            log.info("Found {0:d} nodes, assuming the first is the "
                     "right node".format(len(node_list)))

            node = node_list[0]  # type: _Element
            if node.attrib.get("properties", "") != "cover-image":
                log.info("Setting cover-image property")
                node.set("properties", "cover-image")
                container.dirty(container.opf_name)
            else:
                log.warning("Item node is already set as cover-image")
            found_cover = True

    # Hyphenate files?
    if opts.get("no-hyphens", False):
        nohyphen_css = PersistentTemporaryFile(
            suffix="_nohyphen",
            prefix="kepub_")  # type: PersistentTemporaryFile
        nohyphen_css.write(get_resources("css/no-hyphens.css"))  # noqa: F821
        nohyphen_css.close()

        css_path = os.path.basename(
            container.copy_file_to_container(
                nohyphen_css.name, name="kte-css/no-hyphens.css"))  # type: str
        container.add_content_file_reference("kte-css/{0}".format(css_path))
        os.unlink(nohyphen_css.name)
    elif opts.get("hyphenate", False) and opts.get("hyphen_min_chars", 6) > 0:
        if metadata and metadata.language == NULL_VALUES["language"]:
            log.warning(
                "Hyphenation is enabled but not overriding content file "
                "language. Hyphenation may use the wrong dictionary.")
        hyphen_css = PersistentTemporaryFile(
            suffix="_hyphenate",
            prefix="kepub_")  # type: PersistentTemporaryFile
        css_template = get_resources(
            "css/hyphenation.css.tmpl").decode()  # noqa: F821
        hyphen_limit_lines = opts.get("hyphen_limit_lines", 2)
        if hyphen_limit_lines == 0:
            hyphen_limit_lines = "no-limit"
        hyphen_css.write(
            css_template.format(
                hyphen_min_chars=opts.get("hyphen_min_chars"),
                hyphen_min_chars_before=opts.get("hyphen_min_chars_before", 3),
                hyphen_min_chars_after=opts.get("hyphen_min_chars_after", 3),
                hyphen_limit_lines=hyphen_limit_lines,
            ).encode())
        hyphen_css.close()

        css_path = os.path.basename(
            container.copy_file_to_container(
                hyphen_css.name, name="kte-css/hyphenation.css"))  # type: str
        container.add_content_file_reference("kte-css/{0}".format(css_path))
        os.unlink(hyphen_css.name)

    # Now smarten punctuation
    if opts.get("smarten_punctuation", False):
        container.smarten_punctuation()

    if opts.get("extended_kepub_features", True):
        if metadata is not None:
            log.info("Adding extended Kobo features to {0} by {1}".format(
                metadata.title, " and ".join(metadata.authors)))

        # Add the Kobo span and div tags
        container.convert()

        # Check to see if there's already a kobo*.js in the ePub
        skip_js = False  # type: str
        for name in container.name_path_map:
            if KOBO_JS_RE.match(name):
                skip_js = True
                break

        if not skip_js:
            if os.path.isfile(REFERENCE_KEPUB):
                reference_container = EpubContainer(REFERENCE_KEPUB, log)
                for name in reference_container.name_path_map:
                    if KOBO_JS_RE.match(name):
                        jsname = container.copy_file_to_container(
                            os.path.join(reference_container.root, name),
                            name="kobo.js")
                        container.add_content_file_reference(jsname)
                        break

        # Add the Kobo style hacks
        stylehacks_css = PersistentTemporaryFile(suffix="_stylehacks",
                                                 prefix="kepub_")
        stylehacks_css.write(
            get_resources("css/style-hacks.css"))  # noqa: F821
        stylehacks_css.close()

        css_path = os.path.basename(
            container.copy_file_to_container(stylehacks_css.name,
                                             name="kte-css/stylehacks.css"))
        container.add_content_file_reference("kte-css/{0}".format(css_path))
    os.unlink(filename)
    container.commit(filename)

    _modify_time = time.time() - _modify_start
    log.info("modify_epub took {0:f} seconds".format(_modify_time))