Register Guidelines E-Books Today's Posts Search

Go Back   MobileRead Forums > E-Book Software > Calibre > Plugins

Notices

Reply
 
Thread Tools Search this Thread
Old 08-16-2021, 08:27 AM   #646
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,130
Karma: 1954142
Join Date: Aug 2015
Device: Kindle
Start using calibre-debug -g and post the log here.
capink is offline   Reply With Quote
Old 08-16-2021, 08:47 AM   #647
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,130
Karma: 1954142
Join Date: Aug 2015
Device: Kindle
deleted.

Last edited by capink; 08-16-2021 at 08:53 AM.
capink is offline   Reply With Quote
Old 08-16-2021, 08:53 AM   #648
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,130
Karma: 1954142
Join Date: Aug 2015
Device: Kindle
OK. I identified the problem and released a new version.
capink is offline   Reply With Quote
Old 08-16-2021, 08:55 AM   #649
bob.f
Connoisseur
bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!
 
Posts: 61
Karma: 99068
Join Date: Nov 2017
Device: N/A
Quote:
Originally Posted by capink View Post
Start using calibre-debug -g and post the log here.
calibre-debug.txt
bob.f is offline   Reply With Quote
Old 08-16-2021, 08:58 AM   #650
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,130
Karma: 1954142
Join Date: Aug 2015
Device: Kindle
OK. Please download the version from the first post (or wait until the update is announced by calibre in an hour or so), test it and report back.
capink is offline   Reply With Quote
Old 08-16-2021, 09:05 AM   #651
bob.f
Connoisseur
bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!bob.f has a thesaurus and is not afraid to use it!
 
Posts: 61
Karma: 99068
Join Date: Nov 2017
Device: N/A
Quote:
Originally Posted by capink View Post
OK. Please download the version from the first post (or wait until the update is announced by calibre in an hour or so), test it and report back.
That works, Calibre starts normally now.
bob.f is offline   Reply With Quote
Old 08-16-2021, 10:34 AM   #652
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,130
Karma: 1954142
Join Date: Aug 2015
Device: Kindle
Custom add books action

Here is a new custom "Add Books" action. It is based on calibre's add books action and can be configured to run in one of the following modes:
  • Add books from single directory.
  • Add from folders and sub-folders (single book per directory).
  • Add from folders and sub-folders (multiple books per directory).

When running the the first option, you can make it add books from a predefined directory, which makes it suitable to create your auto-add chain (if used with the timer event). Note however, that unlike calibre's auto-add, this will launch a progress dialog that will block the gui until all books are added.

Also the action has an option to select the newly added books, so that other actions in the chain can work on them.

Code:
import os
from functools import partial
import copy
import shutil

from PyQt5.Qt import (Qt, QApplication, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
                      QRadioButton, QCheckBox, QIcon, QGroupBox, QLabel, QComboBox, QToolButton)

from calibre import prints
from calibre.constants import DEBUG
from calibre.gui2 import choose_dir, choose_files, gprefs
from calibre.gui2.add import Adder
from calibre.gui2.auto_add import allowed_formats
from calibre.gui2.actions.add import AddAction, get_filters
from calibre.utils.date import now

from calibre_plugins.action_chains.actions.base import ChainAction
from calibre_plugins.action_chains.common_utils import DragDropComboBox, get_icon
from calibre_plugins.action_chains.database import get_books_modified_since

class ModifiedAdder(Adder):
    def __init__(self, source, single_book_per_directory=True, db=None, parent=None, callback=None, pool=None, list_of_archives=False, duplicate_opt='runtime'):
        self.duplicate_opt = duplicate_opt
        Adder.__init__(self, source, single_book_per_directory, db, parent, callback, pool, list_of_archives)
        self.block_thread()

    def block_thread(self):
        while not self.abort_scan:
            QApplication.processEvents()
        return

    def process_duplicates(self):
        if self.duplicate_opt == 'runtime':
            return Adder.process_duplicates(self)
        elif self.duplicate_opt == 'add':
            duplicates = copy.copy(self.duplicates)
            if duplicates:
                self.do_one = self.process_duplicate
                self.duplicates_to_process = iter(duplicates)
                self.pd.title = _('Adding duplicates')
                self.pd.msg = ''
                self.pd.max, self.pd.value = len(duplicates), 0
                self.do_one_signal.emit()
                return
        elif self.duplicate_opt == 'remove':
            duplicates = ()
        self.finish()

