mirror of
https://github.com/KeksPirates/SoftwareManager.git
synced 2026-08-03 17:39:42 +02:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1da62ef414 | |||
| 4b5c36030d | |||
| cc5f6a804c | |||
| b783d0a0cb | |||
| d057624548 | |||
| 81f7970c47 | |||
| 6a41ac44c9 | |||
| 26c5410f3f | |||
| 7067f243ae | |||
| d82008c9fe | |||
| 83ff2720c8 | |||
| 83adbb027f |
@@ -24,7 +24,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-22.04
|
||||||
artifact_name: SoftwareManager-dev-${{ github.sha }}-linux
|
artifact_name: SoftwareManager-dev-${{ github.sha }}-linux
|
||||||
asset_name: SoftwareManager-dev-${{ github.sha }}-linux
|
asset_name: SoftwareManager-dev-${{ github.sha }}-linux
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
@@ -159,7 +159,7 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
name: Create Release
|
name: Create Release
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
if: success()
|
if: success()
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -172,7 +172,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p release
|
mkdir -p release
|
||||||
SHORT_SHA="${{ needs.build.outputs.short_sha }}"
|
SHORT_SHA="${{ needs.build.outputs.short_sha }}"
|
||||||
cp artifacts/ubuntu-latest-build/SoftwareManager-dev-*-linux release/SoftwareManager-dev-${SHORT_SHA}-linux
|
cp artifacts/ubuntu-22.04-build/SoftwareManager-dev-*-linux release/SoftwareManager-dev-${SHORT_SHA}-linux
|
||||||
cp artifacts/windows-latest-build/SoftwareManager-dev-*-windows.exe release/SoftwareManager-dev-${SHORT_SHA}-windows.exe
|
cp artifacts/windows-latest-build/SoftwareManager-dev-*-windows.exe release/SoftwareManager-dev-${SHORT_SHA}-windows.exe
|
||||||
cp artifacts/macos-latest-build/SoftwareManager-dev-*-macos release/SoftwareManager-dev-${SHORT_SHA}-macos
|
cp artifacts/macos-latest-build/SoftwareManager-dev-*-macos release/SoftwareManager-dev-${SHORT_SHA}-macos
|
||||||
chmod +x release/SoftwareManager-dev-*-linux release/SoftwareManager-dev-*-macos
|
chmod +x release/SoftwareManager-dev-*-linux release/SoftwareManager-dev-*-macos
|
||||||
@@ -207,4 +207,4 @@ jobs:
|
|||||||
release/SoftwareManager-dev-${{ needs.build.outputs.short_sha }}-windows.exe
|
release/SoftwareManager-dev-${{ needs.build.outputs.short_sha }}-windows.exe
|
||||||
release/SoftwareManager-dev-${{ needs.build.outputs.short_sha }}-macos
|
release/SoftwareManager-dev-${{ needs.build.outputs.short_sha }}-macos
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ from PySide6.QtWidgets import (
|
|||||||
QHBoxLayout,
|
QHBoxLayout,
|
||||||
QSpinBox,
|
QSpinBox,
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
)
|
QFileDialog,
|
||||||
|
)
|
||||||
|
import platform
|
||||||
|
|
||||||
|
|
||||||
def settings_dialog(self):
|
def settings_dialog(self):
|
||||||
@@ -32,14 +34,16 @@ def settings_dialog(self):
|
|||||||
update_checkbox_layout = QHBoxLayout()
|
update_checkbox_layout = QHBoxLayout()
|
||||||
|
|
||||||
# ignore updates checkbox
|
# ignore updates checkbox
|
||||||
update_checkbox = QCheckBox()
|
|
||||||
update_checkbox_container.setLayout(update_checkbox_layout)
|
if platform.system() == "Windows":
|
||||||
update_checkbox_layout.addWidget(QLabel("Ignore Updates: "))
|
update_checkbox = QCheckBox()
|
||||||
update_checkbox_layout.addStretch()
|
update_checkbox_container.setLayout(update_checkbox_layout)
|
||||||
update_checkbox.setChecked(state.ignore_updates)
|
update_checkbox_layout.addWidget(QLabel("Ignore Updates: "))
|
||||||
update_checkbox.toggled.connect(lambda checked: setattr(state, 'ignore_updates', checked))
|
update_checkbox_layout.addStretch()
|
||||||
update_checkbox_layout.addWidget(update_checkbox)
|
update_checkbox.setChecked(state.ignore_updates)
|
||||||
dialog.layout().addWidget(update_checkbox_container)
|
update_checkbox.toggled.connect(lambda checked: setattr(state, 'ignore_updates', checked))
|
||||||
|
update_checkbox_layout.addWidget(update_checkbox)
|
||||||
|
dialog.layout().addWidget(update_checkbox_container)
|
||||||
|
|
||||||
# auto-resume downloads checkbox
|
# auto-resume downloads checkbox
|
||||||
|
|
||||||
@@ -111,6 +115,15 @@ def settings_dialog(self):
|
|||||||
download_path.setText(state.download_path)
|
download_path.setText(state.download_path)
|
||||||
dialog.layout().addWidget(download_path_container)
|
dialog.layout().addWidget(download_path_container)
|
||||||
|
|
||||||
|
def browse_download_path():
|
||||||
|
dir_path = QFileDialog.getExistingDirectory(dialog, "Select Download Directory", state.download_path)
|
||||||
|
if dir_path:
|
||||||
|
download_path.setText(dir_path)
|
||||||
|
|
||||||
|
browse_button = QPushButton("📁")
|
||||||
|
download_path_layout.addWidget(browse_button)
|
||||||
|
browse_button.clicked.connect(browse_download_path)
|
||||||
|
|
||||||
##################
|
##################
|
||||||
# SPEED LIMITING #
|
# SPEED LIMITING #
|
||||||
##################
|
##################
|
||||||
@@ -144,6 +157,15 @@ def settings_dialog(self):
|
|||||||
image_path.setText(state.image_path)
|
image_path.setText(state.image_path)
|
||||||
dialog.layout().addWidget(image_path_container)
|
dialog.layout().addWidget(image_path_container)
|
||||||
|
|
||||||
|
def browse_image_path():
|
||||||
|
file_path = QFileDialog.getOpenFileName(dialog, "Select Image File", state.image_path, "Image Files (*.png *.jpg)")[0]
|
||||||
|
if file_path:
|
||||||
|
image_path.setText(file_path)
|
||||||
|
|
||||||
|
browse_button = QPushButton("📁")
|
||||||
|
image_path_layout.addWidget(browse_button)
|
||||||
|
browse_button.clicked.connect(browse_image_path)
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# SAVE/CANCEL #
|
# SAVE/CANCEL #
|
||||||
###############
|
###############
|
||||||
|
|||||||
+48
-14
@@ -20,7 +20,7 @@ from PySide6.QtWidgets import (
|
|||||||
QStyleOptionButton,
|
QStyleOptionButton,
|
||||||
QStyledItemDelegate,
|
QStyledItemDelegate,
|
||||||
QApplication,
|
QApplication,
|
||||||
)
|
)
|
||||||
|
|
||||||
from PySide6.QtGui import QIcon, QAction, QCloseEvent, QImage, QPixmap
|
from PySide6.QtGui import QIcon, QAction, QCloseEvent, QImage, QPixmap
|
||||||
import darkdetect
|
import darkdetect
|
||||||
@@ -93,8 +93,8 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
try:
|
try:
|
||||||
import ctypes
|
import ctypes
|
||||||
myappid = 'SoftwareManager.App.1'
|
appid = 'SoftwareManager'
|
||||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appid)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
consoleLog(f"Could not set app ID: {e}")
|
consoleLog(f"Could not set app ID: {e}")
|
||||||
|
|
||||||
@@ -147,6 +147,7 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
self.downloadList = QTableView()
|
self.downloadList = QTableView()
|
||||||
self.emptyLibrary = QLabel("No items in library.")
|
self.emptyLibrary = QLabel("No items in library.")
|
||||||
self.emptyDownload = QLabel("No items in downloads.")
|
self.emptyDownload = QLabel("No items in downloads.")
|
||||||
|
self.emptyDownload.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
self.consoleLog = QTextEdit()
|
self.consoleLog = QTextEdit()
|
||||||
self.progressbar = QProgressBar()
|
self.progressbar = QProgressBar()
|
||||||
@@ -183,7 +184,7 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
|
|
||||||
def rowCount(self, parent=QModelIndex()):
|
def rowCount(self, parent=QModelIndex()):
|
||||||
return len(state.downloads)
|
return len(state.downloads)
|
||||||
|
|
||||||
def columnCount(self, parent=QModelIndex()):
|
def columnCount(self, parent=QModelIndex()):
|
||||||
return len(self.headers)
|
return len(self.headers)
|
||||||
|
|
||||||
@@ -209,9 +210,11 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
elif col == 4:
|
elif col == 4:
|
||||||
return f"{download.download_speed_string()}"
|
return f"{download.download_speed_string()}"
|
||||||
elif col == 5:
|
elif col == 5:
|
||||||
pass
|
return f"{download.completed_length_string()}"
|
||||||
elif col == 6:
|
elif col == 6:
|
||||||
return f"{download.total_length_string()}"
|
return f"{download.total_length_string()}"
|
||||||
|
elif col == 7:
|
||||||
|
return f"{download.eta_string()}"
|
||||||
|
|
||||||
if role == Qt.UserRole and col == 0:
|
if role == Qt.UserRole and col == 0:
|
||||||
return download.is_paused
|
return download.is_paused
|
||||||
@@ -220,12 +223,31 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
|
|
||||||
def toggle_pause_resume(self, row):
|
def toggle_pause_resume(self, row):
|
||||||
download = state.downloads[row]
|
download = state.downloads[row]
|
||||||
|
if download.progress == 100:
|
||||||
|
if state.download_path is not None and os.path.exists(state.download_path):
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
os.startfile(os.path.normpath(state.download_path))
|
||||||
|
elif platform.system() == "Linux":
|
||||||
|
subprocess.Popen(["xdg-open", state.download_path])
|
||||||
|
elif platform.system() == "Darwin":
|
||||||
|
subprocess.Popen(["open", state.download_path])
|
||||||
|
else:
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
os.startfile(os.path.normpath(os.getcwd()))
|
||||||
|
elif platform.system() == "Linux":
|
||||||
|
subprocess.Popen(["xdg-open", os.getcwd()])
|
||||||
|
elif platform.system() == "Darwin":
|
||||||
|
subprocess.Popen(["open", os.getcwd()])
|
||||||
|
return
|
||||||
|
|
||||||
if download.is_paused:
|
if download.is_paused:
|
||||||
download.resume()
|
download.resume()
|
||||||
|
consoleLog(f"Resumed download: {download.name}", True)
|
||||||
else:
|
else:
|
||||||
download.pause()
|
download.pause()
|
||||||
|
consoleLog(f"Paused download: {download.name}", True)
|
||||||
idx = self.index(row, 0)
|
idx = self.index(row, 0)
|
||||||
self.dataChanged.emit(idx, idx, [Qt.DisplayRole, Qt.UserRole])
|
self.dataChanged.emit(idx, idx, [Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.UserRole])
|
||||||
|
|
||||||
class PauseResumeDelegate(QStyledItemDelegate):
|
class PauseResumeDelegate(QStyledItemDelegate):
|
||||||
clicked = Signal(int)
|
clicked = Signal(int)
|
||||||
@@ -236,10 +258,16 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
paused = index.data(Qt.UserRole)
|
paused = index.data(Qt.UserRole)
|
||||||
|
download = state.downloads[index.row()]
|
||||||
|
|
||||||
button = QStyleOptionButton()
|
button = QStyleOptionButton()
|
||||||
button.rect = option.rect
|
button.rect = option.rect
|
||||||
button.text = "▶︎" if paused else "⏸︎"
|
|
||||||
|
if download.progress == 100:
|
||||||
|
button.text = "📁"
|
||||||
|
else:
|
||||||
|
button.text = "▶︎" if paused else "⏸︎"
|
||||||
|
|
||||||
button.state = QStyle.State_Enabled
|
button.state = QStyle.State_Enabled
|
||||||
|
|
||||||
QApplication.style().drawControl(
|
QApplication.style().drawControl(
|
||||||
@@ -265,12 +293,6 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
def on_pause_resume_clicked(row):
|
def on_pause_resume_clicked(row):
|
||||||
download_model.toggle_pause_resume(row)
|
download_model.toggle_pause_resume(row)
|
||||||
|
|
||||||
download = state.downloads[row]
|
|
||||||
if download.is_paused:
|
|
||||||
download.pause()
|
|
||||||
else:
|
|
||||||
download.resume()
|
|
||||||
|
|
||||||
delegate = PauseResumeDelegate(self.downloadList)
|
delegate = PauseResumeDelegate(self.downloadList)
|
||||||
self.downloadList.setItemDelegateForColumn(0, delegate)
|
self.downloadList.setItemDelegateForColumn(0, delegate)
|
||||||
delegate.clicked.connect(on_pause_resume_clicked)
|
delegate.clicked.connect(on_pause_resume_clicked)
|
||||||
@@ -345,6 +367,10 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
self.download_timer.timeout.connect(lambda: run_thread(threading.Thread(target=self.download_list_update)))
|
self.download_timer.timeout.connect(lambda: run_thread(threading.Thread(target=self.download_list_update)))
|
||||||
self.download_timer.start(500)
|
self.download_timer.start(500)
|
||||||
|
|
||||||
|
self.active_timer = QTimer()
|
||||||
|
self.active_timer.timeout.connect(self.show_empty_downloads)
|
||||||
|
self.active_timer.start(500)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_log(text):
|
def add_log(text):
|
||||||
if MainWindow._instance:
|
if MainWindow._instance:
|
||||||
@@ -367,6 +393,7 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
if self.download_model:
|
if self.download_model:
|
||||||
self.download_model.layoutAboutToBeChanged.emit()
|
self.download_model.layoutAboutToBeChanged.emit()
|
||||||
self.download_model.layoutChanged.emit()
|
self.download_model.layoutChanged.emit()
|
||||||
|
|
||||||
|
|
||||||
def closeEvent(self, event: QCloseEvent):
|
def closeEvent(self, event: QCloseEvent):
|
||||||
closehelper()
|
closehelper()
|
||||||
@@ -384,9 +411,16 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
|||||||
self.qtablewidget.hide()
|
self.qtablewidget.hide()
|
||||||
self.emptyResults.show()
|
self.emptyResults.show()
|
||||||
else:
|
else:
|
||||||
self.emptyResults.hide()
|
|
||||||
self.qtablewidget.show()
|
self.qtablewidget.show()
|
||||||
|
self.emptyResults.hide()
|
||||||
|
|
||||||
|
def show_empty_downloads(self):
|
||||||
|
if len(state.downloads) > 0:
|
||||||
|
self.emptyDownload.hide()
|
||||||
|
self.downloadList.show()
|
||||||
|
else:
|
||||||
|
self.emptyDownload.show()
|
||||||
|
self.downloadList.hide()
|
||||||
|
|
||||||
# thank you claude
|
# thank you claude
|
||||||
def resizeEvent(self, event):
|
def resizeEvent(self, event):
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from core.utils.data.state import state
|
|||||||
from core.utils.general.logs import update_download_completed_by_hash
|
from core.utils.general.logs import update_download_completed_by_hash
|
||||||
from core.utils.general.logs import consoleLog
|
from core.utils.general.logs import consoleLog
|
||||||
from plyer import notification
|
from plyer import notification
|
||||||
|
import socket
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -42,6 +43,21 @@ def aria2server():
|
|||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.DEVNULL,
|
||||||
creationflags=subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0
|
creationflags=subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
max_checks = 50
|
||||||
|
for check in range(max_checks):
|
||||||
|
try:
|
||||||
|
sock = socket.socket()
|
||||||
|
sock.settimeout(0.1)
|
||||||
|
sock.connect(("localhost", 6800))
|
||||||
|
sock.close()
|
||||||
|
break
|
||||||
|
except(ConnectionRefusedError, socket.timeout):
|
||||||
|
time.sleep(0.1)
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Aria2 Server failed to start")
|
||||||
|
|
||||||
|
consoleLog("Aria2 Server started")
|
||||||
return aria2server
|
return aria2server
|
||||||
|
|
||||||
def dlprogress():
|
def dlprogress():
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ def start_client():
|
|||||||
consoleLog("Started Aria2p")
|
consoleLog("Started Aria2p")
|
||||||
|
|
||||||
def add_magnet(uri):
|
def add_magnet(uri):
|
||||||
aria2.add_magnet(uri)
|
if uri is not None and uri.startswith("magnet:?"):
|
||||||
consoleLog("Magnet URI added to Aria2")
|
aria2.add_magnet(uri)
|
||||||
|
consoleLog("Magnet URI added to Aria2")
|
||||||
|
else:
|
||||||
|
consoleLog(f"Invalid Magnet Link: {uri}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from core.utils.data.state import state
|
|
||||||
from core.utils.general.logs import consoleLog
|
from core.utils.general.logs import consoleLog
|
||||||
from core.utils.network.download import run_download_direct
|
from core.utils.network.download import run_download_direct
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user