예제 #1
0
    def save_settings(cls, config_widget):
        """Ensure settings are properly saved between old and new config styles."""
        try:
            config_widget = config_widget.widget()
            log.warning(
                "KoboTouchExtended:save_settings: Have old style config.")
        except Exception:
            log.info("KoboTouchExtended:save_settings: Have new style config.")

        super(KOBOTOUCHEXTENDED, cls).save_settings(config_widget)
예제 #2
0
    def sync_booklists(self, booklists, end_session=True):
        """Synchronize book lists between calibre and the Kobo device."""
        if self.upload_covers:
            log.info("KoboTouchExtended:sync_booklists:Setting ImageId fields")

            select_query = ("SELECT ContentId FROM content WHERE " +
                            "ContentType = ? AND " +
                            "(ImageId IS NULL OR ImageId = '')")
            update_query = "UPDATE content SET ImageId = ? WHERE ContentId = ?"
            try:
                db = self.device_database_connection()
            except AttributeError:
                import apsw

                db = apsw.Connection(self.device_database_path())

            def __rows_needing_imageid():
                """Map row ContentID entries needing an ImageID.

                Returns a dict object with keys being the ContentID of a row
                without an ImageID.
                """
                c = db.cursor()
                d = {}
                log.debug(
                    "KoboTouchExtended:sync_booklists:About to call query: "
                    "{0}".format(select_query))
                c.execute(select_query, (self.content_types["main"], ))
                for row in c:
                    d[row[0]] = 1
                return d

            all_nulls = __rows_needing_imageid()
            log.debug("KoboTouchExtended:sync_booklists:Got {0:d} rows to "
                      "update".format(len(list(all_nulls.keys()))))
            nulls = []
            for booklist in booklists:
                for b in booklist:
                    if b.application_id is not None and b.contentID in all_nulls:
                        nulls.append((self.imageid_from_contentid(b.contentID),
                                      b.contentID))
            del all_nulls

            cursor = db.cursor()
            while nulls[:100]:
                log.debug("KoboTouchExtended:sync_booklists:Updating {0:d} "
                          "ImageIDs...".format(len(nulls[:100])))
                cursor.executemany(update_query, nulls[:100])
                del nulls[:100]
            cursor.close()
            db.close()
            log.debug(
                "KoboTouchExtended:sync_booklists:done setting ImageId fields")

        super(KOBOTOUCHEXTENDED, self).sync_booklists(booklists, end_session)
예제 #3
0
    def config_widget(cls):
        """Create and populate the driver settings config widget."""
        from calibre.gui2.device_drivers.configwidget import ConfigWidget

        cw = super(KOBOTOUCHEXTENDED, cls).config_widget()
        if isinstance(cw, ConfigWidget):
            log.warning(
                "KoboTouchExtended:config_widget: Have old style config.")
            try:
                from PyQt5.QtCore import QCoreApplication
                from PyQt5.QtWidgets import QScrollArea
            except ImportError:
                from PyQt4.Qt import QCoreApplication
                from PyQt4.Qt import QScrollArea
            qsa = QScrollArea()
            qsa.setWidgetResizable(True)
            qsa.setWidget(cw)
            qsa.validate = cw.validate
            desktop_geom = QCoreApplication.instance().desktop(
            ).availableGeometry()
            if desktop_geom.height() < 800:
                qsa.setBaseSize(qsa.size().width(),
                                desktop_geom.height() - 100)
            cw = qsa
        else:
            log.info("KoboTouchExtended:config_widget: Have new style config.")
            cls.current_friendly_name = cls.gui_name

            from calibre_plugins.kobotouch_extended.device.koboextended_config import (
                KOBOTOUCHEXTENDEDConfig, )

            cw = KOBOTOUCHEXTENDEDConfig(
                cls.settings(),
                cls.FORMATS,
                cls.SUPPORTS_SUB_DIRS,
                cls.MUST_READ_METADATA,
                cls.SUPPORTS_USE_AUTHOR_SORT,
                cls.EXTRA_CUSTOMIZATION_MESSAGE,
                cls,
                extra_customization_choices=cls.EXTRA_CUSTOMIZATION_CHOICES,
            )
        return cw