class ModifiedAddAction(AddAction):

    def __init__(self, gui):
        self.gui = gui
        self.allowed = allowed_formats()
        self.duplicate_opt = 'runtime'

    def do_add_recursive(self, root, single, list_of_archives=False):
        from calibre.gui2.add import Adder
        adder = ModifiedAdder(root, single_book_per_directory=single, db=self.gui.current_db, list_of_archives=list_of_archives,
              callback=self._files_added, parent=self.gui, pool=self.gui.spare_pool(), duplicate_opt=self.duplicate_opt)

    def _add_books(self, paths, to_device, on_card=None):
        if on_card is None:
            on_card = 'carda' if self.gui.stack.currentIndex() == 2 else \
                      'cardb' if self.gui.stack.currentIndex() == 3 else None
        if not paths:
            return
        ModifiedAdder(paths, db=None if to_device else self.gui.current_db,
              parent=self.gui, callback=partial(self._files_added, on_card=on_card), pool=self.gui.spare_pool(), duplicate_opt=self.duplicate_opt)

    def add_books(self, books, *args):
        '''
        Add books from the local filesystem to either the library or the device.
        '''
        filters = get_filters()
        to_device = self.gui.stack.currentIndex() != 0
        if to_device:
            fmts = self.gui.device_manager.device.settings().format_map
            filters = [(_('Supported books'), fmts)]

        if not books:
            return
        self._add_books(books, to_device)

    def add_recursive(self, single, root):
        if not root:
            return
        lp = os.path.normcase(os.path.abspath(self.gui.current_db.library_path))
        if lp.startswith(os.path.normcase(os.path.abspath(root)) + os.pathsep):
            return error_dialog(self.gui, _('Cannot add'), _(
                'Cannot add books from the folder: %s as it contains the currently opened calibre library') % root, show=True)
        self.do_add_recursive(root, single)

    def is_filename_allowed(self, filename):
        ext = os.path.splitext(filename)[1][1:].lower()
        allowed = ext in self.allowed
        return allowed

    def books_from_path(self, path):
        files = [os.path.join(path, x) for x in os.listdir(path) if
                    # Firefox creates 0 byte placeholder files when downloading
                    os.stat(os.path.join(path, x)).st_size > 0 and
                    # Must be a file
                    os.path.isfile(os.path.join(path, x)) and
                    # Must have read and write permissions
                    os.access(os.path.join(path, x), os.R_OK|os.W_OK) and
                    # Must be a known ebook file type
                    self.is_filename_allowed(x)
                ]
        return files

    def clean_path(self, path):
        files = [os.path.join(path, x) for x in os.listdir(path) if
                    os.path.isfile(os.path.join(path, x)) and
                    os.access(os.path.join(path, x), os.R_OK|os.W_OK)]
        dirs = [os.path.join(path, x) for x in os.listdir(path) if
                    os.path.isdir(os.path.join(path, x)) and
                    os.access(os.path.join(path, x), os.R_OK|os.W_OK)]
        for f in files:
            os.remove(f)
        for d in dirs:
            shutil.rmtree(d)


