Skip to content

Commit 91afa9f

Browse files
committed
support user plugins
1 parent f5b9603 commit 91afa9f

14 files changed

+116
-73
lines changed

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
# https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/
4848
setup(
4949
name=package,
50-
version="0.1.36",
50+
version="0.1.37",
5151
python_requires=">=3.8, <3.13",
5252
description=f"UniqueBible App is a cross-platform & offline bible application, integrated with high-quality resources and unique features. Developers: Eliran Wong and Oliver Tseng",
5353
long_description=long_description,

uniquebible/gui/AlephMainWindow.py

+8
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,14 @@ def create_menu(self):
507507
else:
508508
addMenuItem(menu, plugin, self, lambda plugin=plugin: self.runPlugin(plugin), translation=False)
509509
menu.addSeparator()
510+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.ubaUserDir, "plugins", "menu"), "py"):
511+
if not plugin in config.excludeMenuPlugins:
512+
if "_" in plugin:
513+
feature, shortcut = plugin.split("_", 1)
514+
addMenuItem(menu, feature, self, lambda plugin=plugin: self.runPlugin(plugin), shortcut=shortcut, translation=False)
515+
else:
516+
addMenuItem(menu, plugin, self, lambda plugin=plugin: self.runPlugin(plugin), translation=False)
517+
menu.addSeparator()
510518
addMenuItem(menu, "enableIndividualPlugins", self, self.enableIndividualPluginsWindow)
511519

512520
about_menu = self.menuBar().addMenu("{0}{1}".format(config.menuUnderline, config.thisTranslation["menu_about"]))

uniquebible/gui/EnableIndividualPlugins.py