예제 #4
0
    def migrate_old_settings(cls, settings):
        """Migrate old settings to the new format."""
        log.debug("KoboTouchExtended::migrate_old_settings - start")
        settings = super(KOBOTOUCHEXTENDED, cls).migrate_old_settings(settings)
        log.debug(
            "KoboTouchExtended::migrate_old_settings - end",
            settings.extra_customization,
        )

        count_options = 0
        opt_extra_features = count_options
        count_options += 1
        opt_upload_encumbered = count_options
        count_options += 1
        opt_skip_failed = count_options
        count_options += 1
        opt_hypnenate = count_options
        count_options += 1
        opt_smarten_punctuation = count_options
        count_options += 1
        opt_clean_markup = count_options
        count_options += 1
        opt_full_page_numbers = count_options
        count_options += 1
        opt_file_copy_dir = count_options
        count_options += 1
        opt_disable_hyphenation = count_options

        if len(settings.extra_customization) >= count_options:
            log.warning(
                "KoboTouchExtended::migrate_old_settings - settings need to "
                "be migrated")
            try:
                settings.extra_features = settings.extra_customization[
                    opt_extra_features]
            except IndexError:
                pass
            try:
                settings.upload_encumbered = settings.extra_customization[
                    opt_upload_encumbered]
            except IndexError:
                pass
            try:
                settings.skip_failed = settings.extra_customization[
                    opt_skip_failed]
            except IndexError:
                pass
            try:
                settings.hyphenate = settings.extra_customization[
                    opt_hypnenate]
            except IndexError:
                pass
            try:
                settings.smarten_punctuation = settings.extra_customization[
                    opt_smarten_punctuation]
            except IndexError:
                pass
            try:
                settings.clean_markup = settings.extra_customization[
                    opt_clean_markup]
            except IndexError:
                pass
            try:
                settings.file_copy_dir = settings.extra_customization[
                    opt_file_copy_dir]
                if not isinstance(settings.file_copy_dir, str):
                    settings.file_copy_dir = None
            except IndexError:
                pass
            try:
                settings.full_page_numbers = settings.extra_customization[
                    opt_full_page_numbers]
            except IndexError:
                pass
            try:
                settings.disable_hyphenation = settings.extra_customization[
                    opt_disable_hyphenation]
            except IndexError:
                pass

            settings.extra_customization = settings.extra_customization[
                count_options + 1:]
            log.info(
                "KoboTouchExtended::migrate_old_settings - end",
                settings.extra_customization,
            )

        return settings
예제 #5
0
    def upload_books(self,
                     files,
                     names,
                     on_card=None,
                     end_session=True,
                     metadata=None):
        """Process sending the book to the Kobo device."""
        if self.modifying_css():
            log.info(
                "KoboTouchExtended:upload_books:Searching for device-specific "
                "CSS file")
            device_css_file_name = self.KOBO_EXTRA_CSSFILE
            try:
                if self.isAuraH2O():
                    device_css_file_name = "kobo_extra_AURAH2O.css"
                elif self.isAuraHD():
                    device_css_file_name = "kobo_extra_AURAHD.css"
                elif self.isAura():
                    device_css_file_name = "kobo_extra_AURA.css"
                elif self.isGlo():
                    device_css_file_name = "kobo_extra_GLO.css"
                elif self.isGloHD():
                    device_css_file_name = "kobo_extra_GLOHD.css"
                elif self.isMini():
                    device_css_file_name = "kobo_extra_MINI.css"
                elif self.isTouch():
                    device_css_file_name = "kobo_extra_TOUCH.css"
            except AttributeError:
                log.warning(
                    "KoboTouchExtended:upload_books:Calibre version too old "
                    "to handle some specific devices, falling back to "
                    "generic file {0}".format(device_css_file_name))
            device_css_file_name = os.path.join(self.configdir,
                                                device_css_file_name)
            if os.path.isfile(device_css_file_name):
                log.info(
                    "KoboTouchExtended:upload_books:Found device-specific "
                    "file {0}".format(device_css_file_name))
                shutil.copy(
                    device_css_file_name,
                    os.path.join(self._main_prefix, self.KOBO_EXTRA_CSSFILE),
                )
            else:
                log.info(
                    "KoboTouchExtended:upload_books:No device-specific CSS "
                    "file found (expecting {0})".format(device_css_file_name))

        kobo_config_file = os.path.join(self._main_prefix, ".kobo", "Kobo",
                                        "Kobo eReader.conf")
        if os.path.isfile(kobo_config_file):
            cfg = SafeConfigParser(allow_no_value=True)
            cfg.optionxform = str
            cfg.read(kobo_config_file)

            if not cfg.has_section("FeatureSettings"):
                cfg.add_section("FeatureSettings")
            log.info("KoboTouchExtended:upload_books:Setting FeatureSettings."
                     "FullBookPageNumbers to {0}".format(
                         "true" if self.full_page_numbers else "false"))
            cfg.set(
                "FeatureSettings",
                "FullBookPageNumbers",
                "true" if self.full_page_numbers else "false",
            )
            with open(kobo_config_file, "w") as cfgfile:
                cfg.write(cfgfile)

        return super(KOBOTOUCHEXTENDED,
                     self).upload_books(files, names, on_card, end_session,
                                        metadata)
