Compare commits

...

14 Commits

Author SHA1 Message Date
Vxrtrauter 43cbfe056c feat: remove ugly spinner label and related functionality from search process 2026-03-08 13:19:39 +01:00
Vxrtrauter 12df32f72a feat: remove unused install path detection function and clean up update process 2026-03-08 13:15:51 +01:00
Vxrtrauter 9e0ee2a36d trigger workflow 2026-03-08 02:16:23 +01:00
Vxrtrauter 5b9bdd2a2a feat: update download process to use temporary installer path and improve silent installation 2026-03-08 02:16:16 +01:00
Vxrtrauter ff0e1a0798 trigger workflow" 2026-03-08 01:55:59 +01:00
Vxrtrauter 891c5a86c1 feat: enhance update process with progress dialog and install path detection 2026-03-08 01:55:23 +01:00
KeksNino a5190f151c fix: temporarily remove subprocess.Popen to stop opening softwaremanager.exe before update finished 2026-03-08 00:41:46 +01:00
Vxrtrauter 95f6640212 Merge branch 'main' of https://github.com/KeksPirates/SoftwareManager 2026-03-08 00:29:13 +01:00
Vxrtrauter 78a47e89d3 fix: remove broken image path handling from settings dialog and paths tab 2026-03-08 00:29:10 +01:00
KeksNino e47efab901 fix: remove restartapplications flag in updater 2026-03-08 00:25:32 +01:00
KeksNino dbd5e79678 trigger github workflow to test updater 2026-03-08 00:08:37 +01:00
KeksNino 925579b9e0 fix: switch updater to silent instead of verysilent and open new exe after installation 2026-03-07 23:57:23 +01:00
KeksNino 1d969e5b9c feat: auto restart application after update has finished 2026-03-07 23:34:03 +01:00
KeksNino dbf396a187 fix: update updater to silently install new setup file 2026-03-07 23:28:00 +01:00
4 changed files with 89 additions and 37 deletions
+9
View File
@@ -27,22 +27,30 @@
AppId={{8F2E4B6A-1C3D-4E5F-9A7B-0D8E6F2C4A1B} AppId={{8F2E4B6A-1C3D-4E5F-9A7B-0D8E6F2C4A1B}
AppName={#MyAppName} AppName={#MyAppName}
AppVersion={#MyAppVersion} AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher} AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL} AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}/issues AppSupportURL={#MyAppURL}/issues
AppUpdatesURL={#MyAppURL}/releases
DefaultDirName={autopf}\{#MyAppName} DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName} DefaultGroupName={#MyAppName}
AllowNoIcons=yes AllowNoIcons=yes
LicenseFile=LICENSE
OutputDir={#MyOutputDir} OutputDir={#MyOutputDir}
OutputBaseFilename={#MyOutputFilename} OutputBaseFilename={#MyOutputFilename}
Compression=lzma2 Compression=lzma2
SolidCompression=yes SolidCompression=yes
WizardStyle=modern WizardStyle=modern
DisableWelcomePage=no
PrivilegesRequired=lowest PrivilegesRequired=lowest
PrivilegesRequiredOverridesAllowed=dialog PrivilegesRequiredOverridesAllowed=dialog
UninstallDisplayIcon={app}\{#MyAppExeName} UninstallDisplayIcon={app}\{#MyAppExeName}
UninstallDisplayName={#MyAppName}
ArchitecturesAllowed=x64compatible ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible ArchitecturesInstallIn64BitMode=x64compatible
CloseApplications=yes
RestartApplications=yes
ShowLanguageDialog=auto
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -60,3 +68,4 @@ Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: de
[Run] [Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{app}\{#MyAppExeName}"; Flags: nowait skipifnotsilent
+17 -17
View File
@@ -121,24 +121,24 @@ def settings_dialog(self):
# IMAGE PATH # # IMAGE PATH #
############### ###############
image_path_container = QWidget() # image_path_container = QWidget()
image_path_layout = QHBoxLayout() # image_path_layout = QHBoxLayout()
image_path = QLineEdit() # image_path = QLineEdit()
image_path_layout.addWidget(QLabel("Image Path (requires restart):")) # image_path_layout.addWidget(QLabel("Image Path (requires restart):"))
image_path_layout.addWidget(image_path) # image_path_layout.addWidget(image_path)
image_path_container.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) # image_path_container.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
image_path_container.setLayout(image_path_layout) # image_path_container.setLayout(image_path_layout)
image_path.setText(state.image_path) # image_path.setText(state.image_path)
def browse_image_path(): # def browse_image_path():
file_path = QFileDialog.getOpenFileName(dialog, "Select Image File", state.image_path, "Image Files (*.png *.jpg)")[0] # file_path = QFileDialog.getOpenFileName(dialog, "Select Image File", state.image_path, "Image Files (*.png *.jpg)")[0]
if file_path: # if file_path:
image_path.setText(file_path) # image_path.setText(file_path)
browse_button = QPushButton("📁") # browse_button = QPushButton("📁")
image_path_layout.addWidget(browse_button) # image_path_layout.addWidget(browse_button)
browse_button.clicked.connect(browse_image_path) # browse_button.clicked.connect(browse_image_path)
################## ##################
# SPEED LIMITING # # SPEED LIMITING #
@@ -246,7 +246,7 @@ def settings_dialog(self):
download_path.text(), download_path.text(),
down_speed_limit.value(), down_speed_limit.value(),
up_speed_limit.value(), up_speed_limit.value(),
image_path.text(), # image_path.text(),
autoresume_checkbox.isChecked(), autoresume_checkbox.isChecked(),
max_connections.value(), max_connections.value(),
max_downloads.value(), max_downloads.value(),
@@ -258,7 +258,7 @@ def settings_dialog(self):
self.tabs = QTabWidget() self.tabs = QTabWidget()
self.tab1 = general_tab("General", autoresume_container, update_checkbox_container, transparent_window_container, self.tabs) self.tab1 = general_tab("General", autoresume_container, update_checkbox_container, transparent_window_container, self.tabs)
self.tab2 = paths_tab("Paths", download_path_container, image_path_container, self.tabs) self.tab2 = paths_tab("Paths", download_path_container, self.tabs)
self.tab3 = network_tab("Network", interface_container, max_connections_container, max_downloads_container, up_speed_limit_container, down_speed_limit_container, api_url_container, self.tabs) self.tab3 = network_tab("Network", interface_container, max_connections_container, max_downloads_container, up_speed_limit_container, down_speed_limit_container, api_url_container, self.tabs)
dialog.layout().addWidget(self.tabs) dialog.layout().addWidget(self.tabs)
+61 -18
View File
@@ -27,10 +27,10 @@ import requests as r
import os import os
import subprocess import subprocess
import libtorrent as lt import libtorrent as lt
import time
import sys import sys
import json import json
import base64 import base64
import winreg
from core.utils.logging.logs import consoleLog, remove_download_log, flush_log_buffer from core.utils.logging.logs import consoleLog, remove_download_log, flush_log_buffer
from core.utils.general.wrappers import run_thread from core.utils.general.wrappers import run_thread
from core.utils.data.state import state from core.utils.data.state import state
@@ -135,25 +135,50 @@ SVG_FOLDER = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path
def download_update(latest_version): def download_update(latest_version):
new_filename = f"SoftwareManager-dev-{latest_version.replace('-dev', '')}-windows.exe" import tempfile
url = f"https://github.com/KeksPirates/SoftwareManager/releases/latest/download/SoftwareManager-dev-{latest_version.replace('-dev', '')}-windows.exe" import time
print("Downloading update...", True) new_filename = f"SoftwareManager-dev-{latest_version.replace('-dev', '')}-windows-setup.exe"
response = r.get(url, allow_redirects=True) url = f"https://github.com/KeksPirates/SoftwareManager/releases/latest/download/SoftwareManager-dev-{latest_version.replace('-dev', '')}-windows-setup.exe"
with open(new_filename, "wb") as f: installer_path = os.path.join(tempfile.gettempdir(), new_filename)
f.write(response.content)
if not os.path.exists(new_filename): progress = QtWidgets.QProgressDialog("Downloading installer...", None, 0, 0)
progress.setWindowTitle("Updating")
progress.setWindowModality(Qt.WindowModality.ApplicationModal)
progress.setCancelButton(None)
progress.setMinimumDuration(0)
progress.setAutoClose(False)
progress.setAutoReset(False)
progress.setRange(0, 100)
progress.setValue(0)
progress.show()
QtWidgets.QApplication.processEvents()
response = r.get(url, allow_redirects=True, stream=True)
total = int(response.headers.get("content-length", 0))
downloaded = 0
chunks = []
for chunk in response.iter_content(chunk_size=65536):
chunks.append(chunk)
downloaded += len(chunk)
if total > 0:
progress.setValue(int(downloaded * 100 / total))
QtWidgets.QApplication.processEvents()
with open(installer_path, "wb") as f:
for chunk in chunks:
f.write(chunk)
if not os.path.exists(installer_path):
progress.close()
raise FileNotFoundError("Executable not found") raise FileNotFoundError("Executable not found")
subprocess.Popen([new_filename], shell=True)
time.sleep(0.5)
msg = QMessageBox() progress.setLabelText("Installing update...")
msg.setIcon(QMessageBox.Icon.Information) progress.setValue(100)
msg.setWindowTitle("New Version") QtWidgets.QApplication.processEvents()
msg.setText("New version installed.")
msg.setInformativeText("Please remove the old exe.")
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
subprocess.Popen([installer_path, "/VERYSILENT", "/SUPPRESSMSGBOXES", "/SP-", "/CLOSEAPPLICATIONS"])
time.sleep(1)
sys.exit(0) sys.exit(0)
@@ -162,11 +187,13 @@ def windowCloseHelper():
class MainWindow(QtWidgets.QMainWindow, QWidget): class MainWindow(QtWidgets.QMainWindow, QWidget):
log_signal = Signal(str) # Thread-safe signal for logging log_signal = Signal(str) # Thread-safe signal for logging
search_finished_signal = Signal() # Thread-safe signal for search completion
def __init__(self): def __init__(self):
super().__init__() super().__init__()
MainWindow._instance = self MainWindow._instance = self
self.log_signal.connect(self._on_log_signal) self.log_signal.connect(self._on_log_signal)
self.search_finished_signal.connect(self._on_search_finished)
pixmap = QPixmap() pixmap = QPixmap()
image_data = base64.b64decode(logo_base64) image_data = base64.b64decode(logo_base64)
@@ -216,7 +243,7 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
self.searchbar.setPlaceholderText("Search for software...") self.searchbar.setPlaceholderText("Search for software...")
self.searchbar.setClearButtonEnabled(True) self.searchbar.setClearButtonEnabled(True)
self.searchbar.setMinimumHeight(30) self.searchbar.setMinimumHeight(30)
self.searchbar.returnPressed.connect(lambda: run_thread(threading.Thread(target=return_pressed, args=(self,)))) # Triggers data function thread on enter self.searchbar.returnPressed.connect(self._start_search)
self.dlbutton = QtWidgets.QPushButton("Download") self.dlbutton = QtWidgets.QPushButton("Download")
self.dlbutton.setCursor(Qt.CursorShape.PointingHandCursor) self.dlbutton.setCursor(Qt.CursorShape.PointingHandCursor)
@@ -299,7 +326,10 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
container = QWidget() container = QWidget()
containerLayout = QVBoxLayout() containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
search_row = QHBoxLayout()
search_row.addWidget(self.searchbar)
containerLayout.addLayout(search_row)
containerLayout.addWidget(state.tracker_list[state.tracker]) containerLayout.addWidget(state.tracker_list[state.tracker])
class DownloadModel(QAbstractTableModel): class DownloadModel(QAbstractTableModel):
@@ -662,6 +692,19 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
self.context_menu.addAction("Cancel Download", self.cancelDownloadAction) self.context_menu.addAction("Cancel Download", self.cancelDownloadAction)
self.context_menu.addAction("Delete File", self.deleteFileAction) self.context_menu.addAction("Delete File", self.deleteFileAction)
def _start_search(self):
self.searchbar.setEnabled(False)
def _search_thread():
try:
return_pressed(self)
finally:
self.search_finished_signal.emit()
run_thread(threading.Thread(target=_search_thread))
def _on_search_finished(self):
self.searchbar.setEnabled(True)
self.searchbar.setFocus()
@staticmethod @staticmethod
def add_log(text): def add_log(text):
if MainWindow._instance: if MainWindow._instance:
+2 -2
View File
@@ -30,11 +30,11 @@ def general_tab(title, autoresume, update_checkbox, transparent_window, tabs):
tabs.addTab(tab, title) tabs.addTab(tab, title)
return tab return tab
def paths_tab(title, download_path, image_path, tabs): def paths_tab(title, download_path, tabs):
tab = QWidget() tab = QWidget()
layout = QVBoxLayout() layout = QVBoxLayout()
layout.addWidget(download_path) layout.addWidget(download_path)
layout.addWidget(image_path) # layout.addWidget(image_path)
layout.addStretch() layout.addStretch()
tab.setLayout(layout) tab.setLayout(layout)
tabs.addTab(tab, title) tabs.addTab(tab, title)