mirror of
https://github.com/KeksPirates/SoftwareManager.git
synced 2026-08-03 17:39:42 +02:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 08ae3ee8df | |||
| 1ffa1cacb9 | |||
| 207eb70f11 | |||
| 64144e5ed7 | |||
| d05fae7e87 | |||
| 9abdec6c33 | |||
| fb5eb61d05 | |||
| eff2164ecc | |||
| d8aa206ea2 | |||
| 6de74303ff | |||
| 5eb6314cb2 | |||
| 179dd0af83 | |||
| 365700900f | |||
| babbccdc9a | |||
| 367ffab86a | |||
| 71bad60617 | |||
| 27758f794c | |||
| d82afe8577 | |||
| 8592b3058e | |||
| 7a82e948b9 | |||
| 782b0b6bc9 | |||
| 71cc0d9f1f | |||
| 675dead1d9 | |||
| 64ca3c76a2 | |||
| d378ee8258 | |||
| e9b01426f8 | |||
| 631f6592ac | |||
| 468faff16b | |||
| 6b45c40aad | |||
| d6302fc43f | |||
| e768c7518b | |||
| 49c390131a | |||
| 04aaff3b29 |
@@ -141,7 +141,7 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: |
|
||||
pyinstaller --onefile \
|
||||
pyinstaller --windowed \
|
||||
--add-data "build_info.json:." \
|
||||
--exclude-module PyQt6 \
|
||||
--exclude-module PyQt5 \
|
||||
@@ -153,6 +153,10 @@ jobs:
|
||||
--name ${{ env.APP_NAME }} \
|
||||
src/main.py
|
||||
|
||||
- name: Install create-dmg (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install create-dmg
|
||||
|
||||
- name: Rename artifact
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -160,9 +164,20 @@ jobs:
|
||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||
mv nuitka-build/main.dist dist-final/${{ env.APP_NAME }}
|
||||
ls -la dist-final/${{ env.APP_NAME }}/
|
||||
else
|
||||
elif [ "$RUNNER_OS" == "Linux" ]; then
|
||||
chmod +x dist/${{ env.APP_NAME }}
|
||||
mv dist/${{ env.APP_NAME }} dist-final/${{ matrix.artifact_name }}
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
create-dmg \
|
||||
--volname "${{ env.APP_NAME }}" \
|
||||
--window-pos 200 120 \
|
||||
--window-size 600 300 \
|
||||
--icon-size 100 \
|
||||
--icon "${{ env.APP_NAME }}.app" 150 150 \
|
||||
--hide-extension "${{ env.APP_NAME }}.app" \
|
||||
--app-drop-link 450 150 \
|
||||
"dist-final/${{ matrix.artifact_name }}.dmg" \
|
||||
"dist/"
|
||||
fi
|
||||
ls -la dist-final/
|
||||
|
||||
@@ -203,7 +218,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ matrix.os }}-build
|
||||
path: dist-final/${{ matrix.artifact_name }}
|
||||
path: dist-final/${{ matrix.artifact_name }}*
|
||||
retention-days: 1
|
||||
|
||||
release:
|
||||
@@ -225,8 +240,8 @@ jobs:
|
||||
cp artifacts/ubuntu-22.04-build/SoftwareManager-stable-*-linux release/SoftwareManager-stable-${SHORT_SHA}-linux
|
||||
cp artifacts/windows-latest-build/SoftwareManager-stable-*-windows.zip release/SoftwareManager-stable-${SHORT_SHA}-windows.zip
|
||||
cp artifacts/windows-latest-build/SoftwareManager-stable-*-windows-setup.exe release/SoftwareManager-stable-${SHORT_SHA}-windows-setup.exe
|
||||
cp artifacts/macos-latest-build/SoftwareManager-stable-*-macos release/SoftwareManager-stable-${SHORT_SHA}-macos
|
||||
chmod +x release/SoftwareManager-stable-*-linux release/SoftwareManager-stable-*-macos
|
||||
cp artifacts/macos-latest-build/SoftwareManager-stable-*-macos.dmg release/SoftwareManager-stable-${SHORT_SHA}-macos.dmg
|
||||
chmod +x release/SoftwareManager-stable-*-linux
|
||||
ls -la release/
|
||||
|
||||
- name: Generate checksums
|
||||
@@ -236,7 +251,7 @@ jobs:
|
||||
cat SHA256SUMS.txt
|
||||
|
||||
- name: Create Release (Public)
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
tag_name: ${{ needs.build.outputs.version }}
|
||||
@@ -246,5 +261,5 @@ jobs:
|
||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-linux
|
||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-windows.zip
|
||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-windows-setup.exe
|
||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-macos
|
||||
release/SoftwareManager-stable-${{ needs.build.outputs.short_sha }}-macos.dmg
|
||||
release/SHA256SUMS.txt
|
||||
|
||||
@@ -58,6 +58,15 @@ jobs:
|
||||
env:
|
||||
UV_SYSTEM_PYTHON: 1
|
||||
|
||||
- name: Install dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
libxcb-cursor0 libxcb-render-util0 libxcb-xkb1 \
|
||||
libxcb-icccm4 libxcb-keysyms1 libxcb-image0 \
|
||||
libxcb-shape0 libxcb-util1 libxkbcommon-x11-0
|
||||
|
||||
- name: Install Nuitka (Windows only)
|
||||
if: runner.os == 'Windows'
|
||||
run: uv pip install nuitka
|
||||
@@ -266,7 +275,7 @@ jobs:
|
||||
cat release_notes.md
|
||||
|
||||
- name: Create Release (Public)
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
tag_name: ${{ needs.build.outputs.version }}
|
||||
name: ${{ needs.build.outputs.version }}
|
||||
@@ -278,4 +287,4 @@ jobs:
|
||||
release/SoftwareManager-dev-${{ needs.build.outputs.short_sha }}-macos
|
||||
release/SHA256SUMS.txt
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
build:
|
||||
name: Build ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false # keep other platforms building even if one fails
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
run: |
|
||||
pyinstaller --onefile \
|
||||
pyinstaller --windowed \
|
||||
--add-data "build_info.json:." \
|
||||
--exclude-module PyQt6 \
|
||||
--exclude-module PyQt5 \
|
||||
@@ -150,15 +150,30 @@ jobs:
|
||||
--name ${{ env.APP_NAME }} \
|
||||
src/main.py
|
||||
|
||||
- name: Install create-dmg (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install create-dmg
|
||||
|
||||
- name: Stage artifact
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p dist-final
|
||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||
mv nuitka-build/main.dist dist-final/${{ env.APP_NAME }}
|
||||
else
|
||||
elif [ "$RUNNER_OS" == "Linux" ]; then
|
||||
chmod +x dist/${{ env.APP_NAME }}
|
||||
mv dist/${{ env.APP_NAME }} dist-final/${{ matrix.artifact_name }}
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
create-dmg \
|
||||
--volname "${{ env.APP_NAME }} Test" \
|
||||
--window-pos 200 120 \
|
||||
--window-size 600 300 \
|
||||
--icon-size 100 \
|
||||
--icon "${{ env.APP_NAME }}.app" 150 150 \
|
||||
--hide-extension "${{ env.APP_NAME }}.app" \
|
||||
--app-drop-link 450 150 \
|
||||
"dist-final/${{ matrix.artifact_name }}.dmg" \
|
||||
"dist/"
|
||||
fi
|
||||
ls -la dist-final/
|
||||
|
||||
@@ -181,5 +196,5 @@ jobs:
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ matrix.os }}-build
|
||||
path: dist-final/${{ matrix.artifact_name }}
|
||||
path: dist-final/${{ matrix.artifact_name }}*
|
||||
retention-days: 7
|
||||
|
||||
@@ -41,11 +41,11 @@ SoftwareManager is a Python-based GUI tool that simplifies searching and downloa
|
||||
|
||||
<!-- python-dependencies:start -->
|
||||
```text
|
||||
requests (2.33.1)
|
||||
PySide6-Essentials (6.11.0)
|
||||
requests (2.34.2)
|
||||
PySide6-Essentials (6.11.1)
|
||||
beautifulsoup4 (4.14.3)
|
||||
darkdetect (0.7.1)
|
||||
pyinstaller (6.19.0)
|
||||
pyinstaller (6.20.0)
|
||||
PyQtDarkTheme-fork (2.3.6)
|
||||
plyer (2.1.0)
|
||||
psutil (7.2.2)
|
||||
@@ -55,10 +55,6 @@ SoftwareManager is a Python-based GUI tool that simplifies searching and downloa
|
||||
```
|
||||
<!-- python-dependencies:end -->
|
||||
|
||||
## Activity
|
||||
|
||||