class ConfigWidget(QWidget):

    def __init__(self, plugin_action):
        QWidget.__init__(self)
        self.gui = plugin_action.gui
        self.db = self.gui.current_db
        self._init_controls()

    def _init_controls(self):

        l = QVBoxLayout()
        self.setLayout(l)
        
        actions_group_box = QGroupBox('Actions')
        actions_group_box_l = QVBoxLayout()
        actions_group_box.setLayout(actions_group_box_l)
        l.addWidget(actions_group_box)
        
        add_books_opt = self.add_books_opt = QRadioButton('Add books from a single directory')
        self.add_books_opt.setChecked(True)
        actions_group_box_l.addWidget(self.add_books_opt)

        recursive_single_opt = self.recursive_single_opt = QRadioButton('Add from folders and sub-folders (Single book per directory)')
        actions_group_box_l.addWidget(self.recursive_single_opt)

        recursive_multiple_opt = self.recursive_multiple_opt = QRadioButton('Add from folders and sub-folders (Multiple books per directory)')
        actions_group_box_l.addWidget(self.recursive_multiple_opt)

        for opt in [add_books_opt, recursive_single_opt, recursive_multiple_opt]:
            opt.toggled.connect(self._action_opt_toggled)

        location_group_box = QGroupBox(_('Books location'))
        location_group_box_l = QVBoxLayout()
        location_group_box.setLayout(location_group_box_l)
        l.addWidget(location_group_box)

        self.runtime_opt = QRadioButton('Ask at runtime')
        self.runtime_opt.setChecked(True)
        location_group_box_l.addWidget(self.runtime_opt)
        self.predefined_opt = QRadioButton('Add from location defined below')
        location_group_box_l.addWidget(self.predefined_opt)
        hl1 = QHBoxLayout()
        location_group_box_l.addLayout(hl1)
        self.file_combo = DragDropComboBox(self, drop_mode='file')        
        hl1.addWidget(self.file_combo, 1)
        self.choose_path_button = QToolButton(self)
        self.choose_path_button.setToolTip(_('Choose path'))
        self.choose_path_button.setIcon(get_icon('document_open.png'))
        self.choose_path_button.clicked.connect(self._choose_path)
        hl1.addWidget(self.choose_path_button)        

        duplicate_group_box = QGroupBox(_('What to do with duplicate books'))
        duplicate_group_box_l = QVBoxLayout()
        duplicate_group_box.setLayout(duplicate_group_box_l)
        l.addWidget(duplicate_group_box)

        self.duplicate_options = {
            'runtime': _('Ask at runtime'),
            'add': _('Add duplicates'),
            'remove': _('Remove duplicates')
        }
        self.duplicates_combo = QComboBox()
        self.duplicates_combo.addItems(list(self.duplicate_options.values()))
        duplicate_group_box_l.addWidget(self.duplicates_combo)

        options_group_box = QGroupBox(_('Options'))
        options_group_box_l = QVBoxLayout()
        options_group_box.setLayout(options_group_box_l)
        l.addWidget(options_group_box)
        
        self.delete_books_chk = QCheckBox(_('Delete books after adding'))
        options_group_box_l.addWidget(self.delete_books_chk)
#        self.warning_1 = QLabel(_('<b>Warning: </b> This will delete all files and directories in directory'))
#        self.warning_1.setWordWrap(True)
#        options_group_box_l.addWidget(self.warning_1)
        self.select_added_chk = QCheckBox(_('Select added books'))
        options_group_box_l.addWidget(self.select_added_chk)
#        self.hide_progress_chk = QCheckBox('When adding from predefined path, hide progress bar')
#        options_group_box_l.addWidget(self.hide_progress_chk)

        l.addStretch(1)

        self.setMinimumSize(400,500)
        
        self._action_opt_toggled()

    def _action_opt_toggled(self):
        self.delete_books_chk.setEnabled(self.add_books_opt.isChecked())
        if not self.delete_books_chk.isEnabled():
            self.delete_books_chk.setChecked(False)
            
        self.predefined_opt.setEnabled(self.add_books_opt.isChecked())
        if not self.predefined_opt.isEnabled():
            self.runtime_opt.setChecked(True)

    def _choose_path(self):

        root = choose_dir(self.gui, 'recursive book import root dir dialog',
          _('Select root folder'))

        if not root:
            return

        self.block_events = True
        existing_index = self.file_combo.findText(root, Qt.MatchExactly)
        if existing_index >= 0:
            self.file_combo.setCurrentIndex(existing_index)
        else:
            self.file_combo.insertItem(0, root)
            self.file_combo.setCurrentIndex(0)
        self.block_events = False

    def load_settings(self, settings):
        if settings:
            if settings['action'] == 'add_books':
                self.add_books_opt.setChecked(True)
            else:
                if settings['is_single']:
                    self.recursive_single_opt.setChecked(True)
                else:
                    self.recursive_multiple_opt.setChecked(True)
            if settings['path_opt'] == 'runtime':
                self.runtime_opt.setChecked(True)
            else:
                self.predefined_opt.setChecked(True)
            self.file_combo.populate_items(settings.get('file_list', []), settings['path_to_books'])
            self.duplicates_combo.setCurrentText(self.duplicate_options[settings['duplicate_opt']])
            self.delete_books_chk.setChecked(settings['delete_books'])
            self.select_added_chk.setChecked(settings['select_added_books'])
