03-15-2024, 01:27 PM | #1306 |
want to learn what I want
Posts: 1,006
Karma: 6422750
Join Date: Sep 2020
Device: Calibre E-book viewer
|
I got this on start:
(I mean, upon scrolling down the chains dialog) Unhandled exception TypeError: MenusTable._on_viewport_entered() missing 1 required positional argument: 'index' edit: actually it seems that just mouse hovering over the dialog triggers that message Last edited by Comfy.n; 03-15-2024 at 02:18 PM. |
03-15-2024, 09:39 PM | #1307 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Sorry for the mishaps. I am not able to replicate your problems, and this can lead to a fruitless to-and-fro, so I decided to revert to having the icon combo in the actions dialog. I updated the version in post no. 1293
|
Advert | |
|
03-15-2024, 09:51 PM | #1308 | |
want to learn what I want
Posts: 1,006
Karma: 6422750
Join Date: Sep 2020
Device: Calibre E-book viewer
|
Quote:
|
|
03-31-2024, 08:09 PM | #1309 |
Connoisseur
Posts: 91
Karma: 1282284
Join Date: Nov 2010
Location: West of the Pecos
Device: FireHD8, iPad
|
Perhaps I'm not searching this thread properly so, if I'm repeating an old question, please forgive me.
I've created an action chain that does the following: 1. eMail the selected ePub to my Kindle account. 2. Set a custom field (I've named "Uploaded") to "YES" (with a checkmark displayed). The chain works perfectly but what happens if there's some error that prevents the eMail from being received successfully? I know Calibre reports an error (in the Jobs, IIRC) if an eMail isn't reported received by Amazon so what I'm asking is how do I add a check for this in an intermediate step and then, either pass to the next step (if okay) or exit the chain (if not okay)? Thanks for any advice. Barry |
03-31-2024, 08:33 PM | #1310 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
I'm not sure there's a way for Action Chains to detect errors. I think your best option might be to use this custom module and manually ask the user for confirmation.
|
Advert | |
|
04-02-2024, 10:59 AM | #1311 | |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
Quote:
|
|
04-09-2024, 10:44 AM | #1312 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
What's today's update? I not see a changelog entry.
|
04-09-2024, 03:15 PM | #1313 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
It is the same as the test version (running chains in jobs) but it does not exclude chain caller from running in jobs. Also some code modification to Calibre Actions that does not change anything (yet) from the user perspective.
Last edited by capink; 04-09-2024 at 03:18 PM. |
04-11-2024, 04:05 AM | #1314 |
Junior Member
Posts: 2
Karma: 10
Join Date: Apr 2024
Location: Noorderwijk, Belgium
Device: android tablet
|
After upgrading from Calibre 7.4 to 7.8, creation of a action in an action chain results in an error. As far as I see, this applies to all types of actions.
This is the error I get : calibre, version 7.8.0 ERROR: Unhandled exception: <b>AttributeError</b>:'ActionsDialog' object has no attribute 'jobify_chk' calibre 7.8 embedded-python: True Linux-6.8.4-rc1-1-default-x86_64-with-glibc2.38 Linux ('64bit', 'ELF') ('Linux', '6.8.4-rc1-1-default', '#1 SMP PREEMPT_DYNAMIC Thu Apr 4 07:22:28 UTC 2024 (1089550)') Python 3.11.5 Interface language: None EXE path: /app/lib/calibre/bin/calibre Successfully initialized third party plugins: Action Chains (1, 20, 1) && EpubMerge (2, 18, 0) && Favourites Menu (1, 3, 1) && Find Duplicates (1, 10, 9) && Open With (1, 8, 3) && Quality Check (1, 13, 10) Traceback (most recent call last): File "calibre_plugins.action_chains.gui.actions_dialog" , line 203, in accept self.chain_settings['jobify'] = self.jobify_chk.isChecked() ^^^^^^^^^^^^^^^ AttributeError: 'ActionsDialog' object has no attribute 'jobify_chk' |
04-11-2024, 05:00 AM | #1315 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
I uploaded a new version. Try that.
|
04-11-2024, 07:40 AM | #1316 |
Junior Member
Posts: 2
Karma: 10
Join Date: Apr 2024
Location: Noorderwijk, Belgium
Device: android tablet
|
|
04-21-2024, 11:44 AM | #1317 |
Custom User Title
Posts: 8,643
Karma: 61234567
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
For a single-field edit on a taglike, can I both add and remove (different) entries at the same time?
EDIT: it worked when I test. Last edited by ownedbycats; 04-21-2024 at 03:34 PM. |
04-23-2024, 03:35 AM | #1318 |
Enthusiast
Posts: 29
Karma: 10
Join Date: Mar 2017
Device: Kindle Paperwhite
|
Hi,
I've found this code by capink : Code:
import os, numbers import copy from qt.core import (QApplication, Qt, QWidget, QGridLayout, QHBoxLayout, QVBoxLayout, QGroupBox, QComboBox, QRadioButton, QCheckBox, QToolButton, QLineEdit) from calibre import prints from calibre.constants import iswindows, isosx, islinux, DEBUG from calibre.gui2 import error_dialog, Dispatcher, choose_dir from calibre.gui2.actions.save_to_disk import SaveToDiskAction from calibre.utils.formatter_functions import formatter_functions from calibre.gui2.dialogs.template_line_editor import TemplateLineEditor from polyglot.builtins import itervalues 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.templates.dialogs import TemplateBox from calibre_plugins.action_chains.templates import check_template class ModifiedSaveToDiskAction(SaveToDiskAction): def __init__(self, gui): self.gui = gui def save_to_disk(self, single_dir=False, single_format=None, rows=None, write_opf=None, save_cover=None, path=None, opts=None): if rows is None: rows = self.gui.current_view().selectionModel().selectedRows() if not rows or len(rows) == 0: return error_dialog(self.gui, _('Cannot save to disk'), _('No books selected'), show=True) if not path: path = choose_dir(self.gui, 'save to disk dialog', _('Choose destination folder')) if not path: return dpath = os.path.abspath(path).replace('/', os.sep)+os.sep lpath = self.gui.library_view.model().db.library_path.replace('/', os.sep)+os.sep if dpath.startswith(lpath): return error_dialog(self.gui, _('Not allowed'), _('You are trying to save files into the calibre ' 'library. This can cause corruption of your ' 'library. Save to disk is meant to export ' 'files from your calibre library elsewhere.'), show=True) if self.gui.current_view() is self.gui.library_view: from calibre.gui2.save import Saver from calibre.library.save_to_disk import config if opts is None: opts = config().parse() #print('debug1: opts.template: {}, opts.send_template: {}, opts.send_timefmt: {}, opts.timefmt: {}, opts.update_metadata: {}'.format(opts.template, opts.send_template, opts.send_timefmt, opts.timefmt, opts.update_metadata)) if single_format is not None: opts.formats = single_format # Special case for Kindle annotation files if single_format.lower() in ['mbp','pdr','tan']: opts.to_lowercase = False opts.save_cover = False opts.write_opf = False opts.template = opts.send_template opts.single_dir = single_dir if write_opf is not None: opts.write_opf = write_opf if save_cover is not None: opts.save_cover = save_cover book_ids = set(map(self.gui.library_view.model().id, rows)) Saver(book_ids, self.gui.current_db, opts, path, parent=self.gui, pool=self.gui.spare_pool()) else: paths = self.gui.current_view().model().paths(rows) self.gui.device_manager.save_books( Dispatcher(self.books_saved), paths, path) 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 = self.l = QVBoxLayout() self.setLayout(l) self.path_box = QGroupBox(_('&Choose path:')) l.addWidget(self.path_box) path_layout = QVBoxLayout() self.path_box.setLayout(path_layout) self.path_combo = DragDropComboBox(self, drop_mode='file') path_layout.addWidget(self.path_combo) hl1 = QHBoxLayout() path_layout.addLayout(hl1) hl1.addWidget(self.path_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) formats_gb = QGroupBox(_('Formats: '), self) l.addWidget(formats_gb) formats_l = QVBoxLayout() formats_gb.setLayout(formats_l) self.all_fmts_opt = QRadioButton(_('All formats')) self.all_fmts_opt.setChecked(True) formats_l.addWidget(self.all_fmts_opt) self.fmts_list_layout = QHBoxLayout() self.fmts_list_opt = QRadioButton(_('Save only specified formats')) self.fmts_list_edit = QLineEdit() self.fmts_list_edit.setToolTip(_('Comma separated list of formsts you want to save')) self.fmts_list_layout.addWidget(self.fmts_list_opt, 1) self.fmts_list_layout.addWidget(self.fmts_list_edit) formats_l.addLayout(self.fmts_list_layout) template_gb = QGroupBox(_('Template')) template_gb_l = QVBoxLayout() template_gb.setLayout(template_gb_l) self.default_template_opt = QRadioButton(_('Use template define in calibre preferences')) template_gb_l.addWidget(self.default_template_opt) self.default_template_opt.setChecked(True) self.user_template_opt = QRadioButton(_('Define a custom template for this action')) template_gb_l.addWidget(self.user_template_opt) l.addWidget(template_gb) self.user_template_opt.toggled.connect(self._on_template_opt_toggled) self.template_edit = TemplateLineEditor(self) template_gb_l.addWidget(self.template_edit) opts_gb = QGroupBox(_('Options: '), self) l.addWidget(opts_gb) opts_l = QVBoxLayout() opts_gb.setLayout(opts_l) self.single_folder_chk = QCheckBox(_('Save in a single folder')) opts_l.addWidget(self.single_folder_chk) self.save_cover_chk = QCheckBox(_('Save cover')) self.save_cover_chk.setChecked(True) opts_l.addWidget(self.save_cover_chk) self.save_opf_chk = QCheckBox(_('Save opf')) self.save_opf_chk.setChecked(True) opts_l.addWidget(self.save_opf_chk) l.addStretch(1) # self.all_formats = self.gui.library_view.model().db.all_formats() self._on_template_opt_toggled() self.setMinimumSize(400,500) def _on_template_opt_toggled(self): self.template_edit.setEnabled(self.user_template_opt.isChecked()) def _choose_path(self): path = choose_dir(self.gui, 'save to disk dialog', _('Choose destination folder')) if not path: return if iswindows: path = os.path.normpath(path) self.block_events = True existing_index = self.path_combo.findText(path, Qt.MatchExactly) if existing_index >= 0: self.path_combo.setCurrentIndex(existing_index) else: self.path_combo.insertItem(0, path) self.path_combo.setCurrentIndex(0) self.block_events = False def load_settings(self, settings): if settings: if settings['fmt_opt'] == 'all_formats': self.all_fmts_opt.setChecked(True) elif settings['fmt_opt'] == 'selected_formats': self.fmts_list_opt.setChecked(True) fmt = settings['formats'] self.fmts_list_edit.setText(fmt) self.path_combo.setCurrentText(settings['path']) template_opt = settings.get('template_opt', 'default') if template_opt == 'default': self.default_template_opt.setChecked(True) elif template_opt == 'user': self.user_template_opt.setChecked(True) self.template_edit.setText(settings['template']) self.single_folder_chk.setChecked(settings['single_folder']) self.save_cover_chk.setChecked(settings['save_cover']) self.save_opf_chk.setChecked(settings['save_opf']) def save_settings(self): settings = {} settings['path'] = self.path_combo.currentText().strip() if self.fmts_list_opt.isChecked(): settings['fmt_opt'] = 'selected_formats' settings['formats'] = self.fmts_list_edit.text() elif self.all_fmts_opt.isChecked(): settings['fmt_opt'] = 'all_formats' if self.default_template_opt.isChecked(): settings['template_opt'] = 'default' elif self.user_template_opt.isChecked(): settings['template_opt'] = 'user' settings['template'] = self.template_edit.text() settings['single_folder'] = self.single_folder_chk.isChecked() settings['save_cover'] = self.save_cover_chk.isChecked() settings['save_opf'] = self.save_opf_chk.isChecked() return settings class SaveToAction(ChainAction): name = 'Save to disk' def run(self, gui, settings, chain): from calibre.library.save_to_disk import config opts = copy.deepcopy(config().parse()) path = settings['path'] single_dir = settings['single_folder'] if settings['fmt_opt'] == 'selected_formats': opts.formats = settings['formats'].lower() if settings.get('template_opt', 'default') == 'user': opts.template = settings['template'] save_cover = settings['save_cover'] write_opf = settings['save_opf'] action = ModifiedSaveToDiskAction(gui) action.save_to_disk(single_dir=single_dir, write_opf=write_opf, save_cover=save_cover, path=path, opts=opts) def validate(self, settings): if not settings: return (_('Settings Error'), _('You must configure this action before running it')) path = settings['path'] if not path: return (_('No Directory'), _('You must specify a path to valid path')) if not (os.access(path, os.W_OK) and os.path.isdir(path)): return (_('Invalid direcotry'), _('Path is not a writable directory: {}'.format(path))) if not settings.get('fmt_opt'): return (_('No Path'), _('You must choose a format option')) if settings['fmt_opt'] == 'selected_formats': if not settings['formats']: return (_('No format'), _('You must choose a valid format value')) template_opt = settings.get('template_opt', 'default') if template_opt == 'user': template = settings['template'] if not template: return (_('No template'), _('You must specify a template')) else: # only calibre template functions, exclude Action Chains defined functions template_functions = formatter_functions().get_functions() is_template_valid = check_template(template, self.plugin_action, print_error=False, template_functions=template_functions) if is_template_valid is not True: return is_template_valid return True def config_widget(self): return ConfigWidget |
04-23-2024, 07:44 AM | #1319 |
Wizard
Posts: 1,092
Karma: 1948136
Join Date: Aug 2015
Device: Kindle
|
This code should not be pasted as a Python Code action within a chain. Instead go to Action Chains > Manage Modules > create > paste the code. Now you will have a new action called 'Save to disk' that can be used and configured in your chain.
|
04-23-2024, 08:25 AM | #1320 |
Enthusiast
Posts: 29
Karma: 10
Join Date: Mar 2017
Device: Kindle Paperwhite
|
Thanks capink
I've added these lines to save_to_disk method to save the path in a custom column but it's not working, nothing is written in the column : Code:
for row in rows: book_id = self.gui.library_view.model().id(row) set_metadata(self.gui.library_view.model().db, book_id, 'custompath', dpath) |
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
[Editor Plugin] Editor Chains | capink | Plugins | 86 | Today 05:54 PM |
Action Chains Resources | capink | Plugins | 54 | 01-29-2024 11:24 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 |