|
|
#601 |
|
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 5,763
Karma: 24088559
Join Date: Dec 2010
Device: Kindle PW2
|
I'd strongly recommend Automate the Boring Stuff with Python by Al Sweigart, which is available for free online.
You'll also need to download the Sigil Framework Guide. You also might find the Sigil test plugin helpful because it demonstrates most Sigil-specific Python functions. Here's a minimal proof-of-concept edit plugin that will wrap "the" in all html files in <b> tags: Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os
# main routine
def run(bk):
# iterate over all html files
for html_id, href in bk.text_iter():
# read orignal html code from file
original_html = bk.readfile(html_id)
# modify html code
modified_html = original_html.replace('the', '<b>the</b>')
if modified_html != original_html:
# write modified html code to file
bk.writefile(html_id, modified_html)
print(os.path.basename(href) + ' updated')
return 0
def main():
print('I reached main when I should not have\n')
return -1
if __name__ == "__main__":
sys.exit(main())
Code:
from sigil_bs4 import BeautifulSoup
|
|
|
|
|
|
#602 |
|
Sigil Developer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 9,089
Karma: 6379704
Join Date: Nov 2009
Device: many
|
Just to be clear ...
Sigil plugins only allow batch processing of files inside a single loaded epub. If you want to batch process a number of epubs without having to load them in Sigil, python is the way to go but not Sigil Plugins. That said the python modules in Sigil could be extracted and used in a standalone python program with only low to moderate effort. Last edited by KevinH; 10-19-2025 at 09:06 AM. |
|
|
|
|
|
#603 | |
|
Well trained by Cats
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 31,299
Karma: 62000000
Join Date: Aug 2009
Location: The Central Coast of California
Device: Kobo Libra2,Kobo Aura2v1, K4NT(Fixed: New Bat.), Galaxy Tab A
|
Quote:
This is one of the reasons I use Sigil for some tasks and Calibre Editor for others. They fit MY workflow (please keep doing Sigil things, the Sigil way), and Calibre does others. All we need to do is learn to use the tools we have without making those other folk that want the other way (either editor) use OUR way. Only if it is broken, does it need fixin'
|
|
|
|
|
|
|
#604 | |
|
Belgian Pommes Frites
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 131
Karma: 35038
Join Date: Jan 2012
Device: Pocketbook Touch HD
|
Tools
Quote:
|
|
|
|
|
|
|
#605 |
|
Junior Member
![]() Posts: 8
Karma: 10
Join Date: Oct 2025
Device: i dont have one
|
hi , I'm new here and off course i need help
![]() i do not know how to even read python but i'm using AI and off course i'm stuck with a problem... I'm developing a large plugin for adding tool-tips, footnotes and sidebar notes and margin notes for a book i'm working on, and it is going to need a lot of notes So the problem i had at first was that the AI couldn't get the GUI buttons added to caliber editor and even when it succeeded it would break it by accident later and would take very long trying to fix it again . Eventually i decided to ask it to make a shim API for adding menus and buttons to the toolbar and it succeeded with the first but the second is broken and it cannot fix it ![]() Here is the code if any one can help make it work i will be super grateful it add menus and commands under them but it keep adding a drop-down menu to the toolbar and the AI can not tell how to make it add individual commands here is the python code for the shim Code:
# shim.py
# Qt compatibility
try:
from PyQt6.QtWidgets import (QMainWindow, QToolBar, QMenu, QToolButton)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QIcon, QAction
except ImportError:
from PyQt5.QtWidgets import (QMainWindow, QToolBar, QMenu, QToolButton, QAction)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
# Mock Boss and GUI for testing
class MockGui(QMainWindow):
def __init__(self):
super().__init__()
self.resize(800, 600)
self.setWindowTitle("Shim GUI Test")
self.menuBar() # Initialize menu bar
self.plugins_menu = self.menuBar().addMenu('&Plugins')
tb = self.addToolBar("Plugins toolbar")
tb.setObjectName("plugins-toolbar")
tb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
class MockBoss:
def __init__(self):
self.gui = MockGui()
# ShimBoss with new APIs
class ShimBoss:
def __init__(self, gui):
self.gui = gui
def get_plugins_menu(self):
mb = self.gui.menuBar()
for a in mb.actions():
m = a.menu()
if m and m.title() == '&Plugins':
return m
return None
def add_menu_action(self, menu_path, action_text, callback, shortcut=None, icon_path=None, tooltip=None, name=None):
paths = menu_path.split('|')
if paths[0] == 'Plugins':
menu = self.get_plugins_menu()
paths = paths[1:]
else:
mb = self.gui.menuBar()
root_title = paths[0]
menu = None
for a in mb.actions():
m = a.menu()
if m and m.title() == root_title:
menu = m
break
if not menu:
menu = mb.addMenu(root_title)
paths = paths[1:]
for p in paths:
found = False
for a in menu.actions():
if a.menu() and a.menu().title() == p:
menu = a.menu()
found = True
break
if not found:
menu = menu.addMenu(p)
ac = menu.addAction(action_text)
if icon_path:
ac.setIcon(QIcon(icon_path))
if tooltip:
ac.setToolTip(tooltip)
if shortcut:
ac.setShortcut(shortcut)
if name:
ac.setObjectName(name)
ac.triggered.connect(callback)
return ac
def add_toolbar_action(self, action_text, callback, toolbar_name='plugins-toolbar', icon_path=None, tooltip=None, name=None):
tb = self.gui.findChild(QToolBar, toolbar_name)
if not tb:
tb = self.gui.addToolBar('Plugins')
tb.setObjectName(toolbar_name)
ac = QAction(action_text, self.gui)
if icon_path:
ac.setIcon(QIcon(icon_path))
if tooltip:
ac.setToolTip(tooltip)
if name:
ac.setObjectName(name)
ac.triggered.connect(callback)
tb.addAction(ac)
widget = tb.widgetForAction(ac)
if widget:
widget.setPopupMode(QToolButton.NoButton)
return ac
def add_toolbar_dropdown(self, button_text, actions_list, toolbar_name='plugins-toolbar', icon_path=None, tooltip=None):
"""
Add a dropdown toolbar button with sub-actions.
actions_list: list of dicts, e.g., [{'text': 'Sub1', 'callback': fn1, 'shortcut': None, 'icon_path': None, 'tooltip': None}]
"""
tb = self.gui.findChild(QToolBar, toolbar_name)
if not tb:
tb = self.gui.addToolBar('Plugins')
tb.setObjectName(toolbar_name)
toolbutton = QToolButton(self.gui)
toolbutton.setText(button_text)
if icon_path:
toolbutton.setIcon(QIcon(icon_path))
if tooltip:
toolbutton.setToolTip(tooltip)
menu = QMenu(toolbutton)
for act_dict in actions_list:
ac = menu.addAction(act_dict['text'])
if act_dict.get('icon_path'):
ac.setIcon(QIcon(act_dict['icon_path']))
if act_dict.get('tooltip'):
ac.setToolTip(act_dict['tooltip'])
if act_dict.get('shortcut'):
ac.setShortcut(act_dict['shortcut'])
ac.triggered.connect(act_dict['callback'])
toolbutton.setMenu(menu)
toolbutton.setPopupMode(QToolButton.InstantPopup)
tb.addWidget(toolbutton)
return toolbutton
def hide_toolbar_action(self, name, toolbar_name='plugins-toolbar'):
tb = self.gui.findChild(QToolBar, toolbar_name)
if tb:
for ac in tb.actions():
if ac.objectName() == name:
ac.setVisible(False)
def show_toolbar_action(self, name, toolbar_name='plugins-toolbar'):
tb = self.gui.findChild(QToolBar, toolbar_name)
if tb:
for ac in tb.actions():
if ac.objectName() == name:
ac.setVisible(True)
if __name__ == "__main__":
try:
from PyQt6.QtWidgets import QApplication
except ImportError:
from PyQt5.QtWidgets import QApplication
import sys
app = QApplication(sys.argv)
boss = MockBoss()
shim = ShimBoss(boss.gui)
# Test additions
def quick_fn():
print("Quick action triggered")
shim.add_menu_action('Plugins|Footnotes', 'Test Action', quick_fn, shortcut='Ctrl+T', tooltip='Test')
shim.add_toolbar_action('Quick Action', quick_fn, tooltip='Quick fn', name='quick_action')
# Example hide/show
shim.hide_toolbar_action('quick_action')
shim.show_toolbar_action('quick_action')
boss.gui.show()
sys.exit(app.exec_())
thank you very much in advance |
|
|
|
|
|
#606 |
|
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 28,914
Karma: 207182180
Join Date: Jan 2010
Device: Nexus 7, Kindle Fire HD
|
This is not the Calibre plugin development section of the forum. This area is for Sigil plugin development.
|
|
|
|
|
|
#607 |
|
Sigil Developer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 9,089
Karma: 6379704
Join Date: Nov 2009
Device: many
|
I am beginning to think that use of AI to "code" by non-developers is akin to giving a loaded handgun with the safety off to a complete firearms novice with no instructions on safety, or on use, or even common sense.
The only thing both will generate is a big mess. Let's hope after 25,000 lines of code, I'm wrong, but ... Last edited by KevinH; 10-24-2025 at 12:19 PM. |
|
|
|
|
|
#608 |
|
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 28,914
Karma: 207182180
Join Date: Jan 2010
Device: Nexus 7, Kindle Fire HD
|
I don't mind if people want to use AI for creating code for themselves. I just have a hard time understanding how I can assist someone with a coding issue who has no grasp of the language being used (or the algorithms being created). Other than to gift them with fully working code. I don't have the kind of free time to devote myself that completely to others' projects. Happy to provide my own code as an example, but...
|
|
|
|
|
|
#609 |
|
Junior Member
![]() Posts: 8
Karma: 10
Join Date: Oct 2025
Device: i dont have one
|
Sorry about the misunderstanding. I have not used a forum with software this ancient or with bright white theme since the 90's. So when i searched for old thread for help with development. I did not see the sigil part of the title.
In any case i actually know how to program in java script (embarrassing I know lol) and i'm a technical person i just do not have the time to learn python just to build this.. - it was a test anyway to see if it will work and so far it is kind of working ... I have this output from the plugin and a semi working gui Code:
<span xml:lang="en" title="hello">hi4</span> <span xml:lang="en" title="hello" class="acronym">hi3</span> <span xml:lang="en" title="hello" class="glossary">hi2</span> <span xml:lang="en" title="hello" class="definition">hi</span> <sup><a href="balm.html#ftn3" id="bodyftn3" xml:lang="en" class="noteanchor">[3]</a></sup> <sup><a href="balm.html#ftn1" id="bodyftn1" xml:lang="en" class="noteanchor">[1]</a></sup> <sup><a href="balm.html#ftn2" id="bodyftn2" xml:lang="en" class="noteanchor">[2]</a></sup> <p class="footer">Footnotes</p><div id="ftn1" tabindex="0" xml:lang="en" class="note"><a href="balm.html#bodyftn1" class="noteSymbol">(1)</a> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hello</p></div> <div id="ftn2" tabindex="0" xml:lang="en" class="sidebar"><a href="balm.html#bodyftn2" class="noteSymbol">(2)</a> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hello</p></div> <aside id="ftn3" tabindex="0" xml:lang="en" class="marginnote"><a href="balm.html#bodyftn3" class="noteSymbol">(3)</a> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hello</p></aside> i was not interested in giving me full code just a hint about what is wrong or a code snippet but thanks anyway i will re post in the calibre section |
|
|
|
![]() |
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Loading Plugin in development | Sladd | Development | 6 | 06-17-2014 07:57 PM |
| Question for plugin development gurus | DiapDealer | Plugins | 2 | 02-05-2012 12:33 AM |
| DR800 Plugin development for DR800/DR1000 | yuri_b | iRex Developer's Corner | 0 | 09-18-2010 10:46 AM |
| Device plugin development | reader42 | Plugins | 10 | 03-29-2010 01:39 PM |
| Calibre plugin development - Newbie problems | minstrel | Plugins | 5 | 04-12-2009 01:44 PM |