|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://www.star-history.com/#KeksPirates/SoftwareManager&type=date&legend=top-left">
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
requests==2.33.1
|
||||
PySide6-Essentials==6.11.0
|
||||
requests==2.34.2
|
||||
PySide6-Essentials==6.11.1
|
||||
beautifulsoup4==4.14.3
|
||||
darkdetect==0.7.1
|
||||
pyinstaller==6.19.0
|
||||
pyinstaller==6.21.0
|
||||
PyQtDarkTheme-fork==2.3.6
|
||||
plyer==2.1.0
|
||||
psutil==7.2.2
|
||||
|
||||
@@ -113,7 +113,7 @@ class SteamripScraper:
|
||||
|
||||
try:
|
||||
consoleLog(f"Found download link: {best}")
|
||||
if "buzzheavier" in best:
|
||||
if "buzzheavier" or "bzzhr" in best:
|
||||
link = scrape_buzzheavier(best)
|
||||
return link
|
||||
elif "gofile" in best:
|
||||
|
||||
@@ -12,7 +12,6 @@ import threading
|
||||
import webbrowser
|
||||
import subprocess
|
||||
import platform
|
||||
import time
|
||||
import os
|
||||
|
||||
|
||||
|
||||
@@ -79,9 +79,8 @@ def settings_dialog(self):
|
||||
|
||||
# Ignore Updates checkbox
|
||||
update_checkbox_container, update_checkbox = create_widget(QCheckBox, "Ignore Updates: ")
|
||||
if platform.system() == "Windows":
|
||||
update_checkbox.setChecked(state.ignore_updates)
|
||||
update_checkbox.toggled.connect(lambda checked: setattr(state, 'ignore_updates', checked))
|
||||
update_checkbox.setChecked(state.ignore_updates)
|
||||
update_checkbox.toggled.connect(lambda checked: setattr(state, 'ignore_updates', checked))
|
||||
|
||||
# Autoresume Container Checkbox
|
||||
autoresume_container, autoresume_checkbox = create_widget(QCheckBox, "Auto-Resume Downloads: ")
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
from PySide6.QtWidgets import QDialog, QMessageBox, QCheckBox
|
||||
from utils.network.update_checker import get_updates
|
||||
from PySide6.QtWidgets import QDialog, QMessageBox
|
||||
from utils.network.updater import download_update
|
||||
from utils.config.config import create_config
|
||||
from utils.logging.logs import consoleLog
|
||||
from utils.data.state import state
|
||||
from pathlib import Path
|
||||
import webbrowser
|
||||
import platform
|
||||
import json
|
||||
import os
|
||||
|
||||
RELEASES_URL = "https://github.com/KeksPirates/SoftwareManager/releases/latest"
|
||||
|
||||
def _get_build_info_path() -> (Path | None):
|
||||
current_dir = Path(__file__).resolve().parent
|
||||
|
||||
@@ -31,19 +35,49 @@ def get_version() -> None:
|
||||
else:
|
||||
consoleLog(f"Could not find build info file (Path: {build_info_path})")
|
||||
|
||||
|
||||
def _show_notify_dialog(latest: str) -> None:
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Icon.Information)
|
||||
msg.setWindowTitle("Update Available")
|
||||
msg.setText(f"A new version is available: <b>{latest}</b>")
|
||||
msg.setInformativeText("Visit the releases page to download it.")
|
||||
|
||||
dont_show = QCheckBox("Don't show again")
|
||||
msg.setCheckBox(dont_show)
|
||||
|
||||
open_btn = msg.addButton("Open Releases Page", QMessageBox.ButtonRole.AcceptRole)
|
||||
msg.addButton("Dismiss", QMessageBox.ButtonRole.RejectRole)
|
||||
|
||||
msg.exec()
|
||||
|
||||
if dont_show.isChecked():
|
||||
state.ignore_updates = True
|
||||
create_config()
|
||||
|
||||
if msg.clickedButton() == open_btn:
|
||||
webbrowser.open(RELEASES_URL)
|
||||
|
||||
|
||||
class UpdateDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
if state.ignore_updates is False and platform.system() == "Windows":
|
||||
if state.ignore_updates:
|
||||
return
|
||||
|
||||
assets, latest = get_updates()
|
||||
if assets != None:
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Icon.Information)
|
||||
msg.setWindowTitle("Update Available")
|
||||
msg.setText(f"A new version is available\n({latest})")
|
||||
msg.setInformativeText("Press Ok to download.")
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Ignore)
|
||||
response = msg.exec_()
|
||||
if response == QMessageBox.StandardButton.Ok:
|
||||
download_update(assets)
|
||||
assets, latest = get_updates()
|
||||
if assets is None:
|
||||
return
|
||||
|
||||
if platform.system() == "Windows":
|
||||
msg = QMessageBox()
|
||||
msg.setIcon(QMessageBox.Icon.Information)
|
||||
msg.setWindowTitle("Update Available")
|
||||
msg.setText(f"A new version is available\n({latest})")
|
||||
msg.setInformativeText("Press Ok to download.")
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Ignore)
|
||||
response = msg.exec_()
|
||||
if response == QMessageBox.StandardButton.Ok:
|
||||
download_update(assets)
|
||||
else:
|
||||
_show_notify_dialog(latest)
|
||||
|
||||
|
||||
@@ -20,12 +20,14 @@ def add_direct_download(url: str, title: str, dl_path: Optional[str] = None, hea
|
||||
consoleLog(f"Download already active: {title}")
|
||||
return
|
||||
|
||||
filename = (
|
||||
raw_filename = (
|
||||
detect_filename_from_headers(url, DirectDownloadHandle.USER_AGENT)
|
||||
or extract_filename_from_url(url)
|
||||
or sanitize_filename(title) + ".zip"
|
||||
)
|
||||
|
||||
filename = sanitize_filename(raw_filename)
|
||||
|
||||
handle = DirectDownloadHandle(url, filename, dl_path, headers, single_threaded)
|
||||
with state.downloads_lock:
|
||||
state.active_downloads[url] = handle
|
||||
|
||||
@@ -10,6 +10,7 @@ import requests
|
||||
import hashlib
|
||||
import json
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
@@ -231,8 +232,24 @@ class DirectDownloadHandle:
|
||||
def _preallocate_file(self, total_size: int):
|
||||
if os.path.exists(self._file_path) and os.path.getsize(self._file_path) == total_size:
|
||||
return
|
||||
|
||||
with open(self._file_path, "wb") as f:
|
||||
f.truncate(total_size)
|
||||
if sys.platform == "win32":
|
||||
import msvcrt
|
||||
import ctypes
|
||||
from ctypes.wintypes import DWORD
|
||||
|
||||
handle = msvcrt.get_osfhandle(f.fileno())
|
||||
kernel32 = ctypes.windll.kernel32
|
||||
|
||||
bytes_returned = DWORD()
|
||||
kernel32.DeviceIoControl(
|
||||
handle, 590020, None, 0, None, 0, ctypes.byref(bytes_returned), None
|
||||
)
|
||||
kernel32.SetFilePointerEx(handle, ctypes.c_int64(total_size), None, 0)
|
||||
kernel32.SetEndOfFile(handle)
|
||||
else:
|
||||
f.truncate(total_size)
|
||||
|
||||
def _compute_chunks(self, total_size: int) -> list[ChunkSpec]:
|
||||
num_chunks = min(self.NUM_THREADS, max(1, total_size // self.MIN_CHUNK_SIZE))
|
||||
|
||||
@@ -34,7 +34,7 @@ def detect_filename_from_headers(url: str, user_agent: str) -> Optional[str]:
|
||||
if "filename=" in cd:
|
||||
parts = cd.split("filename=")
|
||||
if len(parts) > 1:
|
||||
fname = parts[-1].strip().strip('"').strip("'")
|
||||
fname = parts[1].split(";")[0].strip().strip('"').strip("'")
|
||||
if fname:
|
||||
return fname
|
||||
except Exception as e:
|
||||
|
||||
@@ -4,7 +4,6 @@ from PySide6.QtCore import QObject, QTimer
|
||||
from utils.data.state import state
|
||||
from plyer import notification
|
||||
import libtorrent as lt
|
||||
import time
|
||||
import os
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user