+28-24
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,13 @@ def setupUI(self):
5252
dataView1.setEditTriggers(QAbstractItemView.NoEditTriggers)
5353
dataViewModel1 = QStandardItemModel(dataView1)
5454
dataView1.setModel(dataViewModel1)
55-
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "startup"), "py"):
56-
item = QStandardItem(plugin)
57-
item.setToolTip(plugin)
58-
item.setCheckable(True)
59-
item.setCheckState(Qt.CheckState.Unchecked if plugin in config.excludeStartupPlugins else Qt.CheckState.Checked)
60-
dataViewModel1.appendRow(item)
55+
for ff in (config.packageDir, config.ubaUserDir):
56+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "startup"), "py"):
57+
item = QStandardItem(plugin)
58+
item.setToolTip(plugin)
59+
item.setCheckable(True)
60+
item.setCheckState(Qt.CheckState.Unchecked if plugin in config.excludeStartupPlugins else Qt.CheckState.Checked)
61+
dataViewModel1.appendRow(item)
6162
dataViewModel1.itemChanged.connect(self.itemChanged1)
6263
layout.addWidget(dataView1)
6364
subLayout.addLayout(layout)
@@ -68,12 +69,13 @@ def setupUI(self):
6869
dataView2.setEditTriggers(QAbstractItemView.NoEditTriggers)
6970
dataViewModel2 = QStandardItemModel(dataView2)
7071
dataView2.setModel(dataViewModel2)
71-
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "menu"), "py"):
72-
item = QStandardItem(plugin)
73-
item.setToolTip(plugin)
74-
item.setCheckable(True)
75-
item.setCheckState(Qt.CheckState.Unchecked if plugin in config.excludeMenuPlugins else Qt.CheckState.Checked)
76-
dataViewModel2.appendRow(item)
72+
for ff in (config.packageDir, config.ubaUserDir):
73+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "menu"), "py"):
74+
item = QStandardItem(plugin)
75+
item.setToolTip(plugin)
76+
item.setCheckable(True)
77+
item.setCheckState(Qt.CheckState.Unchecked if plugin in config.excludeMenuPlugins else Qt.CheckState.Checked)
78+
dataViewModel2.appendRow(item)
7779
dataViewModel2.itemChanged.connect(self.itemChanged2)
7880
layout.addWidget(dataView2)
7981
subLayout.addLayout(layout)
@@ -84,12 +86,13 @@ def setupUI(self):
8486
dataView3.setEditTriggers(QAbstractItemView.NoEditTriggers)
8587
dataViewModel3 = QStandardItemModel(dataView3)
8688
dataView3.setModel(dataViewModel3)
87-
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "context"), "py"):
88-
item = QStandardItem(plugin)
89-
item.setToolTip(plugin)
90-
item.setCheckable(True)
91-
item.setCheckState(Qt.CheckState.Unchecked if plugin in config.excludeContextPlugins else Qt.CheckState.Checked)
92-
dataViewModel3.appendRow(item)
89+
for ff in (config.packageDir, config.ubaUserDir):
90+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "context"), "py"):
91+
item = QStandardItem(plugin)
92+
item.setToolTip(plugin)
93+
item.setCheckable(True)
94+
item.setCheckState(Qt.CheckState.Unchecked if plugin in config.excludeContextPlugins else Qt.CheckState.Checked)
95+
dataViewModel3.appendRow(item)
9396
dataViewModel3.itemChanged.connect(self.itemChanged3)
9497
layout.addWidget(dataView3)
9598
subLayout.addLayout(layout)
@@ -100,12 +103,13 @@ def setupUI(self):
100103
dataView4.setEditTriggers(QAbstractItemView.NoEditTriggers)
101104
dataViewModel4 = QStandardItemModel(dataView4)
102105
dataView4.setModel(dataViewModel4)
103-
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "shutdown"), "py"):
104-
item = QStandardItem(plugin)
105-
item.setToolTip(plugin)
106-
item.setCheckable(True)
107-
item.setCheckState(Qt.CheckState.Unchecked if plugin in config.excludeShutdownPlugins else Qt.CheckState.Checked)
108-
dataViewModel4.appendRow(item)
106+
for ff in (config.packageDir, config.ubaUserDir):
107+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "shutdown"), "py"):
108+
item = QStandardItem(plugin)
109+
item.setToolTip(plugin)
110+
item.setCheckable(True)
111+
item.setCheckState(Qt.CheckState.Unchecked if plugin in config.excludeShutdownPlugins else Qt.CheckState.Checked)
112+
dataViewModel4.appendRow(item)
109113
dataViewModel4.itemChanged.connect(self.itemChanged4)
110114
layout.addWidget(dataView4)
111115
subLayout.addLayout(layout)

uniquebible/gui/MainWindow.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5372,7 +5372,7 @@ def addMenuPluginButton(self, plugin, feature, icon, toolbar, translation=True):
53725372
self.addMaterialIconButton(feature, icon, partial(self.runPlugin, plugin), toolbar, translation=translation)
53735373

53745374
def isMenuPlugin(self, plugin):
5375-
return os.path.isfile(os.path.join(config.packageDir, "plugins", "menu", "{0}.py".format(plugin)))
5375+
return os.path.isfile(os.path.join(config.packageDir, "plugins", "menu", "{0}.py".format(plugin))) or os.path.isfile(os.path.join(config.ubaUserDir, "plugins", "menu", "{0}.py".format(plugin)))
53765376

53775377
def runPlugin(self, fileName, _=None):
53785378
self.crossPlatform.runPlugin(fileName)

uniquebible/gui/MaterialMainWindow.py

+9
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,15 @@ def setSubMenuVlcSpeed():
785785
# For both PySide2 and PyQt5
786786
addMenuItem(menu, plugin, self, partial(self.runPlugin, plugin), translation=False)
787787
menu.addSeparator()
788+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.ubaUserDir, "plugins", "menu"), "py"):
789+
if not plugin in config.excludeMenuPlugins:
790+
if "_" in plugin:
791+
feature, shortcut = plugin.split("_", 1)
792+
feature = "{0} | {1}".format(feature, shortcut)
793+
addMenuItem(menu, feature, self, partial(self.runPlugin, plugin), shortcut=shortcut, translation=False)
794+
else:
795+
addMenuItem(menu, plugin, self, partial(self.runPlugin, plugin), translation=False)
796+
menu.addSeparator()
788797
addMenuItem(menu, "enableIndividualPlugins", self, self.enableIndividualPluginsWindow)
789798

