diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000..f74d7190
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,67 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ main, master, develop, dev, 2.0.0]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ develop, dev, 2.0.0 ]
+ schedule:
+ - cron: '26 13 * * 6'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'python' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+ # Learn more:
+ # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v1
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v1
+
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ https://git.io/JvXDl
+
+ # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/build-and-lint.yml b/.github/workflows/lint-and-build.yml
similarity index 96%
rename from .github/workflows/build-and-lint.yml
rename to .github/workflows/lint-and-build.yml
index ae10b564..775b7925 100644
--- a/.github/workflows/build-and-lint.yml
+++ b/.github/workflows/lint-and-build.yml
@@ -1,17 +1,25 @@
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
-name: Build and lint
+name: Lint and build
on:
push:
branches:
- main
- master
- 2.0.0
+ paths:
+ - '**.py'
+ - '**.pyi'
+ - '**.ui'
pull_request:
branches:
- main
- master
- dev
- dev*
+ paths:
+ - '**.py'
+ - '**.pyi'
+ - '**.ui'
jobs:
Pyright:
runs-on: windows-latest
@@ -54,7 +62,7 @@ jobs:
- run: scripts/compile_resources.bat
- name: Analysing the code with ${{ job.name }}
run: pylint --reports=y --output-format=colorized $(git ls-files '**/*.py*')
- Bandit:
+ Flake8:
runs-on: windows-latest
strategy:
matrix:
@@ -72,8 +80,8 @@ jobs:
pip install -r "scripts/requirements.txt"
- run: scripts/compile_resources.bat
- name: Analysing the code with ${{ job.name }}
- run: bandit -n 1 --severity-level medium --recursive src
- Flake8:
+ run: flake8
+ Bandit:
runs-on: windows-latest
strategy:
matrix:
@@ -91,7 +99,7 @@ jobs:
pip install -r "scripts/requirements.txt"
- run: scripts/compile_resources.bat
- name: Analysing the code with ${{ job.name }}
- run: flake8
+ run: bandit -n 1 --severity-level medium --recursive src
Build:
runs-on: windows-latest
strategy:
diff --git a/.markdownlint.json b/.markdownlint.json
index efb4ef2f..9ecf9f17 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -1,5 +1,6 @@
{
"default": true,
- "MD025": false,
- "MD013": false
+ "MD001": false,
+ "MD013": false,
+ "MD025": false
}
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index d4464eda..49ec5de6 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,3 +1,4 @@
+// Keep in alphabetical order
{
"recommendations": [
"bungcip.better-toml",
@@ -5,11 +6,22 @@
"eamodio.gitlens",
"ms-python.python",
"ms-python.vscode-pylance",
+ "pkief.material-icon-theme",
"shardulm94.trailing-spaces",
"sonarsource.sonarlint-vscode"
],
"unwantedRecommendations": [
+ // VSCode has implemented an optimized version
+ "coenraads.bracket-pair-colorizer",
+ "coenraads.bracket-pair-colorizer-2",
+ // Lots of conflicts
+ "esbenp.prettier-vscode",
+ // Replaced by ESLint
+ "eg2.tslint",
+ "ms-vscode.vscode-typescript-tslint-plugin",
+ // Obsoleted by Pylance
"ms-pyright.pyright",
- "esbenp.prettier-vscode"
+ // The ESLint plugin is sufficient in JS-only projects
+ "sonarsource.sonarlint-vscode",
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5336311a..6252fc0e 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -10,36 +10,11 @@
},
"editor.detectIndentation": false,
"editor.tabSize": 2,
- "[python]": {
- "editor.tabSize": 4,
- "editor.rulers": [
- 72, // PEP8-17 docstrings
- // 79, // PEP8-17 default max
- // 88, // Black default
- 99, // PEP8-17 acceptable max
- 120, // Our hard rule
- ]
- },
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.fixAll.markdownlint": true,
},
- "python.linting.enabled": true,
- "python.linting.pylintEnabled": true,
- "python.linting.pylintCategorySeverity.convention": "Warning",
- "python.linting.pylintCategorySeverity.refactor": "Warning",
- "python.linting.flake8Enabled": true,
- "python.linting.flake8CategorySeverity.E": "Warning",
- // PyRight obsoletes mypy
- "python.linting.mypyEnabled": false,
- // Is already wrapped by Flake8, prospector and pylama
- "python.linting.pycodestyleEnabled": false,
- // Just another wrapper, use Flake8 OR this
- "python.linting.prospectorEnabled": false,
- // Just another wrapper, use Flake8 OR this
- "python.linting.pylamaEnabled": false,
- "python.linting.banditEnabled": true,
"files.insertFinalNewline": true,
"trailing-spaces.includeEmptyLines": true,
"trailing-spaces.trimOnSave": true,
@@ -67,4 +42,41 @@
"**/*.code-search": true,
"typings": true,
},
+ "[python]": {
+ "editor.tabSize": 4,
+ "editor.rulers": [
+ 72, // PEP8-17 docstrings
+ // 79, // PEP8-17 default max
+ // 88, // Black default
+ 99, // PEP8-17 acceptable max
+ 120, // Our hard rule
+ ]
+ },
+ "python.linting.enabled": true,
+ "python.linting.pylintEnabled": true,
+ "python.linting.pylintCategorySeverity.convention": "Warning",
+ "python.linting.pylintCategorySeverity.refactor": "Warning",
+ "python.linting.flake8Enabled": true,
+ "python.linting.flake8CategorySeverity.E": "Warning",
+ // PyRight obsoletes mypy
+ "python.linting.mypyEnabled": false,
+ // Is already wrapped by Flake8, prospector and pylama
+ "python.linting.pycodestyleEnabled": false,
+ // Just another wrapper, use Flake8 OR this
+ "python.linting.prospectorEnabled": false,
+ // Just another wrapper, use Flake8 OR this
+ "python.linting.pylamaEnabled": false,
+ "python.linting.banditEnabled": true,
+ // Copy those over to your user settings
+ "sonarlint.rules": {
+ "python:S1192": {
+ "level": "off"
+ },
+ "python:S3776": {
+ "level": "off"
+ },
+ "python:S107": {
+ "level": "off"
+ },
+ },
}
diff --git a/PyInstaller/hooks/hook-requests.py b/PyInstaller/hooks/hook-requests.py
new file mode 100644
index 00000000..13de4b6b
--- /dev/null
+++ b/PyInstaller/hooks/hook-requests.py
@@ -0,0 +1,4 @@
+from PyInstaller.utils.hooks import collect_data_files
+
+# Get the cacert.pem
+datas = collect_data_files("certifi")
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..ee4fd8d7
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,13 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | :-------: |
+| main | :white_check_mark: |
+| dev* | :white_check_mark: |
+| everything else | WIP branches, security support may be lacking |
+
+## Reporting a Vulnerability
+
+This is a small project, maintained by a few volunteers of the community. Just open up an issue, be clear, explain why it's a vulnerability as well as your recommendations to fix it. Please provide sources if possible.
diff --git a/res/update_checker.ui b/res/update_checker.ui
index 12ffade1..a2f767ae 100644
--- a/res/update_checker.ui
+++ b/res/update_checker.ui
@@ -49,9 +49,9 @@
- 17
+ 20
10
- 281
+ 218
16
@@ -62,13 +62,13 @@
-
+ There is an update available for AutoSplit.
- 17
+ 20
30
91
16
@@ -81,7 +81,7 @@
- 17
+ 20
50
81
16
@@ -94,14 +94,14 @@
- 17
- 76
- 241
+ 20
+ 80
+ 119
16
-
+ Open download page?
@@ -117,7 +117,7 @@
Qt::NoFocus
-
+ Open
@@ -130,7 +130,7 @@
-
+ Later
@@ -162,9 +162,9 @@
- 17
- 100
- 141
+ 20
+ 102
+ 131
20
diff --git a/scripts/build.bat b/scripts/build.bat
index f8a5f6b8..bfc6d7ee 100644
--- a/scripts/build.bat
+++ b/scripts/build.bat
@@ -1,2 +1,2 @@
CALL "%~p0compile_resources.bat"
-pyinstaller -w -F --icon=res\icon.ico "%~p0..\src\AutoSplit.py"
+pyinstaller --windowed --onefile --additional-hooks-dir=Pyinstaller\hooks --icon=res\icon.ico "%~p0..\src\AutoSplit.py"
diff --git a/scripts/lint.ps1 b/scripts/lint.ps1
index 97a72d41..6f66ff32 100644
--- a/scripts/lint.ps1
+++ b/scripts/lint.ps1
@@ -4,8 +4,8 @@ pyright
echo "`nRunning Pylint..."
pylint --score=n --output-format=colorized $(git ls-files '**/*.py*')
-echo "`nRunning Bandit..."
-bandit -f custom --silent --recursive src
-
echo "`nRunning Flake8..."
flake8
+
+echo "`nRunning Bandit..."
+bandit -f custom --silent --recursive src
diff --git a/scripts/requirements.txt b/scripts/requirements.txt
index 30cf1dab..4a438a17 100644
--- a/scripts/requirements.txt
+++ b/scripts/requirements.txt
@@ -10,24 +10,25 @@
# Creating AutoSplit.exe with PyInstaller: .\scripts\build.bat
#
# Dependencies:
+ImageHash
+keyboard
numpy>=1.22.0rc1
opencv-python<=4.5.3.56 # https://github.com/pyinstaller/pyinstaller-hooks-contrib/issues/110
+packaging
+Pillow
PyQt6
PyQt6-tools
PySide6
-Pillow
-ImageHash
-pywin32
-keyboard
-packaging
pyautogui
+pywin32
requests
# Linting and Types
-pywin32-stubs
-types-requests
+bandit
flake8
+flake8-quotes
pylint
-bandit
+pywin32-stubs
+types-requests
#
# Comment this out if you don't want to build AutoSplit.exe:
PyInstaller
diff --git a/src/AutoSplit.py b/src/AutoSplit.py
index 40e81aea..465c9682 100644
--- a/src/AutoSplit.py
+++ b/src/AutoSplit.py
@@ -19,6 +19,7 @@
from copy import copy
from time import time
+import certifi
import cv2
import numpy as np
from PyQt6 import QtCore, QtGui, QtTest
@@ -31,14 +32,14 @@
import split_parser
from AutoControlledWorker import AutoControlledWorker
from capture_windows import capture_region, Rect
-from gen import design
+from compare import checkIfImageHasTransparency, compareImage
+from gen import about, design, update_checker
from hotkeys import send_command, afterSettingHotkey, setSplitHotkey, setResetHotkey, setSkipSplitHotkey, \
setUndoSplitHotkey, setPauseHotkey
-from menu_bar import AboutWidget, VERSION, UpdateCheckerWidget, about, viewHelp, checkForUpdates
+from menu_bar import open_about, VERSION, viewHelp, checkForUpdates, open_update_checker
from screen_region import selectRegion, selectWindow, alignRegion, validateBeforeComparison
+from settings_file import FROZEN
from split_parser import BELOW_FLAG, DUMMY_FLAG, PAUSE_FLAG
-from compare import checkIfImageHasTransparency, compareImage
-
# Resize to these width and height so that FPS performance increases
COMPARISON_RESIZE_WIDTH = 320
@@ -47,9 +48,23 @@
DISPLAY_RESIZE_WIDTH = 240
DISPLAY_RESIZE_HEIGHT = 180
DISPLAY_RESIZE = (DISPLAY_RESIZE_WIDTH, DISPLAY_RESIZE_HEIGHT)
-CREATE_NEW_ISSUE_MESSAGE = \
- "Please create a New Issue at "
-"github.com/Toufool/Auto-Split/issues, describe what happened, and copy & paste the error message below"
+CREATE_NEW_ISSUE_MESSAGE = "Please create a New Issue at " \
+ "github.com/Toufool/Auto-Split/issues, describe what happened, and copy & paste the error message below"
+
+# Needed when compiled, along with the custom hook-requests PyInstaller hook
+os.environ["REQUESTS_CA_BUNDLE"] = certifi.where()
+
+
+def make_excepthook(main_window: AutoSplit):
+ def excepthook(exception_type: type[BaseException], exception: BaseException, _traceback: Optional[TracebackType]):
+ # Catch Keyboard Interrupts for a clean close
+ if exception_type is KeyboardInterrupt or isinstance(exception, KeyboardInterrupt):
+ sys.exit(0)
+ main_window.showErrorSignal.emit(lambda: error_messages.exceptionTraceback(
+ "AutoSplit encountered an unhandled exception and will try to recover, "
+ f"however, there is no guarantee everything will work properly. {CREATE_NEW_ISSUE_MESSAGE}",
+ exception))
+ return excepthook
class AutoSplit(QMainWindow, design.Ui_MainWindow):
@@ -67,6 +82,7 @@ class AutoSplit(QMainWindow, design.Ui_MainWindow):
undoSplitSignal = QtCore.pyqtSignal()
pauseSignal = QtCore.pyqtSignal()
afterSettingHotkeySignal = QtCore.pyqtSignal()
+ updateCheckerWidgetSignal = QtCore.pyqtSignal(str, bool)
# Use this signal when trying to show an error from outside the main thread
showErrorSignal = QtCore.pyqtSignal(FunctionType)
@@ -75,8 +91,9 @@ class AutoSplit(QMainWindow, design.Ui_MainWindow):
timerStartImage = QtCore.QTimer()
# Windows
- aboutWidget: AboutWidget
- updateCheckerWidget: UpdateCheckerWidget
+ AboutWidget: about.Ui_aboutAutoSplitWidget
+ UpdateCheckerWidget: update_checker.Ui_UpdateChecker
+ CheckForUpdatesThread: QtCore.QThread
# Settings
split_image_directory = ""
@@ -149,13 +166,19 @@ class AutoSplit(QMainWindow, design.Ui_MainWindow):
def __init__(self, parent: Optional[QWidget] = None):
super().__init__(parent)
+
+ # Setup global error handling
+ self.showErrorSignal.connect(lambda errorMessageBox: errorMessageBox())
+ # Whithin LiveSplit excepthook needs to use main_window's signals to show errors
+ sys.excepthook = make_excepthook(self)
+
self.setupUi(self)
settings.loadPyQtSettings(self)
# close all processes when closing window
self.actionView_Help.triggered.connect(viewHelp)
- self.actionAbout.triggered.connect(lambda: about(self))
+ self.actionAbout.triggered.connect(lambda: open_about(self))
self.actionCheck_for_Updates.triggered.connect(lambda: checkForUpdates(self))
self.actionSave_Settings.triggered.connect(lambda: settings.saveSettings(self))
self.actionSave_Settings_As.triggered.connect(lambda: settings.saveSettingsAs(self))
@@ -210,6 +233,10 @@ def __init__(self, parent: Optional[QWidget] = None):
self.alignregionButton.clicked.connect(lambda: alignRegion(self))
self.selectwindowButton.clicked.connect(lambda: selectWindow(self))
self.startImageReloadButton.clicked.connect(lambda: self.loadStartImage(True, True))
+ self.actionCheck_for_Updates_on_Open.changed.connect(lambda: settings.set_check_for_updates_on_open(
+ self,
+ self.actionCheck_for_Updates_on_Open.isChecked())
+ )
# update x, y, width, and height when changing the value of these spinbox's are changed
self.xSpinBox.valueChanged.connect(self.updateX)
@@ -221,10 +248,11 @@ def __init__(self, parent: Optional[QWidget] = None):
self.updateCurrentSplitImage.connect(self.updateSplitImageGUI)
self.afterSettingHotkeySignal.connect(lambda: afterSettingHotkey(self))
self.startAutoSplitterSignal.connect(self.autoSplitter)
+ self.updateCheckerWidgetSignal.connect(lambda latest_version, check_on_open:
+ open_update_checker(self, latest_version, check_on_open))
self.resetSignal.connect(self.reset)
self.skipSplitSignal.connect(self.skipSplit)
self.undoSplitSignal.connect(self.undoSplit)
- self.showErrorSignal.connect(lambda errorMessageBox: errorMessageBox())
# live image checkbox
self.liveimageCheckBox.clicked.connect(self.checkLiveImage)
@@ -240,6 +268,12 @@ def __init__(self, parent: Optional[QWidget] = None):
if not self.is_auto_controlled:
settings.loadSettings(self, load_settings_on_open=True)
+ self.show()
+
+ # Needs to be after Ui_MainWindow.show() to be shown overtop
+ if self.actionCheck_for_Updates_on_Open.isChecked():
+ checkForUpdates(self, check_on_open=True)
+
# FUNCTIONS
def getGlobalSettingsValues(self):
@@ -1104,12 +1138,10 @@ def updateSplitImage(self, custom_image_file: str = "", from_start_image: bool =
self.similarity = 0
self.highest_similarity = 0.001
- # exit safely when closing the window
-
def closeEvent(self, a0: Optional[QtGui.QCloseEvent] = None):
- # save global setting values here
- self.setting_check_for_updates_on_open.setValue("check_for_updates_on_open",
- self.actionCheck_for_Updates_on_Open.isChecked())
+ """
+ Exit safely when closing the window
+ """
def exitProgram():
if a0 is not None:
@@ -1154,28 +1186,26 @@ def exitProgram():
def main():
+ # Call to QApplication outside the try-except so we can show error messages
app = QApplication(sys.argv)
try:
app.setWindowIcon(QtGui.QIcon(":/resources/icon.ico"))
- main_window = AutoSplit()
- main_window.show()
- # Needs to be after main_window.show() to be shown over
- if main_window.actionCheck_for_Updates_on_Open.isChecked():
- checkForUpdates(main_window, check_for_updates_on_open=True)
+ AutoSplit()
- # Kickoff the event loop every so often so we can handle KeyboardInterrupt (^C)
- timer = QtCore.QTimer()
- timer.timeout.connect(lambda: None)
- timer.start(500)
+ if not FROZEN:
+ # Kickoff the event loop every so often so we can handle KeyboardInterrupt (^C)
+ timer = QtCore.QTimer()
+ timer.timeout.connect(lambda: None)
+ timer.start(500)
exit_code = app.exec()
- except Exception as exception: # pylint: disable=broad-except
+ except Exception as exception: # pylint: disable=broad-except # We really want to catch everything here
+ message = f"AutoSplit encountered an unrecoverable exception and will now close. {CREATE_NEW_ISSUE_MESSAGE}"
# Print error to console if not running in executable
- if getattr(sys, "frozen", False):
- error_messages.exceptionTraceback(
- f"AutoSplit encountered an unrecoverable exception and will now close. {CREATE_NEW_ISSUE_MESSAGE}",
- exception)
+ if FROZEN:
+ error_messages.exceptionTraceback(message, exception)
else:
+ print(message)
traceback.print_exception(type(exception), exception, exception.__traceback__)
sys.exit(1)
@@ -1185,16 +1215,5 @@ def main():
sys.exit(exit_code)
-def excepthook(exceptionType: type[BaseException], exception: BaseException, _traceback: Optional[TracebackType]):
- # Catch Keyboard Interrupts for a clean close
- if exceptionType is KeyboardInterrupt:
- sys.exit(0)
- error_messages.exceptionTraceback(
- "AutoSplit encountered an unhandled exception and will try to recover, "
- f"however, there is no guarantee everything will work properly. {CREATE_NEW_ISSUE_MESSAGE}",
- exception)
-
-
if __name__ == "__main__":
- sys.excepthook = excepthook
main()
diff --git a/src/gen/design.pyi b/src/gen/design.pyi
index 6d951853..a7a38ee1 100644
--- a/src/gen/design.pyi
+++ b/src/gen/design.pyi
@@ -1,6 +1,9 @@
+from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QMainWindow
class Ui_MainWindow():
+ actionCheck_for_Updates_on_Open: QAction
+
def setupUi(self, MainWindow: QMainWindow) -> None:
...
diff --git a/src/menu_bar.py b/src/menu_bar.py
index cf67f09d..15e6e82d 100644
--- a/src/menu_bar.py
+++ b/src/menu_bar.py
@@ -4,18 +4,24 @@
from AutoSplit import AutoSplit
import os
+
import requests
-from PyQt6 import QtWidgets
+from simplejson.errors import JSONDecodeError
from packaging import version
-from gen import about as about_, resources_rc, update_checker # noqa: F401
+from PyQt6 import QtWidgets
+from PyQt6.QtCore import QThread
+from requests.exceptions import RequestException
+
import error_messages
+import settings_file as settings
+from gen import about, design, resources_rc, update_checker # noqa: F401
# AutoSplit Version number
VERSION = "1.6.1"
# About Window
-class AboutWidget(QtWidgets.QWidget, about_.Ui_aboutAutoSplitWidget):
+class __AboutWidget(QtWidgets.QWidget, about.Ui_aboutAutoSplitWidget):
def __init__(self):
super().__init__()
self.setupUi(self)
@@ -25,57 +31,64 @@ def __init__(self):
self.show()
-class UpdateCheckerWidget(QtWidgets.QWidget, update_checker.Ui_UpdateChecker):
- def __init__(self, latest_version: str, autosplit: AutoSplit, check_for_updates_on_open: bool = False):
+def open_about(autosplit: AutoSplit):
+ autosplit.AboutWidget = __AboutWidget()
+
+
+class __UpdateCheckerWidget(QtWidgets.QWidget, update_checker.Ui_UpdateChecker):
+ def __init__(self, latest_version: str, design_window: design.Ui_MainWindow, check_on_open: bool = False):
super().__init__()
self.setupUi(self)
self.labelCurrentVersionNumber.setText(VERSION)
self.labelLatestVersionNumber.setText(latest_version)
self.pushButtonLeft.clicked.connect(self.openUpdate)
- self.pushButtonRight.clicked.connect(self.closeWindow)
- self.autosplit = autosplit
+ self.checkBoxDoNotAskMeAgain.stateChanged.connect(self.doNotAskMeAgainStateChanged)
+ self.design_window = design_window
if version.parse(latest_version) > version.parse(VERSION):
- self.labelUpdateStatus.setText("There is an update available for AutoSplit.")
- self.labelGoToDownload.setText("Open download page?")
- self.pushButtonLeft.setVisible(True)
- self.pushButtonLeft.setText("Open")
- self.pushButtonRight.setText("Later")
- if not check_for_updates_on_open:
- self.checkBoxDoNotAskMeAgain.setVisible(False)
+ self.checkBoxDoNotAskMeAgain.setVisible(check_on_open)
self.show()
- elif not check_for_updates_on_open:
+ elif not check_on_open:
self.labelUpdateStatus.setText("You are on the latest AutoSplit version.")
+ self.labelGoToDownload.setVisible(False)
self.pushButtonLeft.setVisible(False)
self.pushButtonRight.setText("OK")
self.checkBoxDoNotAskMeAgain.setVisible(False)
self.show()
def openUpdate(self):
- if self.checkBoxDoNotAskMeAgain.isChecked():
- self.autosplit.actionCheck_for_Updates_on_Open.setChecked(False)
os.system('start "" https://github.com/Toufool/Auto-Split/releases/latest')
self.close()
- def closeWindow(self):
- if self.checkBoxDoNotAskMeAgain.isChecked():
- self.autosplit.actionCheck_for_Updates_on_Open.setChecked(False)
- self.close()
+ def doNotAskMeAgainStateChanged(self):
+ settings.set_check_for_updates_on_open(
+ self.design_window,
+ self.checkBoxDoNotAskMeAgain.isChecked())
+
+
+def open_update_checker(autosplit: AutoSplit, latest_version: str, check_on_open: bool):
+ autosplit.UpdateCheckerWidget = __UpdateCheckerWidget(latest_version, autosplit, check_on_open)
def viewHelp():
os.system('start "" https://github.com/Toufool/Auto-Split#tutorial')
-def about(autosplit: AutoSplit):
- autosplit.aboutWidget = AboutWidget()
+class __CheckForUpdatesThread(QThread):
+ def __init__(self, autosplit: AutoSplit, check_on_open: bool):
+ super().__init__()
+ self.autosplit = autosplit
+ self.check_on_open = check_on_open
+
+ def run(self):
+ try:
+ response = requests.get("https://api.github.com/repos/Toufool/Auto-Split/releases/latest")
+ latest_version = response.json()["name"].split("v")[1]
+ self.autosplit.updateCheckerWidgetSignal.emit(latest_version, self.check_on_open)
+ except (RequestException, KeyError, JSONDecodeError):
+ if not self.check_on_open:
+ self.autosplit.showErrorSignal.emit(error_messages.checkForUpdatesError)
-def checkForUpdates(autosplit: AutoSplit, check_for_updates_on_open: bool = False):
- try:
- response = requests.get("https://api.github.com/repos/Toufool/Auto-Split/releases/latest")
- latest_version = response.json()["name"].split("v")[1]
- except requests.exceptions.RequestException:
- if not check_for_updates_on_open:
- error_messages.checkForUpdatesError()
- else:
- autosplit.updateCheckerWidget = UpdateCheckerWidget(latest_version, autosplit, check_for_updates_on_open)
+def checkForUpdates(autosplit: AutoSplit, check_on_open: bool = False):
+ autosplit.CheckForUpdatesThread = __CheckForUpdatesThread(autosplit, check_on_open)
+ autosplit.CheckForUpdatesThread.start()
diff --git a/src/settings_file.py b/src/settings_file.py
index 55636563..9a30cb37 100644
--- a/src/settings_file.py
+++ b/src/settings_file.py
@@ -8,20 +8,24 @@
import pickle
import keyboard # https://github.com/boppreh/keyboard/issues/505
from win32 import win32gui
-from PyQt6 import QtWidgets
+from PyQt6 import QtCore, QtWidgets
import error_messages
+from gen import design
# TODO with settings refactoring
from hotkeys import _hotkey_action # type: ignore
+# Keyword "frozen" is for setting basedir while in onefile mode in pyinstaller
+FROZEN = hasattr(sys, "frozen")
+
# Get the directory of either AutoSplit.exe or AutoSplit.py
-auto_split_directory = os.path.dirname(sys.executable if getattr(sys, "frozen", False) else os.path.abspath(__file__))
+auto_split_directory = os.path.dirname(sys.executable if FROZEN else os.path.abspath(__file__))
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module: str, name: str):
- raise pickle.UnpicklingError("'%s.%s' is forbidden" % (module, name))
+ raise pickle.UnpicklingError(f"'{module}.{name}' is forbidden")
def loadPyQtSettings(autosplit: AutoSplit):
@@ -319,3 +323,26 @@ def loadSettings(autosplit: AutoSplit, load_settings_on_open: bool = False, load
autosplit.last_successfully_loaded_settings_file_path = autosplit.load_settings_file_path
autosplit.checkLiveImage()
autosplit.loadStartImage()
+
+
+def load_check_for_updates_on_open(designWindow: design.Ui_MainWindow):
+ """
+ Retrieve the "Check For Updates On Open" QSettings and set the checkbox state
+ These are only global settings values. They are not *pkl settings values.
+ """
+
+ value = QtCore \
+ .QSettings("AutoSplit", "Check For Updates On Open") \
+ .value("check_for_updates_on_open", True, type=bool)
+ designWindow.actionCheck_for_Updates_on_Open.setChecked(value)
+
+
+def set_check_for_updates_on_open(designWindow: design.Ui_MainWindow, value: bool):
+ """
+ Sets the "Check For Updates On Open" QSettings value and the checkbox state
+ """
+
+ designWindow.actionCheck_for_Updates_on_Open.setChecked(value)
+ QtCore \
+ .QSettings("AutoSplit", "Check For Updates On Open") \
+ .setValue("check_for_updates_on_open", value)
diff --git a/typings/simplejson/errors.pyi b/typings/simplejson/errors.pyi
new file mode 100644
index 00000000..d98b7495
--- /dev/null
+++ b/typings/simplejson/errors.pyi
@@ -0,0 +1,34 @@
+"""
+This type stub file was generated by pyright.
+"""
+
+"""Error classes used by simplejson
+"""
+__all__ = ['JSONDecodeError']
+def linecol(doc, pos): # -> tuple[Unknown, Unknown]:
+ ...
+
+def errmsg(msg, doc, pos, end=...): # -> str:
+ ...
+
+class JSONDecodeError(ValueError):
+ """Subclass of ValueError with the following additional properties:
+
+ msg: The unformatted error message
+ doc: The JSON document being parsed
+ pos: The start index of doc where parsing failed
+ end: The end index of doc where parsing failed (may be None)
+ lineno: The line corresponding to pos
+ colno: The column corresponding to pos
+ endlineno: The line corresponding to end (may be None)
+ endcolno: The column corresponding to end (may be None)
+
+ """
+ def __init__(self, msg, doc, pos, end=...) -> None:
+ ...
+
+ def __reduce__(self): # -> tuple[Type[Self@JSONDecodeError], tuple[Unknown, Unknown, Unknown, Unknown]]:
+ ...
+
+
+