#            self.hide_progress_chk.setChecked(settings['hide_progress'])
            self._action_opt_toggled()

    def save_settings(self):
        settings = {}
        if self.add_books_opt.isChecked():
            settings['action'] = 'add_books'
        elif self.recursive_single_opt.isChecked():
            settings['action'] = 'recursive_add'
            settings['is_single'] = True
        elif self.recursive_multiple_opt.isChecked():
            settings['action'] = 'recursive_add'
            settings['is_single'] = False
        if self.runtime_opt.isChecked():
            settings['path_opt'] = 'runtime'
        else:
            settings['path_opt'] = 'predefined'
        settings['path_to_books'] = self.file_combo.currentText()
        settings['file_list'] = self.file_combo.get_items_list()
        settings['duplicate_opt'] = {v: k for k, v in self.duplicate_options.items()}[self.duplicates_combo.currentText()]
        settings['delete_books'] = self.delete_books_chk.isChecked()
        settings['select_added_books'] = self.select_added_chk.isChecked()
#        settings['hide_progress'] = self.hide_progress_chk.isChecked()
        return settings

class ChainsAddAction(ChainAction):

    name = 'Add Books'

    def __init__(self, plugin_action):
        ChainAction.__init__(self, plugin_action)
        #self.add_action = ModifiedAddAction(plugin_action.gui)

    def run(self, gui, settings, chain):
        add_action = ModifiedAddAction(self.plugin_action.gui)
        start_time = now()
        action = settings['action']
        path_opt = settings['path_opt']
        path_to_books = settings.get('path_to_books', '')
        duplicate_opt = settings['duplicate_opt']
        add_action.duplicate_opt = duplicate_opt
#        if path_opt == 'predefined' and settings['hide_progress']:
#            add_action.hide_progress_dialog = True
        if action == 'add_books':
            if path_opt == 'runtime':
                filters = get_filters()
                books = choose_files(gui, 'add books dialog dir',
                        _('Select books'), filters=filters)
            else:
                books = add_action.books_from_path(path_to_books)
            add_action.add_books(books)
            if settings['delete_books']:
                for book in books:
                    os.remove(book)
        elif action == 'recursive_add':
            is_single = settings['is_single']
            if path_opt == 'runtime':
                root = choose_dir(gui, 'recursive book import root dir dialog',
                  _('Select root folder'))
            else:
                root = path_to_books
            add_action.add_recursive(is_single, root)
#            if settings['delete_books']:
#                add_action.clean_path(path_to_books)
        if settings['select_added_books']:
            added_ids = get_books_modified_since(gui.current_db, start_time)
            gui.library_view.select_rows(added_ids)

    def validate(self, settings):
        if not settings:
            return (_('Settings Error'), _('You must configure this action before running it'))
        if settings['path_opt'] == 'predefined':
            path_to_books = settings['path_to_books']
            if not path_to_books:
                return (_('Path Error'), _('You must choose a path to add books from'))
            if not os.path.isdir(path_to_books):
                return (_('Path Error'), _('Path entered ({}) is not a valid directory'.format(path_to_books)))
            if not os.access(path_to_books, os.R_OK|os.W_OK):
                return (_('Path Error'), _('Path entered ({}) does not have read/write access'.format(path_to_books)))
            if os.path.normpath(path_to_books) == os.path.normpath(gprefs['auto_add_path']):
                return (_('Path Error'), _('Predefined path ({}) cannot be the same as calibre auto add path'.format(path_to_books)))
        return True

    def config_widget(self):
        return ConfigWidget