790799
# information

uniquebible/gui/SystemTrayMenu.py

+16-14
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@
2323
# Menu plugins
2424
if config.enablePlugins:
2525
subMenu = QMenu()
26-
for index, plugin in enumerate(FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "menu"), "py")):
27-
if not plugin in config.excludeMenuPlugins:
28-
feature, *_ = plugin.split("_", 1)
29-
exec("menuPlugin{0} = QAction(feature)".format(index))
30-
#exec("menuPlugin{0}.triggered.connect(config.mainWindow.showFromTray)".format(index))
31-
exec("menuPlugin{0}.triggered.connect(partial(config.mainWindow.runPlugin, plugin))".format(index))
32-
exec("subMenu.addAction(menuPlugin{0})".format(index))
26+
for ff in (config.packageDir, config.ubaUserDir):
27+
for index, plugin in enumerate(FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "menu"), "py")):
28+
if not plugin in config.excludeMenuPlugins:
29+
feature, *_ = plugin.split("_", 1)
30+
exec("menuPlugin{0} = QAction(feature)".format(index))
31+
#exec("menuPlugin{0}.triggered.connect(config.mainWindow.showFromTray)".format(index))
32+
exec("menuPlugin{0}.triggered.connect(partial(config.mainWindow.runPlugin, plugin))".format(index))
33+
exec("subMenu.addAction(menuPlugin{0})".format(index))
3334
menuPlugins = QAction(config.thisTranslation["menu_plugins"])
3435
menuPlugins.setMenu(subMenu)
3536
trayMenu.addAction(menuPlugins)
@@ -154,13 +155,14 @@
154155
# Context plugins
155156
if config.enablePlugins:
156157
subMenu = QMenu()
157-
for index, plugin in enumerate(FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "context"), "py")):
158-
if not plugin in config.excludeContextPlugins:
159-
feature, *_ = plugin.split("_", 1)
160-
exec("contextPlugin{0} = QAction(feature)".format(index))
161-
#exec("contextPlugin{0}.triggered.connect(config.mainWindow.showFromTray)".format(index))
162-
exec("contextPlugin{0}.triggered.connect(partial(config.mainWindow.runContextPluginOnClipboardContent, plugin))".format(index))
163-
exec("subMenu.addAction(contextPlugin{0})".format(index))
158+
for ff in (config.packageDir, config.ubaUserDir):
159+
for index, plugin in enumerate(FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "context"), "py")):
160+
if not plugin in config.excludeContextPlugins:
161+
feature, *_ = plugin.split("_", 1)
162+
exec("contextPlugin{0} = QAction(feature)".format(index))
163+
#exec("contextPlugin{0}.triggered.connect(config.mainWindow.showFromTray)".format(index))
164+
exec("contextPlugin{0}.triggered.connect(partial(config.mainWindow.runContextPluginOnClipboardContent, plugin))".format(index))
165+
exec("subMenu.addAction(contextPlugin{0})".format(index))
164166
contextPlugins = QAction(config.thisTranslation["runContextPluginOnClipboardContent"])
165167
contextPlugins.setMenu(subMenu)
166168
trayMenu.addAction(contextPlugins)

uniquebible/gui/WebEngineView.py

+19-15
Original file line numberDiff line numberDiff line change
@@ -940,20 +940,20 @@ def addMenuActions(self):
940940
self.addAction(separator)
941941