예제 #6
0
    def _modify_epub(self, infile, metadata, container=None):
        if not infile.endswith(EPUB_EXT):
            if not infile.endswith(KEPUB_EXT):
                self.skip_renaming_files.add(metadata.uuid)
            else:
                log.info("KoboTouchExtended:_modify_epub:Skipping all "
                         "processing for calibre-converted KePub file "
                         "{0}".format(infile))
            return super(KOBOTOUCHEXTENDED,
                         self)._modify_epub(infile, metadata, container)

        log.info(
            "KoboTouchExtended:_modify_epub:Adding basic Kobo features to "
            "{0} by {1}".format(metadata.title,
                                " and ".join(metadata.authors)))

        opts = self.settings()
        skip_failed = self.skip_failed
        if skip_failed:
            log.info(
                "KoboTouchExtended:_modify_epub:Failed conversions will be skipped"
            )
        else:
            log.info(
                "KoboTouchExtended:_modify_epub:Failed conversions will raise "
                "exceptions")

        is_encumbered_book = False
        try:
            if container is None:
                container = KEPubContainer(infile, log)
            else:
                is_encumbered_book = container.is_drm_encumbered
        except DRMError:
            log.warning("KoboTouchExtended:_modify_epub:ERROR: ePub is "
                        "DRM-encumbered, not modifying")
            is_encumbered_book = True

        if is_encumbered_book:
            self.skip_renaming_files.add(metadata.uuid)
            if self.upload_encumbered:
                return super(KOBOTOUCHEXTENDED,
                             self)._modify_epub(infile, metadata, container)
            else:
                return False

        try:
            # Add the conversion info file
            calibre_details_file = self.normalize_path(
                os.path.join(self._main_prefix, "driveinfo.calibre"))
            log.debug("KoboTouchExtended:_modify_epub:Calibre details file :: "
                      "{0}".format(calibre_details_file))
            o = {}
            if os.path.isfile(calibre_details_file):
                with open(calibre_details_file, "rb") as f:
                    o = json.loads(f.read())
                for prop in (
                        "device_store_uuid",
                        "prefix",
                        "last_library_uuid",
                        "location_code",
                ):
                    del o[prop]
            else:
                log.warning(
                    "KoboTouchExtended:_modify_file:Calibre details file does "
                    "not exist!")
            o["kobotouchextended_version"] = ".".join(
                [str(n) for n in self.version])
            o["kobotouchextended_options"] = str(opts.extra_customization)
            o["kobotouchextended_currenttime"] = datetime.utcnow().ctime()
            kte_data_file = self.temporary_file("_KoboTouchExtendedDriverInfo")
            log.debug("KoboTouchExtended:_modify_epub:Driver data file :: {0}".
                      format(kte_data_file.name))
            kte_data_file.write(json.dumps(o).encode("UTF-8"))
            kte_data_file.close()
            container.copy_file_to_container(kte_data_file.name,
                                             name="driverinfo.kte",
                                             mt="application/json")

            modify_epub(
                container,
                infile,
                metadata=metadata,
                opts={
                    "clean_markup": self.clean_markup,
                    "hyphenate": self.hyphenate
                    and not self.disable_hyphenation,
                    "no-hyphens": self.disable_hyphenation,
                    "smarten_punctuation": self.smarten_punctuation,
                    "extended_kepub_features": self.extra_features,
                },
            )
        except Exception as e:
            log.exception("Failed to process {0} by {1}: {2}".format(
                metadata.title,
                " and ".join(metadata.authors),
                e.message,
            ))

            if not skip_failed:
                raise

            self.skip_renaming_files.add(metadata.uuid)
            return super(KOBOTOUCHEXTENDED,
                         self)._modify_epub(infile, metadata, container)

        if not self.extra_features:
            self.skip_renaming_files.add(metadata.uuid)

        dpath = self.file_copy_dir or ""
        if dpath != "":
            dpath = os.path.expanduser(dpath).strip()
            dpath = self.create_upload_path(dpath, metadata,
                                            metadata.kte_calibre_name)
            log.info(
                "KoboTouchExtended:_modify_epub:Generated KePub file copy "
                "path: {0}".format(dpath))
            shutil.copy(infile, dpath)

        retval = super(KOBOTOUCHEXTENDED,
                       self)._modify_epub(infile, metadata, container)
        if retval:
            container.commit(outpath=infile)
        return retval