|
|
#1306 |
|
want to learn what I want
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,681
Karma: 7908443
Join Date: Sep 2020
Device: none
|
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 03:18 PM. |
|
|
|
|
|
#1307 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
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 | |
|
|
|
|
#1308 | |
|
want to learn what I want
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,681
Karma: 7908443
Join Date: Sep 2020
Device: none
|
Quote:
|
|
|
|
|
|
|
#1309 |
|
Zealot
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 105
Karma: 1435120
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 |
|
|
|
|
|
#1310 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,358
Karma: 79528341
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 | |
|
|
|
|
#1311 | |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
|
Quote:
|
|
|
|
|
|
|
#1312 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,358
Karma: 79528341
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
What's today's update? I not see a changelog entry.
|
|
|
|
|
|
#1313 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
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 04:18 PM. |
|
|
|
|
|
#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' |
|
|
|
|
|
#1315 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
|
I uploaded a new version. Try that.
|
|
|
|
|
|
#1316 |
|
Junior Member
![]() Posts: 2
Karma: 10
Join Date: Apr 2024
Location: Noorderwijk, Belgium
Device: android tablet
|
|
|
|
|
|
|
#1317 |
|
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,358
Karma: 79528341
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 04:34 PM. |
|
|
|
|
|
#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
|
|
|
|
|
|
#1319 |
|
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,216
Karma: 1995558
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.
|
|
|
|
|
|
#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 |
| Action Chains Resources | capink | Plugins | 80 | 09-18-2025 05:45 AM |
| [Editor Plugin] Editor Chains | capink | Plugins | 106 | 06-17-2025 06:36 PM |
| [GUI Plugin] Noosfere_util, a companion plugin to noosfere DB | lrpirlet | Plugins | 2 | 08-18-2022 04:15 PM |
| [GUI Plugin] Save Virtual Libraries To Column (GUI) | chaley | Plugins | 14 | 04-04-2021 06:25 AM |