942942
subMenu = QMenu()
943-
944-
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "context"), "py"):
945-
if not plugin in config.excludeContextPlugins:
946-
action = QAction(self)
947-
if "_" in plugin:
948-
feature, shortcut = plugin.split("_", 1)
949-
action.setText("{0} | {1}".format(feature, shortcut) if shortcut else feature)
950-
# The following line does not work
951-
#action.setShortcut(QKeySequence(shortcut))
952-
self.parent.parent.addContextPluginShortcut(plugin, shortcut)
953-
else:
954-
action.setText(plugin)
955-
action.triggered.connect(partial(self.runPlugin, plugin))
956-
subMenu.addAction(action)
943+
for ff in (config.packageDir, config.ubaUserDir):
944+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "context"), "py"):
945+
if not plugin in config.excludeContextPlugins:
946+
action = QAction(self)
947+
if "_" in plugin:
948+
feature, shortcut = plugin.split("_", 1)
949+
action.setText("{0} | {1}".format(feature, shortcut) if shortcut else feature)
950+
# The following line does not work
951+
#action.setShortcut(QKeySequence(shortcut))
952+
self.parent.parent.addContextPluginShortcut(plugin, shortcut)
953+
else:
954+
action.setText(plugin)
955+
action.triggered.connect(partial(self.runPlugin, plugin))
956+
subMenu.addAction(action)
957957

958958
separator = QAction(self)
959959
separator.setSeparator(True)
@@ -1008,7 +1008,11 @@ def runPlugin(self, fileName, selectedText=None, activeSelection=False):
10081008
config.contextSource = self
10091009
config.pluginContext = selectedText
10101010
script = os.path.join(config.packageDir, "plugins", "context", "{0}.py".format(fileName))
1011-
self.parent.parent.execPythonFile(script)
1011+
if os.path.isfile(script):
1012+
self.parent.parent.execPythonFile(script)
1013+
script = os.path.join(config.ubaUserDir, "plugins", "context", "{0}.py".format(fileName))
1014+
if os.path.isfile(script):
1015+
self.parent.parent.execPythonFile(script)
10121016
config.pluginContext = ""
10131017
config.contextSource = None
10141018

uniquebible/latest_changes.txt

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
PIP package:
22

3+
0.1.37
4+
5+
* support user plugins, stored in ~/UniqueBible/plugins
6+
37
0.1.36
48

59
* improved commentary output for terminal and stream mode

uniquebible/startup/guiQt.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,11 @@ def exitApplication():
109109
config.mainWindow.closeMediaPlayer()
110110
# Run shutdown plugins
111111
if config.enablePlugins:
112-
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "shutdown"), "py"):
113-
if not plugin in config.excludeShutdownPlugins:
114-
script = os.path.join(config.packageDir, "plugins", "shutdown", "{0}.py".format(plugin))
115-
config.mainWindow.execPythonFile(script)
112+
for ff in (config.packageDir, config.ubaUserDir):
113+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "shutdown"), "py"):
114+
if not plugin in config.excludeShutdownPlugins:
115+
script = os.path.join(ff, "plugins", "shutdown", "{0}.py".format(plugin))
116+
config.mainWindow.execPythonFile(script)
116117
ConfigUtil.save()
117118
NoteService.close()
118119
if (config.runMode == "docker") and config.restartUBA:

uniquebible/startup/share.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ def cleanupTempFiles():
1212
# Run startup plugins
1313
def runStartupPlugins():
1414
if config.enablePlugins:
15-
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "startup"), "py"):
16-
if not plugin in config.excludeStartupPlugins:
17-
script = os.path.join(config.packageDir, "plugins", "startup", "{0}.py".format(plugin))
18-
config.mainWindow.execPythonFile(script)
15+
for ff in (config.packageDir, config.ubaUserDir):
16+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "startup"), "py"):
17+
if not plugin in config.excludeStartupPlugins:
18+
script = os.path.join(ff, "plugins", "startup", "{0}.py".format(plugin))
19+
config.mainWindow.execPythonFile(script)
1920

