diff --git a/setup.py b/setup.py index 8e85ddeeea..122008e095 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ # https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/ setup( name=package, - version="0.1.18", + version="0.1.21", python_requires=">=3.8, <3.13", 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", long_description=long_description, diff --git a/tests/__init__.py b/tests/__init__.py index 9c4312eb87..e69de29bb2 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,64 +0,0 @@ -import os, requests, pkg_resources -from shutil import copytree -from pathlib import Path -from packaging import version - - -# go to resource directory -thisFile = os.path.realpath(__file__) -wd = os.path.dirname(thisFile) -if os.getcwd() != wd: - os.chdir(wd) - -ubahome = os.path.expanduser(os.path.join("~", "UniqueBible")) - -if not os.path.isdir(ubahome): - Path(ubahome).mkdir(parents=True, exist_ok=True) -for i in ("audio", "htmlResources", "import", "macros", "marvelData", "music", "notes", "temp", "terminal_history", "terminal_mode", "thirdParty", "video", "webstorage", "workspace"): - targetFolder = os.path.join(ubahome, i) - if not os.path.isdir(targetFolder): - copytree(i, targetFolder, dirs_exist_ok=True) - #copytree(i, os.path.join(ubahome, i), dirs_exist_ok=True) - -# Add folders below for all new folders created after version 0.1.17 -# ... - -# change directory -if os.getcwd() != ubahome: - os.chdir(ubahome) - -# user plugins; create folders for users to place their own plugins -# TODO: user plugins not working for now; will implement later -for i in ("chatGPT", "config", "context", "event", "language", "layout", "menu", "shutdown", "startup", "terminal", "text_editor"): - Path(os.path.join(ubahome, "plugins", i)).mkdir(parents=True, exist_ok=True) - - -def getPackageInstalledVersion(package): - try: - installed_version = pkg_resources.get_distribution(package).version - return version.parse(installed_version) - except pkg_resources.DistributionNotFound: - return None - -def getPackageLatestVersion(package): - try: - response = requests.get(f"https://pypi.org/pypi/{package}/json", timeout=10) - latest_version = response.json()['info']['version'] - return version.parse(latest_version) - except: - return None - -thisPackage = "uniquebible" - -installed_version = getPackageInstalledVersion(thisPackage) -if installed_version is None: - print("Installed version information is not accessible!") -else: - print(f"Installed version: {installed_version}") -latest_version = getPackageLatestVersion(thisPackage) -if latest_version is None: - print("Latest version information is not accessible at the moment!") -elif installed_version is not None: - print(f"Latest version: {latest_version}") - if latest_version > installed_version: - print("Run `pip install --upgrade uniquebible` to upgrade!") \ No newline at end of file diff --git a/uniquebible/__init__.py b/uniquebible/__init__.py index 9c4312eb87..dc406d84d8 100644 --- a/uniquebible/__init__.py +++ b/uniquebible/__init__.py @@ -50,6 +50,8 @@ def getPackageLatestVersion(package): thisPackage = "uniquebible" +print(f"Checking '{thisPackage}' version ...") + installed_version = getPackageInstalledVersion(thisPackage) if installed_version is None: print("Installed version information is not accessible!") diff --git a/uniquebible/util/BibleVerseParser.py b/uniquebible/util/BibleVerseParser.py index 8fbe54376a..e9c2649ce7 100755 --- a/uniquebible/util/BibleVerseParser.py +++ b/uniquebible/util/BibleVerseParser.py @@ -35,14 +35,16 @@ """ import logging import os +import importlib.resources # File "config.py" is essential for running module "config" # Create file "config.py" if it is missing. # The following two lines are written for use of this parser outside UniqueBible.app import pprint -if not os.path.isfile("config.py"): - open("config.py", "w", encoding="utf-8").close() +configFile = os.path.join(str(importlib.resources.files("uniquebible")), "config.py") +if not os.path.isfile(configFile): + open(configFile, "w", encoding="utf-8").close() # import modules, which are ESSENTIAL for running BibleVerseParser import re, glob, sys diff --git a/uniquebible/util/ConfigUtil.py b/uniquebible/util/ConfigUtil.py index 1ff7cd14b7..c44111820f 100644 --- a/uniquebible/util/ConfigUtil.py +++ b/uniquebible/util/ConfigUtil.py @@ -59,8 +59,13 @@ def setup(noQt=None, cli=None, enableCli=None, enableApiServer=None, enableHttpS config.isChromeOS = True if config.thisOS == "Linux" and os.path.exists("/mnt/chromeos/") else False # check current directory - config.ubaUserDir = os.getcwd() + ubaUserDir = os.path.join(os.path.expanduser("~"), "UniqueBible") + config.ubaUserDir = ubaUserDir if os.path.isdir(ubaUserDir) else os.getcwd() config.packageDir = str(importlib.resources.files("uniquebible")) + + userMarvelData = os.path.join(config.ubaUserDir, "marvelData") + if config.marvelData == "marvelData" and os.path.isdir(userMarvelData): + config.marvelData = userMarvelData # check running mode config.runMode = sys.argv[1] if len(sys.argv) > 1 else "" @@ -1683,7 +1688,8 @@ def save(): config.bookSearchString = "" config.noteSearchString = "" #config.instantHighlightString = "" - with open("config.py", "w", encoding="utf-8") as fileObj: + configFile = os.path.join(config.packageDir, "config.py") + with open(configFile, "w", encoding="utf-8") as fileObj: for name in config.help.keys(): try: value = eval(f"config.{name}") diff --git a/uniquebible/util/FileUtil.py b/uniquebible/util/FileUtil.py index 9489b39728..39184a7252 100644 --- a/uniquebible/util/FileUtil.py +++ b/uniquebible/util/FileUtil.py @@ -3,6 +3,7 @@ from itertools import (takewhile, repeat) import platform from urllib.parse import urlsplit, urlunsplit +import importlib.resources class FileUtil: @@ -37,7 +38,8 @@ def createCustomFiles(): # "custom.js" is essential for custom javascript feature. customCssFile = os.path.join("htmlResources", "css", "custom.css") customJsFile = os.path.join("htmlResources", "js", "custom.js") - userFiles = ("config.py", customCssFile, customJsFile) + configFile = os.path.join(str(importlib.resources.files("uniquebible")), "config.py") + userFiles = (configFile, customCssFile, customJsFile) for userFile in userFiles: if not os.path.isfile(userFile): open(userFile, "a", encoding="utf-8").close() diff --git a/uniquebible/util/LocalCliHandler.py b/uniquebible/util/LocalCliHandler.py index 5426c340d1..e46f695c95 100644 --- a/uniquebible/util/LocalCliHandler.py +++ b/uniquebible/util/LocalCliHandler.py @@ -923,6 +923,7 @@ def getContent(self, command, checkDotCommand=True): config.mainB, config.mainC, config.mainV, *_ = references[-1] return plainText except: + #print(traceback.format_exc()) return self.printInvalidOptionEntered() def fineTuneTextForWebBrowserDisplay(self, text=""): @@ -3729,12 +3730,13 @@ def changeconfig(self, terminalCommandOnly=False): return self.printInvalidOptionEntered() def editConfig(self, editor): - if not os.path.isfile("config.py"): + configFile = os.path.join(config.packageDir, "config.py") + if not os.path.isfile(configFile): return "" self.print(self.divider) self.print("Caution! Editing 'config.py' incorrectly may stop UBA from working.") if not editor: - changesMade = self.multilineEditor(filepath="config.py") + changesMade = self.multilineEditor(filepath=configFile) if changesMade: config.saveConfigOnExit = False self.print(self.divider) @@ -3746,8 +3748,8 @@ def editConfig(self, editor): userInput = userInput.lower() if userInput in ("y", "yes"): self.print("reading config content ...") - if os.path.isfile("config.py"): - with open("config.py", "r", encoding="utf-8") as input_file: + if os.path.isfile(configFile): + with open(configFile, "r", encoding="utf-8") as input_file: content = input_file.read() self.print("config is ready for editing ...") self.print("To apply changes, save as 'config.py' and replace the existing 'config.py' when you finish editing.") diff --git a/uniquebible/util/RemoteCliMainWindow.py b/uniquebible/util/RemoteCliMainWindow.py index 3bfbb62b60..a620c45947 100644 --- a/uniquebible/util/RemoteCliMainWindow.py +++ b/uniquebible/util/RemoteCliMainWindow.py @@ -23,7 +23,10 @@ def __init__(self): self.bibleInfo = DatafileLocation.marvelBibles if not config.enableHttpServer: self.setupResourceLists() - config.thisTranslation = LanguageUtil.loadTranslation(config.displayLanguage) + try: + config.thisTranslation = LanguageUtil.loadTranslation(config.displayLanguage) + except: + pass def importModulesInFolder(self, directory="import"): if os.path.isdir(directory): diff --git a/uniquebible/util/TextCommandParser.py b/uniquebible/util/TextCommandParser.py index c2ce4e2911..f025538626 100644 --- a/uniquebible/util/TextCommandParser.py +++ b/uniquebible/util/TextCommandParser.py @@ -7,6 +7,7 @@ from datetime import date from openai import OpenAI +from uniquebible.util.DatafileLocation import DatafileLocation from uniquebible.db.StatisticsWordsSqlite import StatisticsWordsSqlite from uniquebible.util.VlcUtil import VlcUtil from uniquebible.util.exlbl import allLocations, tc_location_names, sc_location_names @@ -1122,7 +1123,7 @@ def getLastCommentaryInfo(self): return ((config.marvelData, "commentaries", "c{0}.commentary".format(config.commentaryText)), self.getCommentaryCloudID(config.commentaryText)) def getMarvelBibles(self): - return self.parent.bibleInfo + return DatafileLocation.marvelBibles def getCommentaryCloudID(self, commentary): cloudIDs = { @@ -1174,7 +1175,8 @@ def isDatabaseInstalled(self, keyword): def databaseNotInstalled(self, keyword): databaseInfo = self.databaseInfo()[keyword] - self.parent.downloadHelper(databaseInfo) + if self.parent is not None: + self.parent.downloadHelper(databaseInfo) return ("", "", {}) # return invalid command @@ -1215,21 +1217,26 @@ def setMainVerse(self, text, bcvTuple): config.mainText = text config.mainB, config.mainC, config.mainV, *_ = bcvTuple config.setMainVerse = True - self.parent.updateMainRefButton() + if self.parent is not None: + self.parent.updateMainRefButton() def setStudyVerse(self, text, bcvTuple): config.studyText = text config.studyB, config.studyC, config.studyV, *_ = bcvTuple - self.parent.updateStudyRefButton() + if self.parent is not None: + self.parent.updateStudyRefButton() config.commentaryB, config.commentaryC, config.commentaryV, *_ = bcvTuple - self.parent.updateCommentaryRefButton() + if self.parent is not None: + self.parent.updateCommentaryRefButton() def setCommentaryVerse(self, text, bcvTuple): config.commentaryText = text config.commentaryB, config.commentaryC, config.commentaryV, *_ = bcvTuple - self.parent.updateCommentaryRefButton() + if self.parent is not None: + self.parent.updateCommentaryRefButton() config.studyB, config.studyC, config.studyV, *_ = bcvTuple - self.parent.updateStudyRefButton() + if self.parent is not None: + self.parent.updateStudyRefButton() # shared functions about bible text def getConfirmedTexts(self, texts, returnEmptyList=False): @@ -1259,7 +1266,8 @@ def isTextInCompareTexts(self, text, compareTexts): def switchCompareView(self): if self.parent.enforceCompareParallelButton: - self.parent.enforceCompareParallelButtonClicked() + if self.parent is not None: + self.parent.enforceCompareParallelButtonClicked() else: config.enforceCompareParallel = not config.enforceCompareParallel @@ -1311,10 +1319,12 @@ def textBibleVerseParser(self, command, text, view, parallel=False): formattedBibles = [f[:-6] for f in os.listdir(formattedBiblesFolder) if os.path.isfile(os.path.join(formattedBiblesFolder, f)) and f.endswith(".bible") and not re.search(r"^[\._]", f)] if text in ("MOB", "MIB", "MTB", "MPB", "MAB", "LXX1i", "LXX2i", "LXX1", "LXX2") and not config.readFormattedBibles: config.readFormattedBibles = True - self.parent.enableParagraphButtonAction(False) + if self.parent is not None: + self.parent.enableParagraphButtonAction(False) elif config.readFormattedBibles and (((text in ("OHGBi", "OHGB") or not text in formattedBibles) and view == "main") or text == "LXX"): config.readFormattedBibles = False - self.parent.enableParagraphButtonAction(False) + if self.parent is not None: + self.parent.enableParagraphButtonAction(False) # Custom font styling for Bible (fontFile, fontSize, css) = Bible(text).getFontInfo() @@ -1514,9 +1524,11 @@ def googleTextToSpeech(self, command, source): return ("", "", {}) else: if config.isGoogleCloudTTSAvailable: - self.parent.saveCloudTTSAudio(text, language) + if self.parent is not None: + self.parent.saveCloudTTSAudio(text, language) else: - self.parent.saveGTTSAudio(text, language) + if self.parent is not None: + self.parent.saveGTTSAudio(text, language) audioFile = self.parent.getGttsFilename() if os.path.isfile(audioFile): @@ -1525,7 +1537,8 @@ def googleTextToSpeech(self, command, source): if config.developer: print(traceback.format_exc()) else: - self.parent.displayMessage(config.thisTranslation["message_fail"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["message_fail"]) # Keep the following codes for future reference # The following method does not work on Windows @@ -1573,7 +1586,8 @@ def getHideOutputSuffix(): command = f"say -r {config.macOSttsSpeed} -v {voice} -f temp/temp.txt" self.cliTtsProcess = subprocess.Popen([command], shell=True, preexec_fn=os.setpgrp, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) else: - self.parent.displayMessage(config.thisTranslation["message_noTtsVoice"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["message_noTtsVoice"]) else: # espeak has no support of "ko", "ko" here is used to correct detection of traditional chinese # It is not recommended to use "ko" to correct language detection for "zh-tw", if qt built-in tts engine is used. @@ -1634,14 +1648,16 @@ def getHideOutputSuffix(): print(f"'{language}' is not found!") print("Available languages:", languages) else: - self.parent.displayMessage(config.thisTranslation["message_noTtsVoice"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["message_noTtsVoice"]) language = config.ttsDefaultLangauge print(f"Language changed to '{language}'") language = isoLang2epeakLang[language][0] # subprocess is used WebtopUtil.run("espeak -s {0} -v {1} '{2}'".format(config.espeakSpeed, language, text)) else: - self.parent.displayMessage(config.thisTranslation["message_noEspeak"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["message_noEspeak"]) else: # use qt built-in tts engine engineNames = QTextToSpeech.availableEngines() @@ -1655,7 +1671,8 @@ def getHideOutputSuffix(): if not (config.ttsDefaultLangauge in languages): config.ttsDefaultLangauge = "en" if not (language in languages): - self.parent.displayMessage(config.thisTranslation["message_noTtsVoice"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["message_noTtsVoice"]) language = config.ttsDefaultLangauge self.qtTtsEngine.setLocale(isoLang2qlocaleLang[language][0]) @@ -1669,11 +1686,13 @@ def getHideOutputSuffix(): self.qtTtsEngine.say(text) else: - self.parent.displayMessage(config.thisTranslation["message_noTtsVoice"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["message_noTtsVoice"]) return ("", "", {}) def stopTtsAudio(self): - self.parent.closeMediaPlayer() + if self.parent is not None: + self.parent.closeMediaPlayer() # if self.cliTtsProcess is not None: # #print(self.cliTtsProcess) # # The following two lines do not work: @@ -1723,7 +1742,8 @@ def mp3Download(self, command, source): else: # version 2: known issue - only works on Linux, but not macOS or Windows multiprocessing.Process(target=self.downloadYouTubeFile, args=(downloadCommand, command, config.musicFolder)).start() - self.parent.displayMessage(config.thisTranslation["downloading"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["downloading"]) """ #self.parent.reloadResources() return ("", "", {}) @@ -1743,7 +1763,8 @@ def mp4Download(self, command, source): else: # version 2: known issue - only works on Linux, but not macOS or Windows multiprocessing.Process(target=self.downloadYouTubeFile, args=(downloadCommand, command, config.videoFolder)).start() - self.parent.displayMessage(config.thisTranslation["downloading"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["downloading"]) """ #self.parent.reloadResources() return ("", "", {}) @@ -1757,7 +1778,8 @@ def youtubeDownload(self, downloadCommand, youTubeLink): else: # version 2: known issue - only works on Linux, but not macOS or Windows multiprocessing.Process(target=self.downloadYouTubeFile, args=(downloadCommand, youTubeLink, config.videoFolder)).start() - self.parent.displayMessage(config.thisTranslation["downloading"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["downloading"]) """ #self.parent.reloadResources() @@ -1779,21 +1801,24 @@ def downloadYouTubeFile(self, downloadCommand, youTubeLink, outputFolder, noFfmp config.youtubeDlIsUpdated = True if self.isFfmpegInstalled() or not noFfmpeg: if config.runMode in ("", "cli", "gui"): - self.parent.workOnDownloadYouTubeFile(downloadCommand, youTubeLink, outputFolder) + if self.parent is not None: + self.parent.workOnDownloadYouTubeFile(downloadCommand, youTubeLink, outputFolder) """ elif platform.system() == "Linux": try: subprocess.run(["cd {2}; {0} {1}".format(downloadCommand, youTubeLink, outputFolder)], shell=True, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) subprocess.Popen([config.open, outputFolder]) except subprocess.CalledProcessError as err: - self.parent.displayMessage(err, title="ERROR:") + if self.parent is not None: + self.parent.displayMessage(err, title="ERROR:") # on Windows elif platform.system() == "Windows": try: os.system(r"cd .\{2}\ & {0} {1}".format(downloadCommand, youTubeLink, outputFolder)) os.system(r"{0} {1}".format(config.open, outputFolder)) except: - self.parent.displayMessage(config.thisTranslation["noSupportedUrlFormat"], title="ERROR:") + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["noSupportedUrlFormat"], title="ERROR:") # on Unix-based system, like macOS else: try: @@ -1803,10 +1828,12 @@ def downloadYouTubeFile(self, downloadCommand, youTubeLink, outputFolder, noFfmp else: os.system(r"{0} {1}".format(config.open, outputFolder)) except: - self.parent.displayMessage(config.thisTranslation["noSupportedUrlFormat"], title="ERROR:") + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["noSupportedUrlFormat"], title="ERROR:") """ else: - self.parent.displayMessage(config.thisTranslation["ffmpegNotFound"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["ffmpegNotFound"]) wikiPage = "https://github.com/eliranwong/UniqueBible/wiki/Install-ffmpeg" if config.enableHttpServer: subprocess.Popen("{0} {1}".format(config.open, wikiPage), shell=True) @@ -1824,7 +1851,8 @@ def keys_ready(): #print(key_press) if key_press.key in (Keys.ControlQ, Keys.ControlZ): print("\nStopping audio playback ...") - self.parent.closeMediaPlayer() + if self.parent is not None: + self.parent.closeMediaPlayer() done = True playback_event.set() @@ -1899,7 +1927,8 @@ def textRead(self, command, source, displayText=False): # old way #self.parent.playAudioBibleFilePlayListPlusDisplayText(allPlayList, allTextList) if displayText else self.parent.playAudioBibleFilePlayList(allPlayList) else: - self.parent.playAudioBibleFilePlayList(allPlayList) + if self.parent is not None: + self.parent.playAudioBibleFilePlayList(allPlayList) return (target, content, {}) else: return self.invalidCommand() @@ -1916,21 +1945,24 @@ def readChapter(self, command, source): playlist = self.parent.playAudioBibleChapterVerseByVerse(text, b, c) content = HtmlGeneratorUtil().getAudioPlayer(playlist) else: - self.parent.playAudioBibleChapterVerseByVerse(text, b, c) + if self.parent is not None: + self.parent.playAudioBibleChapterVerseByVerse(text, b, c) elif len(items) == 4: text, b, c, startVerse = items if config.enableHttpServer: playlist = self.parent.playAudioBibleChapterVerseByVerse(text, b, c, int(startVerse)) content = HtmlGeneratorUtil().getAudioPlayer(playlist) else: - self.parent.playAudioBibleChapterVerseByVerse(text, b, c, int(startVerse)) + if self.parent is not None: + self.parent.playAudioBibleChapterVerseByVerse(text, b, c, int(startVerse)) return (target, content, {}) #except: # return self.invalidCommand() # READVERSE::: def readVerse(self, command, source): - self.parent.closeMediaPlayer() + if self.parent is not None: + self.parent.closeMediaPlayer() text, b, c, v = command.split(".") folder = os.path.join(config.audioFolder, "bibles", text, "default", "{0}_{1}".format(b, c)) filename = "{0}_{1}_{2}_{3}.mp3".format(text, b, c, v) @@ -1947,7 +1979,8 @@ def readVerse(self, command, source): elif config.isVlcAvailable: VlcUtil.playMediaFile(audioFile, config.vlcSpeed, (not config.hideVlcInterfaceReadingSingleVerse)) else: - self.parent.displayMessage(config.thisTranslation["noMediaPlayer"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["noMediaPlayer"]) return ("", "", {}) except: return self.invalidCommand() @@ -1957,7 +1990,8 @@ def readVerse(self, command, source): # READWORD::: def readWord(self, command, source): if not source == 'http': - self.parent.closeMediaPlayer() + if self.parent is not None: + self.parent.closeMediaPlayer() text, b, c, v, wordID = command.split(".") folder = os.path.join(config.audioFolder, "bibles", text, "default", "{0}_{1}".format(b, c)) filename = "{0}_{1}_{2}_{3}_{4}.mp3".format(text, b, c, v, wordID) @@ -1974,7 +2008,8 @@ def readWord(self, command, source): elif config.isVlcAvailable: VlcUtil.playMediaFile(audioFile, config.vlcSpeed, False) else: - self.parent.displayMessage(config.thisTranslation["noMediaPlayer"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["noMediaPlayer"]) return ("", "", {}) except: return self.invalidCommand() @@ -1988,7 +2023,8 @@ def readWord(self, command, source): # READLEXEME::: def readLexeme(self, command, source): - self.parent.closeMediaPlayer() + if self.parent is not None: + self.parent.closeMediaPlayer() text, b, c, v, wordID = command.split(".") folder = os.path.join(config.audioFolder, "bibles", text, "default", "{0}_{1}".format(b, c)) filename = "lex_{0}_{1}_{2}_{3}_{4}.mp3".format(text, b, c, v, wordID) @@ -2005,7 +2041,8 @@ def readLexeme(self, command, source): elif config.isVlcAvailable: VlcUtil.playMediaFile(audioFile, config.vlcSpeed, False) else: - self.parent.displayMessage(config.thisTranslation["noMediaPlayer"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["noMediaPlayer"]) return ("", "", {}) except: return self.invalidCommand() @@ -2022,14 +2059,16 @@ def openMediaPlayer(self, command, source, gui=True): command = command.strip() if not os.path.isfile(command): return self.invalidCommand() - self.parent.closeMediaPlayer() + if self.parent is not None: + self.parent.closeMediaPlayer() try: if config.mainWindow.audioPlayer is not None: config.mainWindow.addToAudioPlayList(command, True) elif config.isVlcAvailable: VlcUtil.playMediaFile(command, config.vlcSpeed, gui) else: - self.parent.displayMessage(config.thisTranslation["noMediaPlayer"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["noMediaPlayer"]) except: WebtopUtil.openFile(command) return ("", "", {}) @@ -2058,7 +2097,8 @@ def readBible(self, command, source): playlist = self.getBiblePlaylist(reference, text, folder) else: playlist.append((text, book, chapter, None, folder)) - self.parent.playBibleMP3Playlist(playlist) + if self.parent is not None: + self.parent.playBibleMP3Playlist(playlist) return ("", "", {}) def getBiblePlaylist(self, command, text, folder): @@ -2218,7 +2258,8 @@ def textBible(self, command, source): return self.textBibleVerseParser(references, text, source) else: databaseInfo = marvelBibles[text] - self.parent.downloadHelper(databaseInfo) + if self.parent is not None: + self.parent.downloadHelper(databaseInfo) return ("", "", {}) else: return self.textBibleVerseParser(references, text, source) @@ -2236,16 +2277,19 @@ def textText(self, command, source): fileItems = marvelBibles[text][0] if os.path.isfile(os.path.join(*fileItems)): if config.enforceCompareParallel: - self.parent.enforceCompareParallelButtonClicked() + if self.parent is not None: + self.parent.enforceCompareParallelButtonClicked() updateViewConfig, viewText, viewReference, *_ = self.getViewConfig(source) return self.textBibleVerseParser(viewReference, texts[0], source) else: databaseInfo = marvelBibles[text] - self.parent.downloadHelper(databaseInfo) + if self.parent is not None: + self.parent.downloadHelper(databaseInfo) return ("", "", {}) else: if config.enforceCompareParallel: - self.parent.enforceCompareParallelButtonClicked() + if self.parent is not None: + self.parent.enforceCompareParallelButtonClicked() updateViewConfig, viewText, viewReference, *_ = self.getViewConfig(source) return self.textBibleVerseParser(viewReference, texts[0], source) @@ -2355,7 +2399,8 @@ def textMain(self, command, source): # STUDY::: def textStudy(self, command, source): if config.openBibleInMainViewOnly and not config.noQt: - self.parent.enableStudyBibleButtonClicked() + if self.parent is not None: + self.parent.enableStudyBibleButtonClicked() return self.textAnotherView(command, source, "study") # STUDYTEXT::: @@ -2373,7 +2418,8 @@ def copyText(self, command, source): else: from qtpy.QtWidgets import QApplication QApplication.clipboard().setText(command) - self.parent.displayMessage(config.thisTranslation["copied"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["copied"]) except: return self.invalidCommand() return ("", "", {}) @@ -2403,7 +2449,8 @@ def translateText(self, command, source): if "zh-TW" in language: language = language.replace("zh-TW", "zh@TW") if language.count("-") != 1: - self.parent.displayMessage(config.thisTranslation["message_invalid"]) + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["message_invalid"]) else: fromLanguage, toLanguage = language.split("-") if "@" in fromLanguage: @@ -2416,7 +2463,8 @@ def translateText(self, command, source): toLanguage = "en" # translate here translation = translator.translate(text, fromLanguage, toLanguage) - self.parent.displayMessage(translation) + if self.parent is not None: + self.parent.displayMessage(translation) if config.autoCopyTranslateResult and not config.noQt: if config.qtLibrary == "pyside6": from PySide6.QtWidgets import QApplication @@ -2424,8 +2472,10 @@ def translateText(self, command, source): from qtpy.QtWidgets import QApplication QApplication.clipboard().setText(translation) else: - self.parent.displayMessage(config.thisTranslation["ibmWatsonNotEnalbed"]) - self.parent.openWebsite("https://github.com/eliranwong/UniqueBible/wiki/IBM-Watson-Language-Translator") + if self.parent is not None: + self.parent.displayMessage(config.thisTranslation["ibmWatsonNotEnalbed"]) + if self.parent is not None: + self.parent.openWebsite("https://github.com/eliranwong/UniqueBible/wiki/IBM-Watson-Language-Translator") return ("", "", {}) # This function below is an old way to process TRANSLATE::: command with goolgetrans @@ -2444,9 +2494,11 @@ def translateText_old(self, command, source): language, text = self.splitCommand(command) # run google translate if language in languages.values(): - self.parent.mainView.translateTextIntoUserLanguage(text, language) + if self.parent is not None: + self.parent.mainView.translateTextIntoUserLanguage(text, language) else: - self.parent.mainView.displayMessage(config.thisTranslation["message_invalid"]) + if self.parent is not None: + self.parent.mainView.displayMessage(config.thisTranslation["message_invalid"]) return ("", "", {}) # called by MAIN::: & STUDY::: @@ -2468,7 +2520,8 @@ def textAnotherView(self, command, source, target): return self.textBibleVerseParser(references, texts[0], target) else: databaseInfo = marvelBibles[text] - self.parent.downloadHelper(databaseInfo) + if self.parent is not None: + self.parent.downloadHelper(databaseInfo) return ("", "", {}) else: return self.textBibleVerseParser(references, texts[0], target) @@ -2574,7 +2627,8 @@ def textParallel(self, command, source): missingMarvelTexts = [text for text in confirmedTexts if text in marvelBibles and not os.path.isfile(os.path.join(*marvelBibles[text][0]))] if missingMarvelTexts: databaseInfo = marvelBibles[missingMarvelTexts[0]] - self.parent.downloadHelper(databaseInfo) + if self.parent is not None: + self.parent.downloadHelper(databaseInfo) return ("", "", {}) else: if source in ('cli'): @@ -2593,7 +2647,8 @@ def textParallel(self, command, source): (fontFile, fontSize, css) = Bible(text).getFontInfo() config.mainCssBibleFontStyle += css config.mainText = mainText - self.parent.setBibleSelection() + if self.parent is not None: + self.parent.setBibleSelection() return ("study" if config.compareOnStudyWindow else "main", "