Last edited by capink; 08-18-2021 at 09:31 AM.
capink is offline   Reply With Quote
Old 08-16-2021, 05:00 PM   #653
ownedbycats
Custom User Title
ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.
 
ownedbycats's Avatar
 
Posts: 9,059
Karma: 62040591
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
I think I may have asked this before, but...

For my "Cleanup: Loans" chain, I use the "Add File to Selected Book Record" to pop up a dialog so I can navigate to the folder where I have my dummy.overdrive file and add that.

Is there a way to specify the path of the file (e.g. [D:\Documents\Miscellaneous\dummy.overdrive) and just add it without the file dialog?
ownedbycats is online now   Reply With Quote
Old 08-16-2021, 05:14 PM   #654
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,130
Karma: 1954142
Join Date: Aug 2015
Device: Kindle
Quote:
Originally Posted by ownedbycats View Post
I think I may have asked this before, but...

For my "Cleanup: Loans" chain, I use the "Add File to Selected Book Record" to pop up a dialog so I can navigate to the folder where I have my dummy.overdrive file and add that.

Is there a way to specify the path of the file (e.g. [D:\Documents\Miscellaneous\dummy.overdrive) and just add it without the file dialog?
See the custom action here.

Also a list of custom actions is maintained here.
capink is offline   Reply With Quote
Old 08-16-2021, 05:28 PM   #655
ownedbycats
Custom User Title
ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.ownedbycats ought to be getting tired of karma fortunes by now.
 
ownedbycats's Avatar
 
Posts: 9,059
Karma: 62040591
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
Thank you.
ownedbycats is online now   Reply With Quote
Old 08-18-2021, 04:41 AM   #656
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,130
Karma: 1954142
Join Date: Aug 2015
Device: Kindle
Convert book custom action

Here is a minimal "Convert Books" action based on calibre's auto-convert. It is non interactive, and follows the same settings as calibre's auto-convert.

Code:
from PyQt5.Qt import (Qt, QApplication, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
                      QCheckBox, QIcon, QGroupBox)

from calibre import prints
from calibre.constants import DEBUG
from calibre.utils.date import now

from calibre_plugins.action_chains.actions.base import ChainAction
from calibre_plugins.action_chains.actions.calibre_actions import unfinished_job_ids, responsive_wait, responsive_wait_until

class ConfigWidget(QWidget):

    def __init__(self, plugin_action):
        QWidget.__init__(self)
        self.plugin_action = plugin_action
        self.gui = plugin_action.gui
        self.db = self.gui.current_db
        self._init_controls()

    def _init_controls(self):

        l = QVBoxLayout()
        self.setLayout(l)

        job_wait_chk = self.job_wait_chk = QCheckBox(_('Wait until all convert jobs finish.'))
        l.addWidget(job_wait_chk)
        job_wait_chk.setChecked(True)

        l.addStretch(1)

    def load_settings(self, settings):
        if settings:
            self.job_wait_chk.setChecked(settings['wait_jobs'])

    def save_settings(self):
        settings = {}
        settings['wait_jobs'] = self.job_wait_chk.isChecked()
        return settings

class ChainsConvertAction(ChainAction):

    name = 'Convert Books'
    support_scopes = True

    def run(self, gui, settings, chain):
        db = gui.current_db
        book_ids = chain.scope().get_book_ids()
        start_time = now()

        jobs_before_ids = unfinished_job_ids(gui)

        gui.iactions['Convert Books'].auto_convert_auto_add(book_ids)

        wait_jobs = settings.get('wait_jobs', True)

        if wait_jobs:            
            # wait for jobs spawned by action to kick in
            responsive_wait(1)
            
            # save ids of jobs started after running the action                    
            ids_jobs_by_action = unfinished_job_ids(gui).difference(jobs_before_ids)

            # wait for jobs to finish
            responsive_wait_until(lambda: ids_jobs_by_action.intersection(unfinished_job_ids(gui)) == set())         


    def config_widget(self):
        return ConfigWidget

Last edited by capink; 08-19-2021 at 05:11 AM.
capink is offline   Reply With Quote
Old 08-18-2021, 06:59 PM   #657
BetterRed
null operator (he/him)
BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.BetterRed ought to be getting tired of karma fortunes by now.
 
Posts: 20,782
Karma: 27405072
Join Date: Mar 2012
Location: Sydney Australia
Device: none
@capink - suggestion - rather than posting AC scripts in the plugin thread, create a sticky thread (e.g. Action Chain Scripts) and post them in there. And put a link to it in the first post of this thread.

BR
BetterRed is offline   Reply With Quote
Old 08-19-2021, 05:16 AM   #658
capink
Wizard
capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.capink ought to be getting tired of karma fortunes by now.
 
Posts: 1,130
Karma: 1954142
Join Date: Aug 2015
Device: Kindle
Quote:
Originally Posted by BetterRed View Post
@capink - suggestion - rather than posting AC scripts in the plugin thread, create a sticky thread (e.g. Action Chain Scripts) and post them in there. And put a link to it in the first post of this thread.

BR
OK. I will start adding new scripts to a new thread. There is already a link to custom actions in the first post of this thread. I will keep updating it.
capink is offline   Reply With Quote
Old 08-27-2021, 06:36 PM   #659
mr_abomination
Junior Member
mr_abomination began at the beginning.
 
Posts: 8
Karma: 10
Join Date: Jul 2020
Device: Kobo aura
Quote:
Originally Posted by capink View Post
@BetterRed
  • There is a lag of several seconds before the event is activated. This is done to ensure calibre's adder (and auto-adder) has added all the books.
How necessary is this? I have an event set up to run the 'Count Pages' plugin whenever a new book is added, and it seems to take forever to start.

I guess my question is does the EventType.book_created event trigger when the book(s) are starting to be added, or only when they are finished being added?

There is already a timeout method if there is still additional dialog boxes open, so why the long delay?
mr_abomination is offline   Reply With Quote
Old 08-29-2021, 01:40 PM   #660
chillybang
Member
chillybang began at the beginning.
 
Posts: 12
Karma: 10
Join Date: Aug 2021
Device: samsung s8
I'm trying to create the following Calibre bahavior with plugin Action Chains:

After Calibre library is changed on any way (event "Library changed") I want to mark all books in the library (chain action "Selector Modifier", option "select all books in the current library view") and export EPUB format into single folder.

I have following problem with the whole action:

1. I trigger the event "Library changed" with adding or deleting a book to the library. But the action doesn't start after libray is changed. To start the action I'm forced to click the button in the plugin menu, which runs action,
2. Marking all books works, but then the action interrupts to force manual folder selection. After I've selected the folder manually, the action works until end correctly.

How can I avoid these two manual actions I currently forced to do?

1.1 What I'm doing wrong with the event "Library changed"? Why the action doesn't start after it?
2.1 How can I setup an export folder in the action setup, so the action "knows" it always and doesn't force me to select the folder?

Last edited by chillybang; 08-29-2021 at 01:43 PM.
chillybang is offline   Reply With Quote
Reply


Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
[Editor Plugin] Editor Chains capink Plugins 94 07-03-2024 07:26 PM
Action Chains Resources capink Plugins 65 07-01-2024 03:12 PM
[GUI Plugin] Noosfere_util, a companion plugin to noosfere DB lrpirlet Plugins 2 08-18-2022 03:15 PM
[GUI Plugin] Save Virtual Libraries To Column (GUI) chaley Plugins 14 04-04-2021 05:25 AM


All times are GMT -4. The time now is 06:12 PM.


MobileRead.com is a privately owned, operated and funded community.