mirror of
https://github.com/KeksPirates/SoftwareManager.git
synced 2026-08-03 17:39:42 +02:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 375925e56c | |||
| 0b3c8819de | |||
| 626bb7ff62 | |||
| f10c51f894 | |||
| 6a1f7fa677 | |||
| b573ca8fed | |||
| 8a45d71655 | |||
| 0c7bc426db | |||
| 1f06a19c17 | |||
| da92c4ab0a | |||
| f6e3ff4f27 | |||
| 88042b2d3d | |||
| 9265a9cd1c | |||
| adc9f6f6d4 | |||
| a3a6ef5eec | |||
| 8e5e0425ef | |||
| c2b329aed4 | |||
| c5f2be90af |
+63
-40
@@ -15,7 +15,7 @@ permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: "3.11"
|
||||
PYTHON_VERSION: "3.12"
|
||||
APP_NAME: "SoftwareManager"
|
||||
|
||||
jobs:
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
uv pip install -r requirements.txt
|
||||
uv pip install pyinstaller backports.tarfile pillow
|
||||
uv pip install nuitka
|
||||
env:
|
||||
UV_SYSTEM_PYTHON: 1
|
||||
|
||||
@@ -82,56 +82,79 @@ jobs:
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Build executable with PyInstaller (Windows)
|
||||
- name: Install UPX
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||
curl -sL https://github.com/upx/upx/releases/download/v5.1.0/upx-5.1.0-win64.zip -o upx.zip
|
||||
7z x upx.zip -oupx-dir
|
||||
UPX_DIR="$(pwd)/upx-dir/upx-5.1.0-win64"
|
||||
echo "$UPX_DIR" >> $GITHUB_PATH
|
||||
export PATH="$UPX_DIR:$PATH"
|
||||
echo "UPX_BINARY=$UPX_DIR/upx.exe" >> $GITHUB_ENV
|
||||
elif [ "$RUNNER_OS" == "Linux" ]; then
|
||||
curl -sL https://github.com/upx/upx/releases/download/v5.1.0/upx-5.1.0-amd64_linux.tar.xz -o upx.tar.xz
|
||||
tar xf upx.tar.xz
|
||||
UPX_DIR="$(pwd)/upx-5.1.0-amd64_linux"
|
||||
echo "$UPX_DIR" >> $GITHUB_PATH
|
||||
export PATH="$UPX_DIR:$PATH"
|
||||
echo "UPX_BINARY=$UPX_DIR/upx" >> $GITHUB_ENV
|
||||
else
|
||||
brew install upx
|
||||
echo "UPX_BINARY=$(which upx)" >> $GITHUB_ENV
|
||||
fi
|
||||
upx --version | head -1
|
||||
|
||||
- name: Build with Nuitka (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
pyinstaller --onefile --windowed \
|
||||
--add-data "build_info.json;." \
|
||||
--add-data "build_info.json;core" \
|
||||
--add-data "build_info.json;core/interface" \
|
||||
--add-data "core/interface/assets;core/interface/assets" \
|
||||
--icon "core/interface/assets/logo.png" \
|
||||
--exclude-module PyQt6 \
|
||||
--exclude-module PyQt5 \
|
||||
--hidden-import=backports.tarfile \
|
||||
--hidden-import=backports \
|
||||
--hidden-import=jaraco.context \
|
||||
--hidden-import=jaraco.text \
|
||||
--hidden-import=jaraco.functools \
|
||||
--name ${{ env.APP_NAME }} \
|
||||
python -m nuitka \
|
||||
--onefile \
|
||||
--onefile-no-compression \
|
||||
--onefile-tempdir-spec="{CACHE_DIR}/${{ env.APP_NAME }}/${{ env.VERSION }}" \
|
||||
--assume-yes-for-downloads \
|
||||
--windows-console-mode=disable \
|
||||
--enable-plugin=pyside6 \
|
||||
--enable-plugin=upx \
|
||||
--upx-binary="${{ env.UPX_BINARY }}" \
|
||||
--include-data-dir=core/interface/assets=core/interface/assets \
|
||||
--include-data-files=build_info.json=build_info.json \
|
||||
--include-data-files=build_info.json=core/build_info.json \
|
||||
--include-data-files=build_info.json=core/interface/build_info.json \
|
||||
--output-filename=${{ env.APP_NAME }}.exe \
|
||||
main.py
|
||||
|
||||
- name: Build executable with PyInstaller (Unix)
|
||||
- name: Build with Nuitka (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
pyinstaller --onefile --windowed \
|
||||
--add-data "build_info.json:." \
|
||||
--add-data "build_info.json:core" \
|
||||
--add-data "build_info.json:core/interface" \
|
||||
--add-data "core/interface/assets:core/interface/assets" \
|
||||
--icon "core/interface/assets/logo.png" \
|
||||
--exclude-module PyQt6 \
|
||||
--exclude-module PyQt5 \
|
||||
--hidden-import=backports.tarfile \
|
||||
--hidden-import=backports \
|
||||
--hidden-import=jaraco.context \
|
||||
--hidden-import=jaraco.text \
|
||||
--hidden-import=jaraco.functools \
|
||||
--name ${{ env.APP_NAME }} \
|
||||
python -m nuitka \
|
||||
--onefile \
|
||||
--onefile-no-compression \
|
||||
--onefile-tempdir-spec="{CACHE_DIR}/${{ env.APP_NAME }}/${{ env.VERSION }}" \
|
||||
--assume-yes-for-downloads \
|
||||
--enable-plugin=pyside6 \
|
||||
--enable-plugin=upx \
|
||||
--upx-binary="${{ env.UPX_BINARY }}" \
|
||||
--include-data-dir=core/interface/assets=core/interface/assets \
|
||||
--include-data-files=build_info.json=build_info.json \
|
||||
--include-data-files=build_info.json=core/build_info.json \
|
||||
--include-data-files=build_info.json=core/interface/build_info.json \
|
||||
--output-filename=${{ env.APP_NAME }} \
|
||||
main.py
|
||||
|
||||
- name: Make executable (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
run: chmod +x dist/${{ env.APP_NAME }}
|
||||
|
||||
- name: Rename artifact
|
||||
- name: Prepare artifact
|
||||
shell: bash
|
||||
run: |
|
||||
cd dist
|
||||
mv ${{ env.APP_NAME }}${{ runner.os == 'Windows' && '.exe' || '' }} ${{ matrix.artifact_name }}
|
||||
ls -la
|
||||
mkdir -p dist
|
||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||
mv ${{ env.APP_NAME }}.exe dist/${{ matrix.artifact_name }}
|
||||
else
|
||||
mv ${{ env.APP_NAME }} dist/${{ matrix.artifact_name }}
|
||||
chmod +x dist/${{ matrix.artifact_name }}
|
||||
fi
|
||||
ls -la dist/
|
||||
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# SoftwareManager - A Download Manager/Launcher
|
||||
SoftwareManager is a Python-based GUI/TUI tool that simplifies downloading and managing free software from various sources.
|
||||
# SoftwareManager
|
||||
SoftwareManager is a Python-based GUI tool that simplifies searching and downloading software from various sources, including Rutracker, Uztracker and the official M0nkrus Telegram channel.
|
||||
|
||||
## Features
|
||||
- VPN Binding (impl. soon)
|
||||
- Bandwidth/Download speed limiting
|
||||
- Start downloads via a predefined magnet URI.
|
||||
- View detailed download information (name, speed, and status).
|
||||
- Searching & Downloading Software from various pages
|
||||
- Network Interface Binding
|
||||
- Simple UI, Speed Limiting etc.
|
||||
- No Logins required
|
||||
|
||||
## Installation
|
||||
1. Download the binary file for your operating system from releases
|
||||
@@ -14,18 +14,40 @@ SoftwareManager is a Python-based GUI/TUI tool that simplifies downloading and m
|
||||
|
||||
## Manual Installation
|
||||
1. Ensure Python 3.x is installed on your system.
|
||||
2. Clone the Repository:
|
||||
```bash
|
||||
git clone https://github.com/KeksPirates/SoftwareManager.git && cd SoftwareManager
|
||||
```
|
||||
2. Install Dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
3. Run main.py:
|
||||
```bash
|
||||
python3 main.py
|
||||
python main.py
|
||||
```
|
||||
|
||||
## Notes
|
||||
- If you want to host your own server, clone the server branch of this repo, enter your cookie for rutracker.org and run server.py. Detailed Instructions on how to get your rutracker cookie are in the README of its branch.
|
||||
- This tool is for educational purposes only. Use it responsibly.
|
||||
## Additional Information
|
||||
- SoftwareManager is still in Development and most likely contains issues. Please report any bugs you find via the Issues tab. Contributions are also greatly appreciated.
|
||||
- MacOS Builds haven't been properly tested - We're thankful to receive feedback.
|
||||
- If you want to host your own server, clone the server branch of this repo, enter your cookie for rutracker.org and run server.py. Detailed Instructions on how to get your rutracker cookie are in the README of the server branch.
|
||||
|
||||
## Python Dependencies
|
||||
(also included in requirements.txt)
|
||||
|
||||
```bash
|
||||
requests (2.32.2)
|
||||
PySide6 (6.10.1)
|
||||
beautifulsoup (44.13.5)
|
||||
darkdetect (0.7.1)
|
||||
pyinstaller (6.15.0)
|
||||
PyQtDarkTheme-fork (2.3.4)
|
||||
aiohttp (3.13.0)
|
||||
plyer (2.1.0)
|
||||
psutil (7.1.0)
|
||||
libtorrent (2.0.11)
|
||||
libtorrent-windows-dll (0.0.3)
|
||||
```
|
||||
|
||||
## Activity
|
||||
|
||||
@@ -41,6 +63,11 @@ SoftwareManager is a Python-based GUI/TUI tool that simplifies downloading and m
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## Contributors
|
||||
<a href="https://github.com/KeksPirates/SoftwareManager/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=KeksPirates/SoftwareManager" />
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
**Disclaimer:** SoftwareManager is intended for legal and ethical use only. Ensure compliance with applicable laws and regulations when using this tool.
|
||||
|
||||
@@ -4,7 +4,7 @@ from core.utils.general.logs import consoleLog
|
||||
|
||||
|
||||
def scrape_rutracker(search_text):
|
||||
search = requests.get(f"{state.api_url}/search/{search_text}")
|
||||
search = requests.get(f"{state.api_url}/search?q={search_text}")
|
||||
consoleLog("Sent request to server")
|
||||
if search:
|
||||
try:
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import requests
|
||||
import asyncio
|
||||
import threading
|
||||
from bs4 import BeautifulSoup
|
||||
from core.utils.data.state import state
|
||||
from core.utils.general.logs import consoleLog
|
||||
from core.utils.general.wrappers import run_thread
|
||||
|
||||
|
||||
global url_uztracker
|
||||
url_uztracker = "https://uztracker.net/tracker.php?nm="
|
||||
|
||||
async def init_uztracker():
|
||||
def init_uztracker():
|
||||
global up
|
||||
global soup
|
||||
try:
|
||||
@@ -19,12 +21,12 @@ async def init_uztracker():
|
||||
up = False
|
||||
consoleLog(f"Uztracker seems down, status code: {response.status_code}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
consoleLog(f"\nRequest Exception on {url_uztracker}:")
|
||||
consoleLog(f"Request Exception on {url_uztracker}:")
|
||||
consoleLog(str(e))
|
||||
consoleLog("\nIs the Site down?")
|
||||
consoleLog("Is the Site down?")
|
||||
up = False
|
||||
|
||||
asyncio.run(init_uztracker())
|
||||
run_thread(threading.Thread(target=init_uztracker))
|
||||
|
||||
def scrape_uztracker(search):
|
||||
if up:
|
||||
|
||||
@@ -253,9 +253,9 @@ def settings_dialog(self):
|
||||
layout.addWidget(save_btn)
|
||||
|
||||
self.tabs = QTabWidget()
|
||||
self.tab1 = general_tab("General", autoresume_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.tab3 = network_tab("Network", update_checkbox_container, 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().addLayout(layout)
|
||||
|
||||
+11
-7
@@ -155,10 +155,10 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
||||
# Table Widget for Item List
|
||||
self.qtablewidget = QTableWidget()
|
||||
|
||||
self.qtablewidget.setColumnCount(2)
|
||||
self.qtablewidget.setColumnCount(4)
|
||||
self.qtablewidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
|
||||
self.qtablewidget.verticalHeader().setVisible(False)
|
||||
self.qtablewidget.setHorizontalHeaderLabels(["Post Title", "Author"])
|
||||
self.qtablewidget.setHorizontalHeaderLabels(["Post Title", "Author", "Seeders", "Leechers"])
|
||||
|
||||
|
||||
|
||||
@@ -285,10 +285,13 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
||||
subprocess.Popen(["open", save_path])
|
||||
return
|
||||
|
||||
if status.paused:
|
||||
is_paused = bool(magnetdl.flags() & lt.torrent_flags.paused)
|
||||
if is_paused:
|
||||
magnetdl.set_flags(lt.torrent_flags.auto_managed)
|
||||
magnetdl.resume()
|
||||
consoleLog(f"Resumed download: {status.name}", True)
|
||||
else:
|
||||
magnetdl.unset_flags(lt.torrent_flags.auto_managed)
|
||||
magnetdl.pause()
|
||||
consoleLog(f"Paused download: {status.name}", True)
|
||||
|
||||
@@ -383,16 +386,17 @@ class MainWindow(QtWidgets.QMainWindow, QWidget):
|
||||
|
||||
if state.image_path is not None and os.path.exists(state.image_path):
|
||||
self.image = QImage(state.image_path)
|
||||
self.image = self.image.scaledToWidth(300, Qt.SmoothTransformation)
|
||||
self.pixmap = QPixmap.fromImage(self.image)
|
||||
self.overlay_label = QLabel(self)
|
||||
self.overlay_label.setPixmap(self.pixmap)
|
||||
self.overlay_label.adjustSize()
|
||||
self.overlay_label.raise_()
|
||||
|
||||
offset_x = -1350
|
||||
offset_y = -550
|
||||
x = self.width() - self.overlay_label.width() - offset_x
|
||||
y = self.height() - self.overlay_label.height() - offset_y
|
||||
# offset_x = -1350
|
||||
# offset_y = -550
|
||||
x = self.width() - self.overlay_label.width() # - offset_x
|
||||
y = self.height() - self.overlay_label.height() # - offset_y
|
||||
self.overlay_label.move(x, y)
|
||||
|
||||
# temporarily disabled
|
||||
|
||||
@@ -3,7 +3,7 @@ from core.utils.general.logs import consoleLog
|
||||
from core.data.scrapers.uztracker import scrape_uztracker
|
||||
from core.data.scrapers.rutracker import scrape_rutracker
|
||||
from core.data.scrapers.monkrus import scrape_monkrus_telegram
|
||||
from core.utils.network.jsonhandler import split_data, format_data
|
||||
from core.utils.network.jsonhandler import split_data, format_data, format_data_m0nkrus
|
||||
from core.utils.data.state import state
|
||||
|
||||
def return_pressed(self):
|
||||
@@ -44,15 +44,19 @@ def return_pressed(self):
|
||||
self.qtablewidget.clear()
|
||||
self.show_empty_results(True)
|
||||
else:
|
||||
state.post_titles, _, state.post_author = format_data(state.posts)
|
||||
state.post_titles, _, state.post_author, state.post_seeders, state.post_leechers = format_data(state.posts)
|
||||
self.show_empty_results(False)
|
||||
self.qtablewidget.clear()
|
||||
self.qtablewidget.setHorizontalHeaderLabels(["Post Title", "Author"])
|
||||
self.qtablewidget.setHorizontalHeaderLabels(["Post Title", "Author", "Seeders", "Leechers"])
|
||||
self.qtablewidget.setRowCount(len(state.post_titles))
|
||||
for i, author in enumerate(state.post_author):
|
||||
self.qtablewidget.setItem(i, 1, QTableWidgetItem(author))
|
||||
for i, title in enumerate(state.post_titles):
|
||||
self.qtablewidget.setItem(i, 0, QTableWidgetItem(title))
|
||||
for i, seeders in enumerate(state.post_seeders):
|
||||
self.qtablewidget.setItem(i, 2, QTableWidgetItem(seeders))
|
||||
for i, leechers in enumerate(state.post_leechers):
|
||||
self.qtablewidget.setItem(i, 3, QTableWidgetItem(leechers))
|
||||
if state.debug == True:
|
||||
consoleLog(f"Response Cached: {cached}")
|
||||
else:
|
||||
@@ -68,7 +72,7 @@ def return_pressed(self):
|
||||
self.qtablewidget.clear()
|
||||
self.show_empty_results(True)
|
||||
else:
|
||||
state.post_titles, _, state.post_author = format_data(state.posts)
|
||||
state.post_titles, _, state.post_author = format_data_m0nkrus(state.posts)
|
||||
self.show_empty_results(False)
|
||||
self.qtablewidget.clear()
|
||||
self.qtablewidget.setHorizontalHeaderLabels(["Post Title", "Author"])
|
||||
|
||||
@@ -19,10 +19,11 @@ def create_tab(title, searchbar, software_list, tabs, dlbutton, layout2):
|
||||
#################
|
||||
# SETTINGS TABS #
|
||||
#################
|
||||
def general_tab(title, autoresume, transparent_window, tabs):
|
||||
def general_tab(title, autoresume, update_checkbox, transparent_window, tabs):
|
||||
tab = QWidget()
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(autoresume)
|
||||
layout.addWidget(update_checkbox)
|
||||
layout.addWidget(transparent_window)
|
||||
layout.addStretch()
|
||||
tab.setLayout(layout)
|
||||
@@ -40,10 +41,9 @@ def paths_tab(title, download_path, image_path, tabs):
|
||||
return tab
|
||||
|
||||
|
||||
def network_tab(title, update_checkbox, network_interface, max_connections, max_downloads, up_speed_limit, down_speed_limit, api_url, tabs):
|
||||
def network_tab(title, network_interface, max_connections, max_downloads, up_speed_limit, down_speed_limit, api_url, tabs):
|
||||
tab = QWidget()
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(update_checkbox)
|
||||
layout.addWidget(network_interface)
|
||||
layout.addWidget(max_connections)
|
||||
layout.addWidget(max_downloads)
|
||||
|
||||
@@ -36,7 +36,7 @@ def init_session():
|
||||
settings["listen_interfaces"] = f"{interface_ip}:6881"
|
||||
consoleLog(f"Binding to Interface IP: {interface_ip}")
|
||||
else:
|
||||
consoleLog(f"Error finding IP for Interface {state.bound_interface}")
|
||||
consoleLog(f"Skipping Binding, no Interface set. ({state.bound_interface})")
|
||||
|
||||
state.dl_session.apply_settings(settings)
|
||||
|
||||
@@ -51,7 +51,7 @@ def add_download(magnet_uri, dl_path=state.download_path):
|
||||
init_session()
|
||||
|
||||
if magnet_uri in state.active_downloads:
|
||||
consoleLog("Skipping, download already running...")
|
||||
consoleLog("Skipping Downloading, download already running...")
|
||||
return
|
||||
|
||||
magnetdl = lt.parse_magnet_uri(magnet_uri)
|
||||
@@ -114,7 +114,7 @@ def update_settings():
|
||||
settings["listen_interfaces"] = f"{interface_ip}:6881"
|
||||
consoleLog(f"Binding to Interface IP: {interface_ip}")
|
||||
else:
|
||||
consoleLog(f"Error finding IP for Interface {state.bound_interface}")
|
||||
consoleLog(f"Skipping Binding, no Interface set. ({state.bound_interface})")
|
||||
|
||||
state.dl_session.apply_settings(settings)
|
||||
|
||||
|
||||
+27
-14
@@ -8,16 +8,23 @@ def create_config():
|
||||
|
||||
config["General"] = {
|
||||
"debug": True,
|
||||
"ignore_updates": f"{state.ignore_updates}",
|
||||
"autoresume": f"{state.autoresume}",
|
||||
"window_transparency": f"{state.window_transparency}"
|
||||
}
|
||||
|
||||
config["Network"] = {
|
||||
"api_url": f"{state.api_url}",
|
||||
"download_path": f"{state.download_path}",
|
||||
"download_speed_limit": f"{state.down_speed_limit}",
|
||||
"upload_speed_limit": f"{state.up_speed_limit}",
|
||||
"ignore_updates": f"{state.ignore_updates}",
|
||||
"image_path": f"{state.image_path}",
|
||||
"autoresume": f"{state.autoresume}",
|
||||
"upload_speed_limit": f"{state.up_speed_limit}",
|
||||
"max_connections": f"{state.max_connections}",
|
||||
"max_downloads": f"{state.max_downloads}",
|
||||
"window_transparency": f"{state.window_transparency}",
|
||||
"max_downloads": f"{state.max_downloads}"
|
||||
}
|
||||
|
||||
config["Paths"] = {
|
||||
"bound_interface": f"{state.bound_interface}",
|
||||
"image_path": f"{state.image_path}"
|
||||
}
|
||||
|
||||
if platform.system() == "Windows":
|
||||
@@ -48,17 +55,23 @@ def read_config():
|
||||
return
|
||||
|
||||
config.read(config_file)
|
||||
|
||||
|
||||
# General
|
||||
state.debug = config.getboolean("General", "debug", fallback=state.debug)
|
||||
state.api_url = config.get("General", "api_url", fallback=state.api_url)
|
||||
state.download_path = config.get("General", "download_path", fallback=state.download_path)
|
||||
state.down_speed_limit = config.getint("General", "download_speed_limit", fallback=state.down_speed_limit)
|
||||
state.up_speed_limit = config.getint("General", "upload_speed_limit", fallback=state.up_speed_limit)
|
||||
state.ignore_updates = config.getboolean("General", "ignore_updates", fallback=state.ignore_updates)
|
||||
state.image_path = config.get("General", "image_path", fallback=state.image_path)
|
||||
state.autoresume = config.getboolean("General", "autoresume", fallback=state.autoresume)
|
||||
state.max_connections = config.getint("General", "max_connections", fallback=state.max_connections)
|
||||
state.max_downloads = config.getint("General", "max_downloads", fallback=state.max_downloads)
|
||||
state.window_transparency = config.getboolean("General", "window_transparency", fallback=state.window_transparency)
|
||||
|
||||
# Network
|
||||
state.api_url = config.get("Network", "api_url", fallback=state.api_url)
|
||||
state.download_path = config.get("Network", "download_path", fallback=state.download_path)
|
||||
state.down_speed_limit = config.getint("Network", "download_speed_limit", fallback=state.down_speed_limit)
|
||||
state.up_speed_limit = config.getint("Network", "upload_speed_limit", fallback=state.up_speed_limit)
|
||||
state.max_connections = config.getint("Network", "max_connections", fallback=state.max_connections)
|
||||
state.max_downloads = config.getint("Network", "max_downloads", fallback=state.max_downloads)
|
||||
|
||||
# Paths
|
||||
state.bound_interface = config.get("Paths", "bound_interface", fallback=state.bound_interface)
|
||||
state.image_path = config.get("Paths", "image_path", fallback=state.image_path)
|
||||
|
||||
create_config()
|
||||
|
||||
@@ -11,6 +11,8 @@ class AppState(QObject):
|
||||
self.post_titles: List[str] = []
|
||||
self.post_urls: List[str] = []
|
||||
self.post_author: List[str] = []
|
||||
self.post_seeders: List[str] = []
|
||||
self.post_leechers: List[str] = []
|
||||
self.version: str = "dev"
|
||||
self._image_path: str = ""
|
||||
self.ignore_updates: bool = False
|
||||
|
||||
@@ -15,12 +15,12 @@ def get_item_url(item, posts, post_titles): # softwarelist currentitem, post lis
|
||||
return item
|
||||
if state.tracker == "rutracker":
|
||||
item_dict = posts[post_index]
|
||||
_, post_links, _ = format_data([item_dict])
|
||||
_, post_links, _, _, _ = format_data([item_dict])
|
||||
consoleLog(f"Found post URL: {post_links[0]}")
|
||||
return post_links[0]
|
||||
if state.tracker == "m0nkrus":
|
||||
item_dict = posts[post_index]
|
||||
_, post_links, _ = format_data([item_dict])
|
||||
_, post_links, _, _, _,= format_data([item_dict])
|
||||
consoleLog(f"Found post URL: {post_links[0]}")
|
||||
return post_links[0]
|
||||
|
||||
|
||||
@@ -24,7 +24,12 @@ def add_download_log(title, url, magnet_uri, completed) -> DownloadList:
|
||||
|
||||
|
||||
if any(d.magnet_uri == magnet_uri or d.url == url for d in downloads):
|
||||
consoleLog("Skipped Logging, download already in file")
|
||||
if magnet_uri in state.active_downloads:
|
||||
consoleLog("Skipping Logging, download already running...")
|
||||
return
|
||||
consoleLog("File already in Log, updating Download State...")
|
||||
hash = extract_hash_from_magnet(magnet_uri)
|
||||
update_download_completed_by_hash(hash, False)
|
||||
return DownloadList(data=downloads, count=len(downloads)) # thanks again claude (im stupid)
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,16 @@ def split_data(data):
|
||||
|
||||
return count, posts, query, success, cached
|
||||
|
||||
def format_data(data):
|
||||
def format_data(data):
|
||||
post_author = [post["author"] for post in data]
|
||||
post_titles = [post["title"] for post in data]
|
||||
post_links = [post["url"] for post in data]
|
||||
post_seeders = [post["seeders"] for post in data]
|
||||
post_leechers = [post["leechers"] for post in data]
|
||||
|
||||
return post_titles, post_links, post_author, post_seeders, post_leechers
|
||||
|
||||
def format_data_m0nkrus(data):
|
||||
post_author = [post["author"] for post in data]
|
||||
post_titles = [post["title"] for post in data]
|
||||
post_links = [post["url"] for post in data]
|
||||
@@ -20,4 +29,7 @@ def format_data(data):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# https://open.spotify.com/track/70vjXI7oBou5buTtgiJeRW?si=25640cc4243c4bf3
|
||||
|
||||
@@ -17,6 +17,7 @@ import platform
|
||||
import signal
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -41,16 +42,17 @@ def keyboardinterrupthandler(signum, frame):
|
||||
closehelper()
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_time = time.perf_counter()
|
||||
read_config()
|
||||
logs = get_download_logs()
|
||||
count, downloads = split_data(logs)
|
||||
_, downloads = split_data(logs)
|
||||
if args.debug:
|
||||
state.debug = args.debug # override of read_config
|
||||
signal.signal(signal.SIGINT, keyboardinterrupthandler)
|
||||
consoleLog("Starting SoftwareManager...")
|
||||
consoleLog("Fetching Network Interfaces...")
|
||||
list_interfaces()
|
||||
consoleLog("Initialiting Interface variables...")
|
||||
consoleLog("Initializing Interface variables...")
|
||||
init_interfaces()
|
||||
consoleLog(f"Current Bound: {state.bound_interface}")
|
||||
run_thread(threading.Thread(target=send_notification, args=(shutdown_event,), daemon=True))
|
||||
@@ -59,6 +61,7 @@ if __name__ == "__main__":
|
||||
consoleLog("Started Thread: update_log")
|
||||
run_thread(threading.Thread(target=check_completed, args=(downloads, state.autoresume)))
|
||||
consoleLog("Started Thread: check_completed")
|
||||
consoleLog("Launching GUI")
|
||||
elapsed = time.perf_counter() - start_time
|
||||
consoleLog(f"Initialization completed in {elapsed:.2f}s. Launching GUI")
|
||||
run_gui()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user