Merge pull request #88 from KeksPirates/refactor/stability

fix/refactor/Improve Stability
This commit is contained in:
shayaa
2026-04-17 14:57:48 +02:00
committed by GitHub
15 changed files with 201 additions and 155 deletions
+1
View File
@@ -143,6 +143,7 @@ venv/
ENV/ ENV/
env.bak/ env.bak/
venv.bak/ venv.bak/
.python-version
# Spyder project settings # Spyder project settings
.spyderproject .spyderproject
+15 -7
View File
@@ -1,9 +1,13 @@
from utils.logging.logs import consoleLog
import requests import requests
def scrape_buzzheavier(url): def scrape_buzzheavier(url):
try:
response = requests.get(url) response = requests.get(url, timeout=15)
response.raise_for_status() response.raise_for_status()
except requests.RequestException as e:
consoleLog(f"Buzzheavier: Failed to fetch page - {e}")
return None
download_url = url + '/download' download_url = url + '/download'
@@ -12,7 +16,11 @@ def scrape_buzzheavier(url):
'hx-request': 'true', 'hx-request': 'true',
'referer': url 'referer': url
} }
head_response = requests.head(download_url, headers=headers, allow_redirects=False) try:
hx_redirect = head_response.headers.get('hx-redirect') head_response = requests.head(download_url, headers=headers, allow_redirects=False, timeout=15)
return hx_redirect hx_redirect = head_response.headers.get('hx-redirect')
return hx_redirect
except requests.RequestException as e:
consoleLog(f"Buzzheavier: Failed to fetch download URL - {e}")
return None
+35 -33
View File
@@ -23,42 +23,44 @@ def scrape_gofile(url):
content_id = match.group(1) content_id = match.group(1)
session = requests.Session() session = requests.Session()
try:
# Create a guest account
r = session.post(f"{_API_BASE}/accounts", headers={"User-Agent": _USER_AGENT}, timeout=15)
data = r.json()
if data.get("status") != "ok":
consoleLog("GoFile: Failed to create guest account")
return None
# Create a guest account account_token = data["data"]["token"]
r = session.post(f"{_API_BASE}/accounts", headers={"User-Agent": _USER_AGENT}) website_token = _generate_website_token(account_token)
data = r.json()
if data.get("status") != "ok":
consoleLog("GoFile: Failed to create guest account")
return None
account_token = data["data"]["token"] headers = {
website_token = _generate_website_token(account_token) "User-Agent": _USER_AGENT,
"Authorization": f"Bearer {account_token}",
"X-Website-Token": website_token,
"X-BL": "en-US",
"Referer": "https://gofile.io/",
"Origin": "https://gofile.io",
}
headers = { # Fetch folder contents
"User-Agent": _USER_AGENT, r = session.get(f"{_API_BASE}/contents/{content_id}", headers=headers, timeout=15)
"Authorization": f"Bearer {account_token}", data = r.json()
"X-Website-Token": website_token, if data.get("status") != "ok":
"X-BL": "en-US", consoleLog(f"GoFile: API error - {data.get('status')}")
"Referer": "https://gofile.io/", return None
"Origin": "https://gofile.io",
}
# Fetch folder contents children = data["data"].get("children", {})
r = session.get(f"{_API_BASE}/contents/{content_id}", headers=headers) if not children:
data = r.json() consoleLog("GoFile: No files found")
if data.get("status") != "ok": return None
consoleLog(f"GoFile: API error - {data.get('status')}")
return None
children = data["data"].get("children", {}) first_child = next(iter(children.values()))
if not children: link = first_child.get("link")
consoleLog("GoFile: No files found") if not link:
return None consoleLog("GoFile: No download link in response")
return None
first_child = next(iter(children.values())) return link, headers
link = first_child.get("link") finally:
if not link: session.close()
consoleLog("GoFile: No download link in response")
return None
return link, headers
+11 -2
View File
@@ -2,6 +2,7 @@ from utils.network.jsonhandler import split_data, format_data
from utils.data.tracker import get_magnet_link from utils.data.tracker import get_magnet_link
from utils.logging.logs import consoleLog from utils.logging.logs import consoleLog
from utils.data.state import state from utils.data.state import state
from urllib.parse import quote
from typing import Dict from typing import Dict
import requests import requests
@@ -11,10 +12,18 @@ class RutrackerScraper:
is_magnet = True is_magnet = True
def search(self, query): def search(self, query):
search = requests.get(f"{state.api_url}/search?q={query}", timeout=15) try:
search = requests.get(f"{state.api_url}/search?q={quote(query)}", timeout=15)
except requests.RequestException as e:
consoleLog(f"Failed to reach server: {e}")
return []
consoleLog("Sent request to server") consoleLog("Sent request to server")
if search: if search:
_, data, _, success, cached = split_data(search.text) try:
_, data, _, success, cached = split_data(search.text)
except (KeyError, ValueError) as e:
consoleLog(f"Failed to parse server response: {e}")
return []
if cached: if cached:
consoleLog("Server response cached") consoleLog("Server response cached")
if success: if success:
+2 -2
View File
@@ -27,7 +27,7 @@ class SteamripScraper:
try: try:
url = f"https://steamrip.com/games-list-page/" url = f"https://steamrip.com/games-list-page/"
response = requests.get(url) response = requests.get(url, timeout=15)
response.raise_for_status() response.raise_for_status()
text = response.text text = response.text
except requests.RequestException as e: except requests.RequestException as e:
@@ -61,7 +61,7 @@ class SteamripScraper:
def scrape_steamrip_game_downloads(self, url): def scrape_steamrip_game_downloads(self, url):
try: try:
response = requests.get(url) response = requests.get(url, timeout=15)
response.raise_for_status() response.raise_for_status()
except requests.RequestException as e: except requests.RequestException as e:
consoleLog(f"SteamRip: Failed to fetch game page - {e}") consoleLog(f"SteamRip: Failed to fetch game page - {e}")
+1 -1
View File
@@ -19,7 +19,7 @@ class UztrackerScraper:
posts = [] posts = []
try: try:
response = requests.get(search_url) response = requests.get(search_url, timeout=15)
response.raise_for_status() response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser') soup = BeautifulSoup(response.text, 'html.parser')
links = soup.find_all('tr', class_="tCenter hl-tr", id=lambda x: x and x.startswith('tor_')) links = soup.find_all('tr', class_="tCenter hl-tr", id=lambda x: x and x.startswith('tor_'))
+19 -18
View File
@@ -1,4 +1,5 @@
from PySide6.QtCore import Qt, QPoint, Signal, QThread from PySide6.QtCore import Qt, QPoint, Signal, QThread
from network.direct_download.handle import DirectDownloadHandle
from utils.logging.logs import consoleLog, remove_download_log from utils.logging.logs import consoleLog, remove_download_log
from utils.network.download import download_selected from utils.network.download import download_selected
from utils.data.tracker import get_magnet_link from utils.data.tracker import get_magnet_link
@@ -121,7 +122,12 @@ class ContextMenu_Downloads:
remove_download_log(magnet_link) remove_download_log(magnet_link)
if state.dl_session: if isinstance(magnetdl, DirectDownloadHandle):
try:
magnetdl.stop()
except Exception as e:
consoleLog(f"Exception while stopping direct download: {e}")
elif state.dl_session:
try: try:
state.dl_session.remove_torrent(magnetdl) state.dl_session.remove_torrent(magnetdl)
except Exception as e: except Exception as e:
@@ -179,29 +185,24 @@ class ContextMenu_Downloads:
remove_download_log(magnet_link) remove_download_log(magnet_link)
if state.dl_session: if isinstance(magnetdl, DirectDownloadHandle):
try:
magnetdl.stop()
except Exception as e:
consoleLog(f"Exception while stopping direct download: {e}")
elif state.dl_session:
try: try:
state.dl_session.remove_torrent(magnetdl) state.dl_session.remove_torrent(magnetdl)
time.sleep(0.5)
except Exception as e: except Exception as e:
consoleLog(f"Exception while removing download from LibTorrent: {e}") consoleLog(f"Exception while removing download from LibTorrent: {e}")
if download_path and os.path.exists(download_path): if download_path and os.path.exists(download_path):
last_error = None try:
for attempt in range(3): if os.path.isfile(download_path) or os.path.isdir(download_path):
try: send2trash(download_path)
if os.path.isfile(download_path) or os.path.isdir(download_path): consoleLog(f"Deleted files for: {torrent_name}", True)
send2trash(download_path) except Exception as e:
consoleLog(f"Deleted files for: {torrent_name}", True) consoleLog(f"Error deleting files: {e}", True)
last_error = None
break
except Exception as e:
last_error = e
if attempt < 2:
time.sleep(0.5)
if last_error:
consoleLog(f"Error deleting files: {last_error}", True)
else: else:
consoleLog(f"Removed entry (files not found): {torrent_name}", True) consoleLog(f"Removed entry (files not found): {torrent_name}", True)
+6 -9
View File
@@ -17,6 +17,7 @@ from interface.utils.searchhelper import run_search
from interface.utils.tabhelper import create_tab from interface.utils.tabhelper import create_tab
from utils.general.shutdown import closehelper from utils.general.shutdown import closehelper
from utils.general.wrappers import run_thread from utils.general.wrappers import run_thread
from utils.logging.logs import log_emitter
from interface.dialogs.image import Image from interface.dialogs.image import Image
from utils.data.state import state from utils.data.state import state
@@ -68,14 +69,12 @@ class CenteredDelegate(QStyledItemDelegate):
class MainWindow(QtWidgets.QMainWindow, QWidget): class MainWindow(QtWidgets.QMainWindow, QWidget):
eventFilter = eventFilter eventFilter = eventFilter
log_signal = Signal(str)
search_results_signal = Signal(list) search_results_signal = Signal(list)
_instance = None _instance = None
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.search_results_signal.connect(self._on_search_results) self.search_results_signal.connect(self._on_search_results)
pixmap = QPixmap() pixmap = QPixmap()
@@ -132,6 +131,7 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
self.consoleLog = QTextEdit() self.consoleLog = QTextEdit()
self.statusbar = QStatusBar() self.statusbar = QStatusBar()
log_emitter.new_log.connect(self._on_log_signal)
flush_log_buffer() flush_log_buffer()
self._tracker_elided_delegate = ElidedItemDelegate(lambda: self._tracker_hovered_row, self) self._tracker_elided_delegate = ElidedItemDelegate(lambda: self._tracker_hovered_row, self)
@@ -307,6 +307,10 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
table.setItemDelegateForColumn(i, self._tracker_hover_delegate) table.setItemDelegateForColumn(i, self._tracker_hover_delegate)
def _start_search(self): def _start_search(self):
self.searchbar.setEnabled(False)
state.trackertable.setRowCount(0)
self.show_empty_results(False)
def _search_thread(): def _search_thread():
try: try:
run_search(self) run_search(self)
@@ -315,13 +319,6 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
self.search_results_signal.emit([]) self.search_results_signal.emit([])
run_thread(threading.Thread(target=_search_thread)) run_thread(threading.Thread(target=_search_thread))
@staticmethod
def add_log(text):
if hasattr(MainWindow, "_instance") and MainWindow._instance:
MainWindow._instance.log_signal.emit(text)
return True
return False
def _on_log_signal(self, text): def _on_log_signal(self, text):
if hasattr(self, 'consoleLog'): if hasattr(self, 'consoleLog'):
self.consoleLog.append(text) self.consoleLog.append(text)
+2 -6
View File
@@ -6,9 +6,6 @@ for scraper in SCRAPERS:
state.trackers[scraper.name] = scraper state.trackers[scraper.name] = scraper
def run_search(self) -> None: def run_search(self) -> None:
state.trackertable.setRowCount(0)
self.show_empty_results(False)
search_text = self.searchbar.text() search_text = self.searchbar.text()
# Check for empty search # Check for empty search
if search_text == "": if search_text == "":
@@ -16,12 +13,11 @@ def run_search(self) -> None:
return return
state.posts = [] state.posts = []
self.searchbar.setEnabled(False)
consoleLog(f"User searched for: {search_text}") consoleLog(f"User searched for: {search_text}")
# Get current tracker and call its search function # Get current tracker and call its search function
scraper = state.trackers[state.currenttracker] scraper = state.trackers[state.currenttracker]
state.posts = scraper.search(search_text) state.posts = scraper.search(search_text)
# Update GUI headers to match the current scraper # Update GUI headers to match the current scraper
self.search_results_signal.emit(scraper.headers) self.search_results_signal.emit(scraper.headers)
+8 -6
View File
@@ -1,4 +1,3 @@
from network.libtorrent_misc import send_notification, update_log, check_deleted_files
from utils.logging.loghandler import split_data, check_completed, check_downloads from utils.logging.loghandler import split_data, check_completed, check_downloads
from network.interface import list_interfaces, init_interfaces from network.interface import list_interfaces, init_interfaces
from PySide6.QtNetwork import QLocalServer, QLocalSocket from PySide6.QtNetwork import QLocalServer, QLocalSocket
@@ -9,12 +8,13 @@ from utils.general.shutdown import closehelper
from utils.general.wrappers import run_thread from utils.general.wrappers import run_thread
from interface.assets.base64_icons import logo_base64 from interface.assets.base64_icons import logo_base64
from PySide6.QtWidgets import QSystemTrayIcon, QMenu from PySide6.QtWidgets import QSystemTrayIcon, QMenu
from network.libtorrent_misc import AppDaemons
from utils.general.shutdown import force_exit from utils.general.shutdown import force_exit
from utils.config.config import read_config from utils.config.config import read_config
from PySide6.QtGui import QAction, QPixmap from PySide6.QtGui import QAction, QPixmap
from utils.logging.logs import consoleLog from utils.logging.logs import consoleLog
from interface.gui import MainWindow from interface.gui import MainWindow
from PySide6.QtCore import Qt, QObject from PySide6.QtCore import Qt, QObject, QThread
from utils.data.state import state from utils.data.state import state
from PySide6 import QtWidgets from PySide6 import QtWidgets
import qdarktheme import qdarktheme
@@ -45,7 +45,6 @@ class SingleInstance(QObject):
self.server.listen(SERVER_NAME) self.server.listen(SERVER_NAME)
self.server.newConnection.connect(self.handle_connection) self.server.newConnection.connect(self.handle_connection)
self.is_running = False self.is_running = False
self.is_running = False
def handle_connection(self): def handle_connection(self):
socket = self.server.nextPendingConnection() socket = self.server.nextPendingConnection()
@@ -143,9 +142,12 @@ def main():
init_interfaces() init_interfaces()
consoleLog(f"Current Bound: {state.bound_interface}") consoleLog(f"Current Bound: {state.bound_interface}")
# Start background daemon threads # Start background daemon threads
run_thread(threading.Thread(target=send_notification, args=(state.shutdown_event,), daemon=True)) app._daemon_thread = QThread()
run_thread(threading.Thread(target=update_log, args=(state.shutdown_event,), daemon=True)) app._daemons = AppDaemons()
run_thread(threading.Thread(target=check_deleted_files, args=(state.shutdown_event,), daemon=True)) app._daemons.moveToThread(app._daemon_thread)
app._daemon_thread.started.connect(app._daemons.start_all)
app.aboutToQuit.connect(app._daemon_thread.quit)
app._daemon_thread.start()
# Start background non-daemon threads # Start background non-daemon threads
run_thread(threading.Thread(target=check_completed, args=(downloads, state.autoresume))) run_thread(threading.Thread(target=check_completed, args=(downloads, state.autoresume)))
run_thread(threading.Thread(target=check_downloads, args=(downloads,))) run_thread(threading.Thread(target=check_downloads, args=(downloads,)))
+1 -1
View File
@@ -163,7 +163,7 @@ def add_seed(magnet_uri, file_path):
return False return False
with state.downloads_lock: with state.downloads_lock:
state.active_downloads[magnet_uri] = handle state.active_downloads[magnet_uri] = handle
state.seeded_magnets.add(magnet_uri) state.seeded_magnets.add(magnet_uri)
return True return True
+54 -48
View File
@@ -1,5 +1,6 @@
from utils.logging.logs import update_download_completed_by_hash from utils.logging.logs import update_download_completed_by_hash
from utils.logging.logs import consoleLog from utils.logging.logs import consoleLog
from PySide6.QtCore import QObject, QTimer
from utils.data.state import state from utils.data.state import state
from plyer import notification from plyer import notification
import libtorrent as lt import libtorrent as lt
@@ -19,55 +20,28 @@ def cleanup_session():
with state.downloads_lock: with state.downloads_lock:
state.active_downloads.clear() state.active_downloads.clear()
def send_notification(shutdown_event): class AppDaemons(QObject):
notified = set() def __init__(self):
while not shutdown_event.is_set(): super().__init__()
try:
with state.downloads_lock:
items = list(state.active_downloads.items())
for magnet_uri, magnetdl in items:
if isinstance(magnetdl, dict):
continue
status = magnetdl.status()
if status.state == lt.torrent_status.seeding and magnet_uri not in notified:
notification.notify(
title="Download finished",
message=f"{status.name} has finished downloading.",
timeout=4
)
notified.add(magnet_uri)
except Exception as e:
consoleLog(f"Exception while sending notification: {e}")
time.sleep(5)
def update_log(shutdown_event): self.notified_magnets = set()
updated = set() self.updated_magnets = set()
while not shutdown_event.is_set():
try:
with state.downloads_lock:
items = list(state.active_downloads.items())
for magnet_uri, magnetdl in items:
if isinstance(magnetdl, dict):
continue
status = magnetdl.status()
if status.state == lt.torrent_status.seeding and magnet_uri not in updated and magnet_uri not in state.seeded_magnets:
consoleLog(f"Marking {status.name} as completed")
if hasattr(status, 'info_hashes'):
info_hash = str(status.info_hashes.v1)
else:
info_hash = str(status.info_hash)
update_download_completed_by_hash(info_hash, True)
updated.add(magnet_uri)
except Exception as e:
consoleLog(f"Exception while updating log file: {e}")
time.sleep(5)
def check_deleted_files(shutdown_event): # Create Timers
while not shutdown_event.is_set(): self.deleted_files_timer = QTimer(self)
self.completed_downloads_timer = QTimer(self)
# Connect Timer Signals
self.deleted_files_timer.timeout.connect(self.check_deleted_files)
self.completed_downloads_timer.timeout.connect(self.check_completed_downloads)
def start_all(self):
consoleLog("Starting Timer: deleted_files")
self.deleted_files_timer.start(2000)
consoleLog("Starting Timer: completed_downloads")
self.completed_downloads_timer.start(5000)
def check_deleted_files(self):
try: try:
with state.downloads_lock: with state.downloads_lock:
items = list(state.active_downloads.items()) items = list(state.active_downloads.items())
@@ -87,4 +61,36 @@ def check_deleted_files(shutdown_event):
del state.active_downloads[magnet_uri] del state.active_downloads[magnet_uri]
except Exception as e: except Exception as e:
consoleLog(f"Exception while checking for file deletions: {e}") consoleLog(f"Exception while checking for file deletions: {e}")
time.sleep(5)
def check_completed_downloads(self):
try:
with state.downloads_lock:
items = list(state.active_downloads.items())
seeded = set(state.seeded_magnets)
for magnet_uri, magnetdl in items:
if isinstance(magnetdl, dict):
continue
status = magnetdl.status()
if status.state == lt.torrent_status.seeding:
if magnet_uri not in self.updated_magnets and magnet_uri not in seeded:
consoleLog(f"Marking {status.name} as completed")
if hasattr(status, 'info_hashes'):
info_hash = str(status.info_hashes.v1)
else:
info_hash = str(status.info_hash)
update_download_completed_by_hash(info_hash, True)
self.updated_magnets.add(magnet_uri)
if magnet_uri not in self.notified_magnets:
notification.notify(
title="Download finished",
message=f"{status.name} has finished downloading.",
timeout=4
)
self.notified_magnets.add(magnet_uri)
except Exception as e:
consoleLog(f"Exception while checking downloads: {e}")
+1
View File
@@ -61,6 +61,7 @@ class AppState(QObject):
self.max_connections: int = 200 self.max_connections: int = 200
self.max_downloads: int = 10 self.max_downloads: int = 10
self.downloads_lock = threading.RLock() self.downloads_lock = threading.RLock()
self._log_lock = threading.Lock()
@property @property
def image_path(self) -> str: def image_path(self) -> str:
+14 -14
View File
@@ -1,4 +1,5 @@
from utils.data.models import Download, DownloadList from utils.data.models import Download, DownloadList
from PySide6.QtCore import QObject, Signal
from utils.data.state import state from utils.data.state import state
from dataclasses import asdict from dataclasses import asdict
from datetime import datetime from datetime import datetime
@@ -7,6 +8,10 @@ import time
import os import os
import re import re
class LogSignal(QObject):
new_log = Signal(str)
log_emitter = LogSignal()
def _downloads_file_path() -> str: def _downloads_file_path() -> str:
return os.path.join(state.settings_path, "downloads.json") return os.path.join(state.settings_path, "downloads.json")
@@ -187,27 +192,22 @@ def _update_download_completed_by_hash_inner(info_hash, completed) -> DownloadLi
def set_main_window(window): def set_main_window(window):
state.main_window = window state.main_window = window
def flush_log_buffer(): # credits to claude def flush_log_buffer():
if state.log_buffer: with state._log_lock:
try: for text in state.log_buffer:
from interface.gui import MainWindow log_emitter.new_log.emit(text)
for log_entry in state.log_buffer:
MainWindow.add_log(log_entry) state.log_buffer.clear()
state.log_buffer = []
except Exception as e:
consoleLog(f"Exception while flushing log buffer: {e}")
def consoleLog(text, printAnyways = False): def consoleLog(text, printAnyways = False):
now = datetime.now() now = datetime.now()
current_time = now.strftime("%H:%M:%S") current_time = now.strftime("%H:%M:%S")
formatted_text = f"[{current_time}] {text}" formatted_text = f"[{current_time}] {text}"
try: with state._log_lock:
from interface.gui import MainWindow
if not MainWindow.add_log(formatted_text):
state.log_buffer.append(formatted_text)
except Exception:
state.log_buffer.append(formatted_text) state.log_buffer.append(formatted_text)
log_emitter.new_log.emit(formatted_text)
if state.debug or printAnyways: if state.debug or printAnyways:
print(formatted_text) print(formatted_text)
+31 -8
View File
@@ -2,13 +2,12 @@ from network.direct_download.handle import DirectDownloadHandle
from utils.general.shutdown import closehelper from utils.general.shutdown import closehelper
from utils.logging.logs import consoleLog from utils.logging.logs import consoleLog
from utils.data.state import state from utils.data.state import state
from PySide6.QtCore import Qt from PySide6.QtCore import Qt, QTimer, QEventLoop
from PySide6 import QtWidgets from PySide6 import QtWidgets
import libtorrent as lt import libtorrent as lt
import subprocess import subprocess
import tempfile import tempfile
import hashlib import hashlib
import time
import sys import sys
import os import os
@@ -42,7 +41,6 @@ def download_update(assets: list):
progress = QtWidgets.QProgressDialog("Downloading update... (0.0 MB/s)", None, 0, 100) progress = QtWidgets.QProgressDialog("Downloading update... (0.0 MB/s)", None, 0, 100)
progress.setWindowTitle("Updating") progress.setWindowTitle("Updating")
progress.setWindowModality(Qt.WindowModality.ApplicationModal) progress.setWindowModality(Qt.WindowModality.ApplicationModal)
progress.setCancelButton(None)
progress.setMinimumDuration(0) progress.setMinimumDuration(0)
progress.setAutoClose(False) progress.setAutoClose(False)
progress.setAutoReset(False) progress.setAutoReset(False)
@@ -55,14 +53,19 @@ def download_update(assets: list):
handle = DirectDownloadHandle(url, filename, tempfile.gettempdir()) handle = DirectDownloadHandle(url, filename, tempfile.gettempdir())
handle.start() handle.start()
while True: loop = QEventLoop()
QtWidgets.QApplication.processEvents() timer = QTimer()
timer.setInterval(100)
def poll_progress():
status = handle.status() status = handle.status()
if status.error: if status.error:
state.down_speed_limit = original_limit state.down_speed_limit = original_limit
progress.close() progress.close()
consoleLog(f"Update download failed: {status.error}") consoleLog(f"Update download failed: {status.error}")
timer.stop()
loop.quit()
return return
if status.total_wanted > 0: if status.total_wanted > 0:
@@ -72,9 +75,25 @@ def download_update(assets: list):
progress.setLabelText(f"Downloading update... ({speed_mb:.1f} MB/s)") progress.setLabelText(f"Downloading update... ({speed_mb:.1f} MB/s)")
if status.state == lt.torrent_status.seeding: if status.state == lt.torrent_status.seeding:
break timer.stop()
loop.quit()
time.sleep(0.1) if progress.wasCanceled():
state.down_speed_limit = original_limit
consoleLog("Update download cancelled by user.")
timer.stop()
loop.quit()
return
timer.timeout.connect(poll_progress)
timer.start()
loop.exec()
if progress.wasCanceled():
return
if handle.status().error:
return
state.down_speed_limit = original_limit state.down_speed_limit = original_limit
@@ -84,6 +103,11 @@ def download_update(assets: list):
else: else:
progress.close() progress.close()
consoleLog("Error: Invalid file hash, file may be corrupted") consoleLog("Error: Invalid file hash, file may be corrupted")
QtWidgets.QMessageBox.critical(
None,
"Update Failed",
"Error: Invalid file hash, file may be corrupted"
)
sys.exit(0) sys.exit(0)
else: else:
consoleLog("Skipping hash verification (no hash found for release)") consoleLog("Skipping hash verification (no hash found for release)")
@@ -94,5 +118,4 @@ def download_update(assets: list):
closehelper() closehelper()
subprocess.Popen([installer_path, "/VERYSILENT", "/SUPPRESSMSGBOXES", "/SP-", "/CLOSEAPPLICATIONS"]) subprocess.Popen([installer_path, "/VERYSILENT", "/SUPPRESSMSGBOXES", "/SP-", "/CLOSEAPPLICATIONS"])
time.sleep(1)
os._exit(0) os._exit(0)