![]() |
#76 | |
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,171
Karma: 77304081
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Quote:
|
|
![]() |
![]() |
![]() |
#77 | |
Guru
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 911
Karma: 810834
Join Date: Sep 2017
Location: Buenos Aires, Argentina
Device: moon+ reader, kindle paperwhite
|
Quote:
Okay, Calibre opens from the virtual library, but what I was looking for through action chains was for the book viewer to open books from that virtual library. |
|
![]() |
![]() |
![]() |
#78 | |
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,510
Karma: 8065348
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
The attached chain shows how to do it. Change the name of the VL in the selection modifier to what you want. |
|
![]() |
![]() |
![]() |
#79 |
Chalut o/
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 452
Karma: 678910
Join Date: Dec 2017
Device: Kobo
|
Re-calc Book Size
A little module to re-calc the size column of a book.
Useful if you've had edited the book files by a third-party program. Code:
import os from calibre_plugins.action_chains.actions.base import ChainAction class ReCalcSize(ChainAction): name = 'Re-calc Size' def run(self, gui, settings, chain): db = gui.current_db.new_api ids = chain.scope().get_book_ids() rslt = {} for book_id in ids: sizes = [0] for fmt in db.fields['formats'].for_book(book_id): path = db.format_abspath(book_id, fmt) sizes.append(os.path.getsize(path)) max_size = max(sizes) if max_size != db.fields['size'].for_book(book_id): rslt[book_id] = max_size db.fields['size'].table.update_sizes(rslt) db.update_last_modified(rslt.keys()) Last edited by un_pogaz; 08-06-2025 at 04:29 AM. |
![]() |
![]() |
![]() |
#80 | |
Custom User Title
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 11,171
Karma: 77304081
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Quote:
to use, create a long-text column (interpret type: plain text) with lookup name #fanficsettings. As I suggest editing settings in the personal.ini editor rather than the column itself, I also included Calibre ID in the commented header to make it easier to locate the book the section's associated with. An example from my library: Code:
## stillwaters01 - There Were Days (8382) [https://archiveofourown.org/works/959950] exclude_notes:chaptersummary |
|
![]() |
![]() |
![]() |
#81 |
Wizard
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1,212
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
|
Here is a custom action that addresses filtering problem, without the need for the user to use template language at all. It allows the following:
Code:
#!/usr/bin/env python # ~*~ coding: utf-8 ~*~ __license__ = 'GPL v3' __copyright__ = '2025, Ahmed Zaki <azaki00.dev@gmail.com>' __docformat__ = 'restructuredtext en' from qt.core import (QWidget, QVBoxLayout, QGroupBox, QRadioButton, QLineEdit, QCheckBox, QLabel) from calibre import prints from calibre.constants import DEBUG from calibre.utils.search_query_parser import ParseException from calibre_plugins.action_chains.actions.base import ChainAction from calibre_plugins.action_chains.database import is_search_valid 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) search_lbl = QLabel(_('Calibre search')) search_lbl.setToolTip(_('Use a regular calibre search')) l.addWidget(search_lbl) searchbox = self.searchbox = QLineEdit(self) searchbox.textChanged.connect(self._on_searchbox_text_change) l.addWidget(searchbox) selection_groupbox = QGroupBox(_('Selection options')) selection_groupbox_layout = QVBoxLayout() selection_groupbox.setLayout(selection_groupbox_layout) selected_opt = self.selected_opt = QRadioButton(_('Restrict to currently selected books')) selection_groupbox_layout.addWidget(selected_opt) selected_opt.setChecked(True) all_opt = self.all_opt = QRadioButton(_('Act on all books')) selection_groupbox_layout.addWidget(all_opt) scope_opt = self.scope_opt = QRadioButton(_('Restrict to books in current scope')) selection_groupbox_layout.addWidget(scope_opt) saved_selection_opt = self.saved_selection_opt = QRadioButton(_('Restrict to books saved in a variable')) selection_groupbox_layout.addWidget(saved_selection_opt) retrieve_variable_ledit = self.retrieve_variable_ledit = QLineEdit() selection_groupbox_layout.addWidget(retrieve_variable_ledit) self.l.addWidget(selection_groupbox) save_selection_gb = self.save_selection_gb = QGroupBox(_('Save currently selected books into a variable')) save_selection_l = QVBoxLayout() save_selection_gb.setLayout(save_selection_l) save_selection_gb.setCheckable(True) save_selection_lbl = QLabel(_('Variable name')) save_selection_ledit = self.save_selection_ledit = QLineEdit() save_selection_l.addWidget(save_selection_lbl) save_selection_l.addWidget(save_selection_ledit) l.addWidget(save_selection_gb) self.l.addStretch(1) self.setMinimumSize(300,400) def _on_searchbox_text_change(self): text = self.searchbox.text() if text: ok = is_search_valid(self.db, text) ss = 'QLineEdit { border: 2px solid %s; border-radius: 3px }' % ( '#50c878' if ok else '#FF2400') self.searchbox.setStyleSheet(ss) else: self.searchbox.setStyleSheet('') def load_settings(self, settings): if settings: search_text = settings.get('search_text', '') self.searchbox.setText(search_text) superset = settings.get('opt', 'selected_books') if superset == 'selected_books': self.selected_opt.setChecked(True) elif superset == 'current_scope': self.scope_opt.setChecked(True) elif superset == 'all_books': self.all_opt.setChecked(True) elif superset == 'saved_selection': self.saved_selection_opt.setChecked(True) self.retrieve_variable_ledit.setText(settings['retrieve_variable']) self.save_selection_gb.setChecked(settings['save_selection']) self.save_selection_ledit.setText(settings.get('save_variable', '')) def save_settings(self): settings = {} settings['search_text'] = self.searchbox.text() if self.selected_opt.isChecked(): settings['opt'] = 'selected_books' elif self.scope_opt.isChecked(): settings['opt'] = 'current_scope' elif self.all_opt.isChecked(): settings['opt'] = 'all_books' elif self.saved_selection_opt.isChecked(): settings['opt'] = 'saved_selection' settings['retrieve_variable'] = self.retrieve_variable_ledit.text() settings['save_selection'] = self.save_selection_gb.isChecked() if settings['save_selection']: settings['save_variable'] = self.save_selection_ledit.text().strip() return settings class SubsetSelector(ChainAction): name = 'Subset Selector' _is_builtin = False support_scopes = True def run(self, gui, settings, chain): db = gui.current_db cache = {} # dont save them yet, cache and save later if settings['save_selection']: cache['current_ids'] = gui.current_view().get_selected_ids() superset = settings.get('opt', 'selected_books') search_text = settings['search_text'].strip() if search_text: if superset == 'selected_books': if cache.get('current_ids'): superset_ids = cache['current_ids'] else: superset_ids = gui.current_view().get_selected_ids() elif superset == 'current_scope': superset_ids = chain.scope().get_book_ids() elif superset == 'all_books': superset_ids = gui.current_db.all_ids() elif superset == 'saved_selection': superset_ids = getattr(chain, 'python_vars', {}).get(settings['retrieve_variable'], None) if superset_ids == None: prints(f'Action Chains: Subset Selector: {settings["retrieve_variable"]} is empty') superset_ids = [] try: if not search_text: book_ids = superset_ids else: search_ids = db.data.search_getting_ids(search_text, '', use_virtual_library=False) if superset == 'all_books': book_ids = search_ids else: book_ids = list(set(search_ids).intersection(superset_ids)) except ParseException: book_ids = [] gui.current_view().select_rows(book_ids, change_current=True, scroll=False) # Avoid saving selected books early in case the opt # saved_selection is ticked if settings['save_selection']: save_variable = settings['save_variable'] if not hasattr(chain, 'python_vars'): chain.python_vars = {} chain.python_vars[save_variable] = cache['current_ids'] chain.chain_vars[save_variable] = ','.join([str(x) for x in chain.python_vars[save_variable]]) def validate(self, settings): gui = self.plugin_action.gui db = gui.current_db if not settings: return (_('Settings Error'), _('You must configure this superset before running it')) search_text = settings['search_text'] if not is_search_valid(db, search_text): return (_('Invalid search'), _(f'Search "{search_text}" is not valid')) if settings['save_selection'] and not settings.get('save_variable', '').strip(): return (_('Empty variable'), _('You must choose a variable name to save books')) if settings['opt'] == 'saved_selection' and not settings.get('retrieve_variable', '').strip(): return (_('Empty variable'), _('You must enter saved variable name')) return True def config_widget(self): return ConfigWidget
Notes:
Last edited by capink; Today at 08:42 AM. |
![]() |
![]() |
![]() |
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
[GUI Plugin] Action Chains | capink | Plugins | 1548 | Today 10:55 AM |
Book Scanning tool chains | tomsem | Workshop | 17 | 12-03-2023 09:19 AM |
Mystery and Crime Thorne, Guy: Chance in Chains (1914); v1 | Pulpmeister | Kindle Books | 0 | 11-25-2018 09:09 PM |
Mystery and Crime Thorne, Guy: Chance in Chains (1914); v1 | Pulpmeister | ePub Books | 0 | 11-25-2018 09:08 PM |
Could this be the last year for the big chains? | Connallmac | News | 66 | 01-07-2011 04:11 PM |