
Good morning. I am completely new to development in python and even more so in Calibre. I wanted, for my personal use, to prepare a small plugin that would allow me to manage the biography of an author, on several books at the same time. With the help of AI I made this plugin, which apparently integrates with Calibre because we see it in the plugin folder and also in Preferences>Plugins>User Interface Action. Unfortunately, I cannot test it, because it does not appear in the menu (despite the creation request). I searched in the different toolbars (in Preferences), in the shortcuts but without success. So maybe my code doesn't work, but I don't know because I can't test it. Sorry for my bad English: I am French speaking. And also sorry if my question is really stupid in your eyes: be lenient.
Could you tell me what I'm doing wrong?
here is the code for the 2 main files (the other 2, manifest.json and __init_.py are less important I believe):
1. ui.py
Code:
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel, QComboBox, QTextEdit, QPushButton
from calibre.gui2 import info_dialog
from calibre.gui2.dialogs.message_box import MessageBox
class BioManagerUI(QDialog):
"""
Fenêtre pour gérer les biographies des auteurs.
L'utilisateur sélectionne un auteur et saisit/modifie sa biographie.
"""
def __init__(self, gui, parent=None):
super(BioManagerUI, self).__init__(parent)
self.gui = gui
self.setWindowTitle("Gérer les biographies des auteurs")
self.resize(500, 400)
layout = QVBoxLayout(self)
# Label et menu déroulant pour sélectionner un auteur
label = QLabel("Sélectionnez un auteur :")
layout.addWidget(label)
self.combo = QComboBox(self)
self.combo.addItems(self.get_authors())
layout.addWidget(self.combo)
# Zone de saisie pour la biographie (support HTML)
self.text_edit = QTextEdit(self)
self.text_edit.setAcceptRichText(True)
layout.addWidget(self.text_edit)
# Bouton pour enregistrer
self.save_button = QPushButton("Enregistrer", self)
self.save_button.clicked.connect(self.save_bio)
layout.addWidget(self.save_button)
def get_authors(self):
"""
Récupère la liste de tous les auteurs présents dans la bibliothèque.
"""
db_instance = self.gui.current_db
authors = set()
for book_id in db_instance.all_book_ids():
mi = db_instance.get_metadata(book_id, index_is_id=True)
if mi.authors:
authors.update(mi.authors)
return sorted(authors)
def save_bio(self):
"""
Enregistre la biographie pour l'auteur sélectionné.
Si une biographie existe déjà, demande si l'utilisateur souhaite la remplacer ou l'ajouter.
"""
db_instance = self.gui.current_db
author = self.combo.currentText()
new_bio = self.text_edit.toHtml().strip()
count = 0
existing_bio = ""
for book_id in db_instance.all_book_ids():
mi = db_instance.get_metadata(book_id, index_is_id=True)
if mi.authors == [author]:
existing_bio = db_instance.get_custom(book_id, "#auteurbio") or ""
break
if existing_bio:
choice = MessageBox.question(
self.gui,
"Biographie existante",
f"Une biographie existe déjà pour {author}.\nVoulez-vous la remplacer ou l'ajouter ?",
"Remplacer", "Ajouter", "Annuler"
)
if choice == 2:
return
elif choice == 1:
new_bio = existing_bio + "\n\n" + new_bio
for book_id in db_instance.all_book_ids():
mi = db_instance.get_metadata(book_id, index_is_id=True)
if mi.authors == [author]:
db_instance.set_custom(book_id, "#auteurbio", new_bio)
count += 1
info_dialog(self.gui, "Succès", f"Biographie mise à jour pour {count} livre(s) de {author}.", show=True)
self. Accept()
2. plugin.py
Code:
import csv
import os, sys, subprocess, zipfile
from functools import partial
from calibre.constants import DEBUG, numeric_version as calibre_version
from calibre.gui2 import info_dialog, question_dialog, error_dialog, Dispatcher
from calibre.gui2.actions import InterfaceAction
from calibre.customize import InterfaceActionBase
#-----------------------------------------------
class BioManagerUpdate(InterfaceAction):
name = 'bio_manager_action'
action_spec = ('Gérer Biographies', None, 'Gérer les biographies des auteurs', None)
action_type = 'global'
accepts_drops = False
auto_repeat = False
priority = 9
popup_type = 1
def genesis(self):
# On récupère la fenêtre principale
self.maingui = self.gui
# Créer un sous-menu "Biographies" dans le menu "Outils"
self.menu = self.gui.main_window.menu.addMenu("Biographies")
# Ajout de l'action au sous-menu avec un identifiant unique (ici, "_v2" pour forcer le changement)
self.qaction.setText("Gérer Biographies")
self.qaction.triggered.connect(self.open_ui)
self.menu.addAction(self.qaction)
# Ajout de l'action dans le menu "Outils" (si disponible)
if hasattr(self.gui.main_window, 'menu_actions') and 'tools' in self.gui.main_window.menu_actions:
self.gui.main_window.menu_actions['tools'].addAction(self.qaction)
print("Plugin 'Gérer Biographies' chargé (v2).")
def apply_settings(self):
self.gui.add_action(self)
def open_ui(self):
try:
from calibre_plugins.bio_manager.ui import BioManagerUI
except ImportError:
from ui import BioManagerUI
ui = BioManagerUI(self.gui)
ui.exec_()
#-----------------------------------------------
class BioManagerPlugin(InterfaceActionBase):
name = "BioManager"
description = "Un plugin pour gérer les biographies des auteurs dans Calibre"
supported_platforms = ["windows", "osx", "linux"]
author = "ChatGPT & Joëlle"
version = (1, 0, 0)
minimum_calibre_version = (5, 0)
def load_actual_plugin(self, gui):
self.actual_plugin = BioManagerUpdate(gui)
gui.add_action(self.actual_plugin)
def unload_actual_plugin(self):
self.actual_plugin = None