mirror of
https://github.com/KeksPirates/SoftwareManager.git
synced 2026-08-04 17:59:43 +02:00
fix: improve download status handling and enhance thread safety in logging functions
This commit is contained in:
@@ -296,7 +296,8 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
elif status.state == lt.torrent_status.seeding:
|
elif status.state == lt.torrent_status.seeding:
|
||||||
return "Seeding"
|
return "Seeding"
|
||||||
elif status.paused:
|
elif status.paused:
|
||||||
return "Paused"
|
is_auto = bool(magnetdl.flags() & lt.torrent_flags.auto_managed)
|
||||||
|
return "Queued" if is_auto else "Paused"
|
||||||
else:
|
else:
|
||||||
return "Queued"
|
return "Queued"
|
||||||
elif col == 3:
|
elif col == 3:
|
||||||
@@ -407,7 +408,8 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
button.setIcon(_svg_icon(SVG_FOLDER, 18))
|
button.setIcon(_svg_icon(SVG_FOLDER, 18))
|
||||||
button.setText("")
|
button.setText("")
|
||||||
else:
|
else:
|
||||||
button.setIcon(_svg_icon(SVG_PLAY if status.paused else SVG_PAUSE, 18))
|
is_user_paused = status.paused and not bool(magnetdl.flags() & lt.torrent_flags.auto_managed)
|
||||||
|
button.setIcon(_svg_icon(SVG_PLAY if is_user_paused else SVG_PAUSE, 18))
|
||||||
button.setText("")
|
button.setText("")
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
@@ -424,7 +426,8 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
btnPause.setIcon(_svg_icon(SVG_FOLDER, 18))
|
btnPause.setIcon(_svg_icon(SVG_FOLDER, 18))
|
||||||
else:
|
else:
|
||||||
btnPause = QtWidgets.QPushButton()
|
btnPause = QtWidgets.QPushButton()
|
||||||
btnPause.setIcon(_svg_icon(SVG_PLAY if status.paused else SVG_PAUSE, 18))
|
is_user_paused = status.paused and not bool(magnetdl.flags() & lt.torrent_flags.auto_managed)
|
||||||
|
btnPause.setIcon(_svg_icon(SVG_PLAY if is_user_paused else SVG_PAUSE, 18))
|
||||||
btnPause.setIconSize(QSize(18, 18))
|
btnPause.setIconSize(QSize(18, 18))
|
||||||
btnPause.setFixedSize(30, 30)
|
btnPause.setFixedSize(30, 30)
|
||||||
btnPause.setCursor(Qt.CursorShape.PointingHandCursor)
|
btnPause.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
@@ -442,9 +445,6 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
widget.setLayout(layout)
|
widget.setLayout(layout)
|
||||||
return widget
|
return widget
|
||||||
def editorEvent(self, event, model, option, index):
|
def editorEvent(self, event, model, option, index):
|
||||||
if index.column() == 0 and event.type() == QEvent.Type.MouseButtonPress:
|
|
||||||
self.clicked.emit(index.row())
|
|
||||||
return True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.download_model = DownloadModel()
|
self.download_model = DownloadModel()
|
||||||
@@ -453,6 +453,8 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
self.downloadList.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.Fixed)
|
self.downloadList.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.Fixed)
|
||||||
self.downloadList.horizontalHeader().resizeSection(0, 70)
|
self.downloadList.horizontalHeader().resizeSection(0, 70)
|
||||||
self.downloadList.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
|
self.downloadList.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
|
||||||
|
self.downloadList.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
|
self.downloadList.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
self.downloadList.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.ResizeToContents)
|
self.downloadList.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
self.downloadList.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.ResizeToContents)
|
self.downloadList.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
self.downloadList.horizontalHeader().setSectionResizeMode(6, QHeaderView.ResizeMode.ResizeToContents)
|
self.downloadList.horizontalHeader().setSectionResizeMode(6, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
@@ -666,12 +668,34 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
|
|
||||||
def download_list_update(self):
|
def download_list_update(self):
|
||||||
if self.download_model:
|
if self.download_model:
|
||||||
|
row_count = self.download_model.rowCount()
|
||||||
|
if row_count > 0:
|
||||||
|
top_left = self.download_model.index(0, 0)
|
||||||
|
bottom_right = self.download_model.index(row_count - 1, self.download_model.columnCount() - 1)
|
||||||
|
self.download_model.dataChanged.emit(top_left, bottom_right, [Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.UserRole])
|
||||||
|
|
||||||
|
if not hasattr(self, '_last_dl_row_count'):
|
||||||
|
self._last_dl_row_count = 0
|
||||||
|
if row_count != self._last_dl_row_count:
|
||||||
|
|
||||||
|
for row in range(row_count, self._last_dl_row_count):
|
||||||
|
idx = self.download_model.index(row, 0)
|
||||||
|
self.downloadList.closePersistentEditor(idx)
|
||||||
|
self._last_dl_row_count = row_count
|
||||||
self.download_model.layoutAboutToBeChanged.emit()
|
self.download_model.layoutAboutToBeChanged.emit()
|
||||||
self.download_model.layoutChanged.emit()
|
self.download_model.layoutChanged.emit()
|
||||||
for row in range(self.download_model.rowCount()):
|
for row in range(row_count):
|
||||||
idx = self.download_model.index(row, 0)
|
idx = self.download_model.index(row, 0)
|
||||||
self.downloadList.closePersistentEditor(idx)
|
self.downloadList.closePersistentEditor(idx)
|
||||||
self.downloadList.openPersistentEditor(idx)
|
self.downloadList.openPersistentEditor(idx)
|
||||||
|
else:
|
||||||
|
|
||||||
|
delegate = self.downloadList.itemDelegateForColumn(0)
|
||||||
|
for row in range(row_count):
|
||||||
|
idx = self.download_model.index(row, 0)
|
||||||
|
editor = self.downloadList.indexWidget(idx)
|
||||||
|
if editor and delegate:
|
||||||
|
delegate.setEditorData(editor, idx)
|
||||||
self._update_speed_label()
|
self._update_speed_label()
|
||||||
|
|
||||||
def _update_speed_label(self):
|
def _update_speed_label(self):
|
||||||
@@ -703,6 +727,7 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
def eventFilter(self, obj, event):
|
def eventFilter(self, obj, event):
|
||||||
|
try:
|
||||||
for tbl in (self.rutrackerlist, self.uztrackerlist, self.monkruslist):
|
for tbl in (self.rutrackerlist, self.uztrackerlist, self.monkruslist):
|
||||||
if obj == tbl.viewport():
|
if obj == tbl.viewport():
|
||||||
if event.type() == QEvent.Type.MouseMove:
|
if event.type() == QEvent.Type.MouseMove:
|
||||||
@@ -732,6 +757,8 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
old_row = self._hovered_row
|
old_row = self._hovered_row
|
||||||
self._hovered_row = -1
|
self._hovered_row = -1
|
||||||
self._invalidate_hover_row(old_row)
|
self._invalidate_hover_row(old_row)
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
return super().eventFilter(obj, event)
|
return super().eventFilter(obj, event)
|
||||||
|
|
||||||
def _invalidate_hover_row(self, row):
|
def _invalidate_hover_row(self, row):
|
||||||
|
|||||||
@@ -6,23 +6,14 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
_log_buffer = []
|
_log_buffer = []
|
||||||
|
_downloads_lock = threading.RLock()
|
||||||
|
|
||||||
|
|
||||||
def add_download_log(title, url, magnet_uri, completed) -> DownloadList:
|
def add_download_log(title, url, magnet_uri, completed) -> DownloadList:
|
||||||
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
# wait for metadata outside the lock to avoid blocking other threads
|
||||||
|
|
||||||
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
|
||||||
try:
|
|
||||||
with open(downloads_file, "r") as file:
|
|
||||||
existing_data = json.load(file)
|
|
||||||
downloads = [Download(**d) for d in existing_data.get("data", [])]
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
downloads = []
|
|
||||||
else:
|
|
||||||
downloads = []
|
|
||||||
|
|
||||||
magnetdl = state.active_downloads.get(magnet_uri)
|
magnetdl = state.active_downloads.get(magnet_uri)
|
||||||
if magnetdl:
|
if magnetdl:
|
||||||
status = magnetdl.status()
|
status = magnetdl.status()
|
||||||
@@ -37,6 +28,21 @@ def add_download_log(title, url, magnet_uri, completed) -> DownloadList:
|
|||||||
path = os.path.join(save_path, torrent_name)
|
path = os.path.join(save_path, torrent_name)
|
||||||
else:
|
else:
|
||||||
path = os.path.join(state.download_path, title)
|
path = os.path.join(state.download_path, title)
|
||||||
|
with _downloads_lock:
|
||||||
|
return _add_download_log_inner(title, url, magnet_uri, completed, path)
|
||||||
|
|
||||||
|
def _add_download_log_inner(title, url, magnet_uri, completed, path) -> DownloadList:
|
||||||
|
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
||||||
|
|
||||||
|
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
||||||
|
try:
|
||||||
|
with open(downloads_file, "r") as file:
|
||||||
|
existing_data = json.load(file)
|
||||||
|
downloads = [Download(**d) for d in existing_data.get("data", [])]
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
downloads = []
|
||||||
|
else:
|
||||||
|
downloads = []
|
||||||
|
|
||||||
if any(d.magnet_uri == magnet_uri or d.url == url for d in downloads):
|
if any(d.magnet_uri == magnet_uri or d.url == url for d in downloads):
|
||||||
if magnet_uri in state.active_downloads:
|
if magnet_uri in state.active_downloads:
|
||||||
@@ -65,6 +71,10 @@ def add_download_log(title, url, magnet_uri, completed) -> DownloadList:
|
|||||||
return download_list
|
return download_list
|
||||||
|
|
||||||
def remove_download_log(magnet_uri) -> DownloadList:
|
def remove_download_log(magnet_uri) -> DownloadList:
|
||||||
|
with _downloads_lock:
|
||||||
|
return _remove_download_log_inner(magnet_uri)
|
||||||
|
|
||||||
|
def _remove_download_log_inner(magnet_uri) -> DownloadList:
|
||||||
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
||||||
|
|
||||||
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
||||||
@@ -91,6 +101,10 @@ def remove_download_log(magnet_uri) -> DownloadList:
|
|||||||
return download_list
|
return download_list
|
||||||
|
|
||||||
def update_download_completed(magnet_uri, completed) -> DownloadList:
|
def update_download_completed(magnet_uri, completed) -> DownloadList:
|
||||||
|
with _downloads_lock:
|
||||||
|
return _update_download_completed_inner(magnet_uri, completed)
|
||||||
|
|
||||||
|
def _update_download_completed_inner(magnet_uri, completed) -> DownloadList:
|
||||||
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
||||||
|
|
||||||
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
||||||
@@ -143,6 +157,10 @@ def update_download_completed(magnet_uri, completed) -> DownloadList:
|
|||||||
|
|
||||||
|
|
||||||
def get_download_logs() -> DownloadList:
|
def get_download_logs() -> DownloadList:
|
||||||
|
with _downloads_lock:
|
||||||
|
return _get_download_logs_inner()
|
||||||
|
|
||||||
|
def _get_download_logs_inner() -> DownloadList:
|
||||||
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
||||||
|
|
||||||
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
||||||
@@ -166,6 +184,10 @@ def extract_hash_from_magnet(magnet_uri): # full credits to claude for this
|
|||||||
|
|
||||||
|
|
||||||
def update_download_completed_by_hash(info_hash, completed) -> DownloadList:
|
def update_download_completed_by_hash(info_hash, completed) -> DownloadList:
|
||||||
|
with _downloads_lock:
|
||||||
|
return _update_download_completed_by_hash_inner(info_hash, completed)
|
||||||
|
|
||||||
|
def _update_download_completed_by_hash_inner(info_hash, completed) -> DownloadList:
|
||||||
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
downloads_file = os.path.join(state.settings_path, "downloads.json")
|
||||||
|
|
||||||
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
if os.path.exists(downloads_file) and os.path.getsize(downloads_file) > 0:
|
||||||
|
|||||||
Reference in New Issue
Block a user