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 06-03-2023, 05:56 AM   #1111
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,196
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
Quote:
Originally Posted by Philantrop View Post
Using version 1.18.7 I get an error when I try to add or modify an action type "Calibre Actions" and try calling its settings:

Code:
calibre, version 6.19.1
ERROR: Unhandled exception: <b>AttributeError</b>:'int' object has no attribute 'replace'

calibre 6.19.1  embedded-python: True
Linux-6.3.3-200.fc38.x86_64-x86_64-with-glibc2.37 Linux ('64bit', 'ELF')
('Linux', '6.3.3-200.fc38.x86_64', '#1 SMP PREEMPT_DYNAMIC Wed May 17 14:31:24 UTC 2023')
Python 3.10.1
Interface language: en_GB
Successfully initialized third party plugins: [...]

Traceback (most recent call last):
  File "calibre_plugins.action_chains.gui.__init__", line 46, in setup_ui
    self.widget = self.widget_cls(self.plugin_action, self.chain_name, self.chains_config)
TypeError: CalibreActionsWidget.__init__() takes 2 positional arguments but 4 were given

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "calibre_plugins.action_chains.gui.views", line 430, in _on_button_clicked
    d = SettingsWidgetDialog(name, self, self.plugin_action, config_widget, action, m.chain_name, m.chains_config, title)
  File "calibre_plugins.action_chains.gui.__init__", line 41, in __init__
    Dialog.__init__(self, title, name, parent)
  File "calibre/gui2/widgets2.py", line 225, in __init__
  File "calibre_plugins.action_chains.gui.__init__", line 51, in setup_ui
    self.widget = self.widget_cls(self.plugin_action)
  File "calibre_plugins.action_chains.actions.calibre_actions", line 162, in __init__
    self._init_controls()
  File "calibre_plugins.action_chains.actions.calibre_actions", line 197, in _init_controls
    self._populate_actions_tree(lookup_menu_map)
  File "calibre_plugins.action_chains.actions.calibre_actions", line 287, in _populate_actions_tree
    self._populate_action_children(QMenu.actions(m), tl,
  File "calibre_plugins.action_chains.actions.calibre_actions", line 307, in _populate_action_children
    text = get_title(ac, plugin_name)
  File "calibre_plugins.action_chains.actions.calibre_actions", line 74, in get_title
    safe_title = get_safe_title(action)
  File "calibre_plugins.action_chains.actions.calibre_actions", line 68, in get_safe_title
    return text.replace('&&', '—').replace('&', '').replace('—', '&')
AttributeError: 'int' object has no attribute 'replace'
Cannot replicate. Export the chain and post it here.
capink is offline   Reply With Quote
Old 06-12-2023, 01:14 PM   #1112
Bertrand
Zealot
Bertrand began at the beginning.
 
Posts: 124
Karma: 10
Join Date: Dec 2008
Location: France
Device: None
Windows 11 / calibre 6.20 / Action Chains 1.18.7

I have the same problem as Philantrop.
I can't add a calibre action.

Here is the json file from export.

Spoiler:

Code:
calibre, version 6.20.0
ERREUR : Exception non gérée: <b>AttributeError</b>:'int' object has no attribute 'replace'

calibre 6.20  embedded-python: True
Windows-10-10.0.22621-SP0 Windows ('64bit', 'WindowsPE')
('Windows', '10', '10.0.22621')
Python 3.10.1
Windows: ('10', '10.0.22621', 'SP0', 'Multiprocessor Free')
Interface language: fr
Successfully initialized third party plugins: Action Chains (1, 18, 7) && Comments Cleaner (1, 10, 0) && Count Pages (1, 13, 0) && EpubCheck (0, 2, 4) && Extract ISBN (1, 6, 0) && Favourites Menu (1, 3, 0) && Find Duplicates (1, 10, 8) && Kobo Books (1, 9, 2) && KoboTouchExtended (3, 6, 3) && Modify ePub (1, 8, 1) && Open With (1, 8, 1) && Quality Check (1, 13, 4) && View Manager (1, 10, 2) && Walk Search History (1, 5, 3)
Traceback (most recent call last):
  File "calibre_plugins.action_chains.gui.__init__", line 46, in setup_ui
TypeError: CalibreActionsWidget.__init__() takes 2 positional arguments but 4 were given

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "calibre_plugins.action_chains.gui.views", line 430, in _on_button_clicked
  File "calibre_plugins.action_chains.gui.__init__", line 41, in __init__
  File "calibre\gui2\widgets2.py", line 225, in __init__
  File "calibre_plugins.action_chains.gui.__init__", line 51, in setup_ui
  File "calibre_plugins.action_chains.actions.calibre_actions", line 162, in __init__
  File "calibre_plugins.action_chains.actions.calibre_actions", line 197, in _init_controls
  File "calibre_plugins.action_chains.actions.calibre_actions", line 287, in _populate_actions_tree
  File "calibre_plugins.action_chains.actions.calibre_actions", line 307, in _populate_action_children
  File "calibre_plugins.action_chains.actions.calibre_actions", line 74, in get_title
  File "calibre_plugins.action_chains.actions.calibre_actions", line 68, in get_safe_title
AttributeError: 'int' object has no attribute 'replace'


Thanks
Attached Files
File Type: zip action chains.zip (712 Bytes, 625 views)
Bertrand is offline   Reply With Quote
Old 06-13-2023, 06:38 AM   #1113
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,196
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
Quote:
Originally Posted by Bertrand View Post
Windows 11 / calibre 6.20 / Action Chains 1.18.7

I have the same problem as Philantrop.
I can't add a calibre action.

Here is the json file from export.

Thanks
I still cannot replicate the problem even when switching language to French. The strange thing is that the calibre actions you uploaded does not run the function that raises the error, because it is a top level action (Extract ISBN). Are you sure you uploaded the right chain?

Anyway, here is modified version of the plugin that has print some debug statements. Please run this modified version in debug mode, and post your debug log.

Last edited by capink; 06-14-2023 at 01:43 PM. Reason: remove debug version
capink is offline   Reply With Quote
Old 06-13-2023, 07:17 AM   #1114
Bertrand
Zealot
Bertrand began at the beginning.
 
Posts: 124
Karma: 10
Join Date: Dec 2008
Location: France
Device: None
Thank you.

Here is the log file (not sure if it is what you want) and a new export of the action chain, just in case.

To be clear, I get the error as soon as I click the icon settings
- If I want to modify a calibre action (for example, Extract ISBN in the screenshot)
- If I want to add a calibre action

(I also tried on a portable version of calibre, and I get the same thing)
Attached Thumbnails
Click image for larger version

Name:	20230613_130415.jpg
Views:	1027
Size:	130.5 KB
ID:	202002  
Attached Files
File Type: txt log.txt (23.3 KB, 493 views)
File Type: zip nettoyage 1.zip (712 Bytes, 651 views)
Bertrand is offline   Reply With Quote
Old 06-13-2023, 07:44 AM   #1115
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,196
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
From what I can see from the log the problem is one of the multiple SortAction is returning an int value of 0 instead of returning a text value (when calling QAction.text() method). I don't why this is happening and why it is not replicated on my system.

Anyway try this new version, see whether it helps with the problem.

Last edited by capink; 06-14-2023 at 01:42 PM. Reason: zip removed. New version with modifications releases
capink is offline   Reply With Quote
Old 06-13-2023, 08:50 AM   #1116
Bertrand
Zealot
Bertrand began at the beginning.
 
Posts: 124
Karma: 10
Join Date: Dec 2008
Location: France
Device: None
It works.
Thanks a lot !
Bertrand is offline   Reply With Quote
Old 06-14-2023, 01:12 PM   #1117
Philantrop
Addict
Philantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beautyPhilantrop does all things with Zen-like beauty
 
Philantrop's Avatar
 
Posts: 296
Karma: 32153
Join Date: Dec 2008
Device: Kindles (e-ink)
Quote:
Originally Posted by capink View Post
From what I can see from the log the problem is one of the multiple SortAction is returning an int value of 0 instead of returning a text value (when calling QAction.text() method). I don't why this is happening and why it is not replicated on my system.

Anyway try this new version, see whether it helps with the problem.
I'm late to the party because I never got notified of your reply, sorry. I'm all the more happy to also report things working fine now. Thank you very much for the fix and, of course, this fabulous plugin!
Philantrop is offline   Reply With Quote
Old 07-05-2023, 01:07 AM   #1118
Comfy.n
want to learn what I want
Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.
 
Posts: 1,614
Karma: 7891011
Join Date: Sep 2020
Device: none
Hi, do we have a chain for Prince PDF plugin? I could only set up the first step, that runs the existing Calibre Action and brings up the plugin dialog. Then we would need some script to send alt+P, then maybe wait a second, then send alt + V.
Comfy.n is offline   Reply With Quote
Old 07-05-2023, 04:38 AM   #1119
Venia Legendi
Member
Venia Legendi began at the beginning.
 
Venia Legendi's Avatar
 
Posts: 13
Karma: 10
Join Date: Apr 2013
Device: lots of, frequently changing
Persistant vars?

Trying to use an old chain (which has worked AFAIK), I get "EXCEPTION: Formatter: Unknown function set_persistent_vars"?

Problem in front of the screen?

Quote:
Originally Posted by capink View Post
Version 1.7.0
  • Update: Add persistent storage for templates. Can be accessed using these new template functions: persistent_vars(), set_persistent_vars(), list_persistent_vars(), delete_persistent_vars(), list_persistent_namespaces(), delete_persistent_namespaces()
Venia Legendi is offline   Reply With Quote
Old 07-05-2023, 07:21 AM   #1120
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,196
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
Quote:
Originally Posted by Venia Legendi View Post
Trying to use an old chain (which has worked AFAIK), I get "EXCEPTION: Formatter: Unknown function set_persistent_vars"?

Problem in front of the screen?
Persistent vars functions were removed after the introduction of python templates, which provides better solution if you know python.

I thought no one used them. But if you want to get them back, copy the code below into your module editor:

Code:
from calibre.utils.config import JSONConfig
from calibre_plugins.action_chains.templates.functions.base import TemplateFunction

###########################################
# Persistent Vars
###########################################

persistent_storage = JSONConfig('plugins/action_chains/action-chains-persistent-storage')

# initialize root namespace if not present
if not persistent_storage.get('root_namespace'):
    persistent_storage['root_namespace'] = {}

class VarStorage(object):

    def __init__(self):
        self.root_namespace = persistent_storage['root_namespace']
        # prefixes are used to avoid vars overwriting namespaces
        self.var_type = 'VAR'
        self.ns_type = 'NS'

    # Naming rules : {{{{
    def mangle_name(self, name, typ):
        if not self.validate_name(name):
            raise ValueError('Invalid {} name: {}'.format(typ, name))
        prefix = '_{}_'.format(typ)
        name = name if name.startswith(prefix) else prefix + name
        return name

    def unmangle_name(self, name, typ):
        prefix = '_{}_'.format(typ)
        if name.startswith(prefix):
            name = name.replace(prefix, '')
        return name

    def is_var(self, name):
        prefix = '_{}_'.format(self.var_type)
        if name.startswith(prefix):
            return True
        return False

    def is_namespace(self, name):
        prefix = '_{}_'.format(self.ns_type)
        if name.startswith(prefix):
            return True
        return False

    def validate_namespace_path(self, namespace_path):
        for node in namespace_path:
            if not self.validate_name(node):
                return False
        return True

    def validate_name(self, name):
        if not name.replace('_', '').isalnum():
            return False
        return True

    def mangle_namespace_path(self, namespace_path):
        if not self.validate_namespace_path(namespace_path):
            raise ValueError('Invalid namespace path: {}'.format(namespace_path))
        mangled_path = []
        for node in namespace_path:
            mangled_node = self.mangle_name(node, self.ns_type)
            mangled_path.append(mangled_node)
        return mangled_path
    # }}}}

    def commit(self):
        persistent_storage.commit()

    def get_namespace(self, namespace_path=[]):
        mangled_path = self.mangle_namespace_path(namespace_path)
        ns = self.root_namespace
        for node in mangled_path:
            try:
                ns = ns[node]
            except KeyError as e:
                raise ValueError('Namespace cannot be found: {}'.format(namespace_path))
        return ns

    def create_namespace_if_not_present(self, namespace_path=[]):
        mangled_path = self.mangle_namespace_path(namespace_path)
        ns = self.root_namespace
        for node in mangled_path:
            if not ns.get(node):
                ns[node] = {}
            ns = ns[node]

    def get_var(self, var_name, namespace_path=[]):
        try:
            namespace = self.get_namespace(namespace_path)
        except:
            return ''
        name = self.mangle_name(var_name, self.var_type)
        return namespace.get(name, '')

    def set_var(self, var_name, var_value, namespace_path=[]):
        if not isinstance(var_value, str):
            raise ValueError('Persistent variable values can only of string type')
        self.create_namespace_if_not_present(namespace_path)
        namespace = self.get_namespace(namespace_path)
        name = self.mangle_name(var_name, self.var_type)
        namespace[name] = var_value
        self.commit()

    def list_vars(self, namespace_path=[]):
        namespace = self.get_namespace(namespace_path)
        all_vars = []
        for name in namespace.keys():
            if self.is_var(name):
                var = self.unmangle_name(name, self.var_type)
                all_vars.append(var)
        return all_vars

    def list_namespaces(self, namespace_path=[]):
        if not namespace_path:
            namespace = self.root_namespace
        else:
            namespace = self.get_namespace(namespace_path)
        all_ns = []
        for name in namespace.keys():
            if self.is_namespace(name):
                ns = self.unmangle_name(name, self.ns_type)
                all_ns.append(ns)
        return all_ns

    def delete_namespace(self, namespace_path=[]):
        if not namespace_path:
            self.root_namespace.clear()
        else:
            if len(namespace_path) == 1:
                parent = self.root_namespace
            elif len(namespace_path) > 1:
                parent_path = namespace_path[:-1]
                parent = self.get_namespace(parent_path)
            mangled_name = self.mangle_name(namespace_path[-1], self.ns_type)
            del parent[mangled_name]
        self.commit()

    def delete_var(self, var_name, namespace_path=[]):
        namespace = self.get_namespace(namespace_path)
        mangled_name = self.mangle_name(var_name, self.var_type)
        del namespace[mangled_name]
        self.commit()

persistent_vars = VarStorage()


###########################################
# Persistent Vars Template Functions
###########################################

class PersistentVars(TemplateFunction):

    doc = _('Retrieve value for variable stored in persistent memory using set_persistent_vars()\n'
            'Usage: persistent_vars(var_name, [namespace])\n'
            '`var_name`: name of the variable\n'
            '`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
            'are possible and are represented by dot notation e.g. namespace1.namspace2 '
            'If no namespace is provided, the default namespace will be used.\n'
            'This function is part of the action chain plugin and will not work elsewhere.')
    name = 'persistent_vars'
    arg_count = -1

    def evaluate(self, formatter, kwargs, mi, locals, *args):
        if len(args) not in [1, 2]:
            raise ValueError('Incorrect number of arguments')
        var_name = args[0]
        if len(args) == 2:
            namespace_path = args[1].split('.')
        else:
            namespace_path = []
        if not persistent_vars.validate_namespace_path(namespace_path):
            raise ValueError('Namespaces must contain only letter, numbers and underscores')
        try:
            return persistent_vars.get_var(var_name, namespace_path)
        except:
            # if namespace cannot be found
            return ''

class SetPersistentVars(TemplateFunction):

    doc = _('Set variables to presistent memory\n'
            'Usage: set_persistent_vars(var_name, var_value, [namespace])\n'
            '`var_name`: name of the variable\n'
            '`var_value`: value of the variable\n'
            '`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
            'are possible and are represented by dot notation e.g. namespace1.namspace2 '
            'If no namespace is provided, the default namespace will be used.\n'
            'This function is part of the action chain plugin and will not work elsewhere.')
    name = 'set_persistent_vars'
    arg_count = -1

    def evaluate(self, formatter, kwargs, mi, locals, *args):
        if len(args) not in [2, 3]:
            raise ValueError('Incorrect number of arguments')
        var_name = args[0]
        var_value = args[1]
        if not persistent_vars.validate_name(var_name):
            raise ValueError('Invalid variable name: {}'.format(var_name))
        if len(args) == 3:
            namespace_path = args[2].split('.')
        else:
            namespace_path = []
        if not persistent_vars.validate_namespace_path(namespace_path):
            raise ValueError('Namespaces must contain only letter, numbers and underscores')
        # We don't want to write vars when the user is typing in the template
        if not self.context == 'template_dialog_mode':
            persistent_vars.set_var(var_name, var_value, namespace_path)
        return ''

class DeletePersistentVars(TemplateFunction):

    doc = _('Delete variable from presistent memory\n'
            'Usage: set_persistent_vars(var_name, var_value, [namespace])\n'
            '`var_name`: name of the variable\n'
            '`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
            'are possible and are represented by dot notation e.g. namespace1.namspace2 '
            'If no namespace is provided, the default namespace will be used.\n'
            'This function is part of the action chain plugin and will not work elsewhere.')
    name = 'delete_persistent_vars'
    arg_count = -1

    def evaluate(self, formatter, kwargs, mi, locals, *args):
        if len(args) not in [1, 2]:
            raise ValueError('Incorrect number of arguments')
        var_name = args[0]
        if not persistent_vars.validate_name(var_name):
            raise ValueError('Invalid variable name: {}'.format(var_name))
        if len(args) == 2:
            namespace_path = args[1].split('.')
        else:
            namespace_path = []
        if not persistent_vars.validate_namespace_path(namespace_path):
            raise ValueError('Namespaces must contain only letter, numbers and underscores')
        # We don't want to delete vars when the user is typing in the template
        if not self.context == 'template_dialog_mode':
            try:
                persistent_vars.delete_var(var_name, namespace_path)
            except Exception as e:
                import traceback
                print(traceback.format_exc())
        return ''

class ListPersistentVars(TemplateFunction):

    doc = _('List variables stored in presistent memory using set_persistent_vars()\n'
            'Usage: list_persistent_vars([namespace])\n'
            '`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
            'are possible and are represented by dot notation e.g. namespace1.namspace2 '
            'If no namespace is provided, the default namespace will be used.\n'
            'This function is part of the action chain plugin and will not work elsewhere.')
    name = 'list_persistent_vars'
    arg_count = -1

    def evaluate(self, formatter, kwargs, mi, locals, *args):
        if len(args) not in [0, 1]:
            raise ValueError('Incorrect number of arguments')
        if len(args) == 1:
            namespace_path = args[0].split('.')
        else:
            namespace_path = []
        if not persistent_vars.validate_namespace_path(namespace_path):
            raise ValueError('Namespaces must contain only letter, numbers and underscores')
        all_vars = persistent_vars.list_vars(namespace_path)
        return ','.join(all_vars)

class ListPersistentNamespaces(TemplateFunction):

    doc = _('List namespaces in presistent memory used by set_persistent_vars()\n'
            'Usage: list_persistent_namespaces([namespace])\n'
            '`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
            'are possible and are represented by dot notation e.g. namespace1.namspace2 '
            'If no namespace is provided, all top level namespaces will be listed.\n'
            'This function is part of the action chain plugin and will not work elsewhere.')
    name = 'list_persistent_namespaces'
    arg_count = -1

    def evaluate(self, formatter, kwargs, mi, locals, *args):
        if len(args) not in [0, 1]:
            raise ValueError('Incorrect number of arguments')
        if len(args) == 1:
            namespace_path = args[0].split('.')
        else:
            namespace_path = []
        if not persistent_vars.validate_namespace_path(namespace_path):
            raise ValueError('Namespaces must contain only letter, numbers and underscores')
        all_ns = persistent_vars.list_namespaces(namespace_path)
        return ','.join(all_ns)

class DeletePersistentNamespaces(TemplateFunction):

    doc = _('Delete a namespace in presistent memory used by set_persistent_vars()\n'
            'Usage: delete_persistent_namespaces([namespace])\n'
            '`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
            'are possible and are represented by dot notation e.g. namespace1.namspace2 '
            'If no namespace is provided, the top level namespace including all namespaces and '
            'vars will be deleted\n'
            'This function is part of the action chain plugin and will not work elsewhere.')
    name = 'delete_persistent_namespaces'
    arg_count = -1

    def evaluate(self, formatter, kwargs, mi, locals, *args):
        if len(args) not in [0, 1]:
            raise ValueError('Incorrect number of arguments')
        if len(args) == 1:
            namespace_path = args[0].split('.')
        else:
            namespace_path = []
        if not persistent_vars.validate_namespace_path(namespace_path):
            raise ValueError('Namespaces must contain only letter, numbers and underscores')
        # We don't want to delete namespaces when the user is typing in the template
        if not self.context == 'template_dialog_mode':
            try:
                persistent_vars.delete_namespace(namespace_path)
            except Exception as e:
                import traceback
                print(traceback.format_exc())
        return ''
capink is offline   Reply With Quote
Old 07-05-2023, 07:24 AM   #1121
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,196
Karma: 1995558
Join Date: Aug 2015
Device: Kindle
Quote:
Originally Posted by Comfy.n View Post
Hi, do we have a chain for Prince PDF plugin? I could only set up the first step, that runs the existing Calibre Action and brings up the plugin dialog. Then we would need some script to send alt+P, then maybe wait a second, then send alt + V.
No. It it is not working through Calibre Actions, the only way is for someone to write a custom action that calls the plugin's code directly.
capink is offline   Reply With Quote
Old 07-05-2023, 07:36 AM   #1122
Comfy.n
want to learn what I want
Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.
 
Posts: 1,614
Karma: 7891011
Join Date: Sep 2020
Device: none
Quote:
Originally Posted by capink View Post
No. It it is not working through Calibre Actions, the only way is for someone to write a custom action that calls the plugin's code directly.
understood, thanks!
Comfy.n is offline   Reply With Quote
Old 07-05-2023, 10:28 AM   #1123
Venia Legendi
Member
Venia Legendi began at the beginning.
 
Venia Legendi's Avatar
 
Posts: 13
Karma: 10
Join Date: Apr 2013
Device: lots of, frequently changing
Quote:
Originally Posted by capink View Post
Persistent vars functions were removed after the introduction of python templates, which provides better solution if you know python.

I thought no one used them. But if you want to get them back, copy the code below into your module editor:
Thank you, code works, I'll switch then to python templates.
Venia Legendi is offline   Reply With Quote
Old 07-12-2023, 10:45 AM   #1124
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: 11,007
Karma: 75555555
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
Question: Is there a method to add a file to the extra data folder similar to SFE on 'formats'?

Context: I have a chain that copies the cover path to clipboard then follows it with the 'add data file' Calibre action where I paste it in. It's a little clunky though.
ownedbycats is offline   Reply With Quote
Old 07-12-2023, 02:16 PM   #1125
chaley
Grand Sorcerer
chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.
 
Posts: 12,447
Karma: 8012886
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
Quote:
Originally Posted by ownedbycats View Post
Question: Is there a method to add a file to the extra data folder similar to SFE on 'formats'?

Context: I have a chain that copies the cover path to clipboard then follows it with the 'add data file' Calibre action where I paste it in. It's a little clunky though.
You can do this with a python template. It would probably be better as an Action Chains python action but I didn't feel like doing that.

Code:
python:
def evaluate(book, context):
	import os
	from shutil import copy
	from calibre.db.constants import DATA_DIR_NAME

	db = context.db
	cache = db.new_api
	# Get the normalized library path
	library_path = cache.backend.library_path
	
    # Construct the full path to the book folder
	path = os.path.join(library_path, cache.field_for('path', book.id).replace('/', os.sep))

	# Ensure the data directory exists
	data_dir = os.path.join(path, DATA_DIR_NAME)
	if not os.path.exists(data_dir):
		os.mkdir(data_dir)

	cover_file = os.path.join(path, 'cover.jpg')
	if os.path.exists(cover_file):
		# It does. Copy it to the data directory. The 'copy' method takes a
		# directory as a target.
		copy(cover_file, data_dir)
		return 'copied'
	return 'not copied'
chaley is offline   Reply With Quote
Reply


Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
[Editor Plugin] Editor Chains capink Plugins 106 06-17-2025 05:36 PM
Action Chains Resources capink Plugins 77 06-16-2025 12:45 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 07:11 AM.


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