2021
def printContentOnConsole(text):
2122
if not "html-text" in sys.modules:

uniquebible/util/CrossPlatform.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,11 @@ def getHistory(self, view):
206206

207207
def runPlugin(self, fileName):
208208
script = os.path.join(config.packageDir, "plugins", "menu", "{0}.py".format(fileName))
209-
self.execPythonFile(script)
209+
if os.path.isfile(script):
210+
self.execPythonFile(script)
211+
script = os.path.join(config.ubaUserDir, "plugins", "menu", "{0}.py".format(fileName))
212+
if os.path.isfile(script):
213+
self.execPythonFile(script)
210214

211215
def execPythonFile(self, script):
212216
if config.developer:

uniquebible/util/LocalCliHandler.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -777,17 +777,22 @@ def execFile(self):
777777
return ""
778778

779779
def plugins(self, default="", accept_default=False):
780-
availablePlugins = FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "terminal"), "py")
780+
availablePlugins = FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "terminal"), "py") + FileUtil.fileNamesWithoutExtension(os.path.join(config.ubaUserDir, "plugins", "terminal"), "py")
781781
if default and accept_default:
782782
userInput = self.simplePrompt(default=default, accept_default=accept_default)
783783
else:
784784
userInput = self.dialogs.getValidOptions(options=availablePlugins, title="Plugins", default=default)
785785
if not userInput or userInput.lower() == config.terminal_cancel_action:
786786
return self.cancelAction()
787787
try:
788-
#filepath = os.path.join(config.packageDir, "plugins", "terminal", f"{availablePlugins[int(userInput)]}.py")
789-
filepath = os.path.join(config.packageDir, "plugins", "terminal", f"{userInput}.py")
790-
self.execPythonFile(filepath)
788+
filepath1 = os.path.join(config.packageDir, "plugins", "terminal", f"{userInput}.py")
789+
filepath2 = os.path.join(config.ubaUserDir, "plugins", "terminal", f"{userInput}.py")
790+
if os.path.isfile(filepath1):
791+
self.execPythonFile(filepath1)
792+
elif os.path.isfile(filepath2):
793+
self.execPythonFile(filepath2)
794+
else:
795+
return self.printInvalidOptionEntered()
791796
return ""
792797
except:
793798
return self.printInvalidOptionEntered()

uniquebible/util/RemoteHttpHandler.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,11 @@ def runStartupPlugins(self):
236236
config.bibleWindowContentTransformers = []
237237
config.customCommandShortcuts = {}
238238
if config.enablePlugins:
239-
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(config.packageDir, "plugins", "startup"), "py"):
240-
if not plugin in config.excludeStartupPlugins:
241-
script = os.path.join(config.packageDir, "plugins", "startup", "{0}.py".format(plugin))
242-
config.mainWindow.execPythonFile(script)
239+
for ff in (config.packageDir, config.ubaUserDir):
240+
for plugin in FileUtil.fileNamesWithoutExtension(os.path.join(ff, "plugins", "startup"), "py"):
241+
if not plugin in config.excludeStartupPlugins:
242+
script = os.path.join(ff, "plugins", "startup", "{0}.py".format(plugin))
243+
config.mainWindow.execPythonFile(script)
243244

244245
def execPythonFile(self, script):
245246
self.textCommandParser.parent.execPythonFile(script)

uniquebible/util/terminal_text_editor.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ def plugins(self):
600600
if not userInput or userInput.lower() == config.terminal_cancel_action:
601601
return self.parent.cancelAction()
602602
try:
603-
filepath = os.path.join(config.packageDir, "plugins", "text_editor", f"{userInput}.py")
603+
filepath = os.path.join(pluginDir, f"{userInput}.py")
604604
self.parent.execPythonFile(filepath)
605605
return ""
606606
except:

0 commit comments

Comments
 (0)