Quality of life update (already lol), added a bunch of things + bug fixes

This commit is contained in:
faroukbmiled 2023-07-31 21:44:31 +01:00
parent dc2bfebc03
commit f9407f9e41

View File

@ -2,18 +2,18 @@ import os
import sys import sys
import subprocess import subprocess
import configparser import configparser
import filecmp
import json import json
import shutil import shutil
import zipfile
import psutil import psutil
import requests import requests
import time import time
import threading import threading
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QMessageBox, QHBoxLayout, QProgressBar, QSizePolicy from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QMessageBox, QHBoxLayout, QProgressBar, QSizePolicy, QFileDialog
from PyQt5.QtCore import Qt, QThread, pyqtSignal from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtCore import QCoreApplication from PyQt5.QtCore import QCoreApplication
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon, QPixmap
import webbrowser import webbrowser
import qdarktheme import qdarktheme
@ -28,6 +28,15 @@ def cwd():
else: else:
return os.path.dirname(os.path.abspath(__file__)) return os.path.dirname(os.path.abspath(__file__))
def check_steamcmd():
steamcmd_path = get_steamcmd_path()
steamcmd_exe_path = os.path.join(steamcmd_path, "steamcmd.exe")
if not os.path.exists(steamcmd_exe_path):
return False
return True
def convert_speed(speed_bytes): def convert_speed(speed_bytes):
if speed_bytes < 1024: if speed_bytes < 1024:
return speed_bytes, "B/s" return speed_bytes, "B/s"
@ -92,11 +101,17 @@ def get_file_size(url):
return file_size return file_size
return None return None
def get_workshop_file_size(workshop_id): def get_workshop_file_size(workshop_id, raw=None):
url = f"https://steamcommunity.com/sharedfiles/filedetails/?id={workshop_id}&searchtext=" url = f"https://steamcommunity.com/sharedfiles/filedetails/?id={workshop_id}&searchtext="
response = requests.get(url) response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser") soup = BeautifulSoup(response.text, "html.parser")
file_size_element = soup.find("div", class_="detailsStatRight") file_size_element = soup.find("div", class_="detailsStatRight")
if raw:
file_size_text = file_size_element.get_text(strip=True)
file_size_text = file_size_text.replace(",", "")
return file_size_text
if file_size_element: if file_size_element:
file_size_text = file_size_element.get_text(strip=True) file_size_text = file_size_element.get_text(strip=True)
file_size_text = file_size_text.replace(",", "") file_size_text = file_size_text.replace(",", "")
@ -175,12 +190,13 @@ def download_workshop_map(workshop_id, destination_folder, progress_bar, speed_l
except Exception as E: except Exception as E:
print(f"Error copying files: {E}") print(f"Error copying files: {E}")
show_message("Download Complete", f"{mod_type} files are downloaded at {folder_name_path}") show_message("Download Complete", f"{mod_type} files are downloaded at {folder_name_path}", icon=QMessageBox.Information)
def show_message(title, message): def show_message(title, message, icon=QMessageBox.Warning):
msg = QMessageBox() msg = QMessageBox()
msg.setWindowTitle(title) msg.setWindowTitle(title)
msg.setText(message) msg.setText(message)
msg.setIcon(icon)
msg.exec_() msg.exec_()
class DownloadThread(QThread): class DownloadThread(QThread):
@ -201,10 +217,55 @@ class WorkshopDownloaderApp(QWidget):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.initUI() self.initUI()
if not check_steamcmd():
self.show_warning_message()
self.download_thread = None self.download_thread = None
self.button_download.setEnabled(True) self.button_download.setEnabled(True)
self.button_stop.setEnabled(False) self.button_stop.setEnabled(False)
def show_warning_message(self):
msg_box = QMessageBox(self)
msg_box.setWindowTitle("Warning")
msg_box.setWindowIcon(QIcon('ryuk.ico'))
msg_box.setText("steamcmd.exe was not found in the specified directory.\nPress Download to get it or Press OK and select it from there!.")
msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
download_button = msg_box.addButton("Download", QMessageBox.AcceptRole)
download_button.clicked.connect(self.download_steamcmd)
result = msg_box.exec_()
if result == QMessageBox.Cancel:
sys.exit(0)
def download_steamcmd(self):
steamcmd_url = "https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"
steamcmd_zip_path = os.path.join(cwd(), "steamcmd.zip")
try:
response = requests.get(steamcmd_url)
response.raise_for_status()
with open(steamcmd_zip_path, "wb") as zip_file:
zip_file.write(response.content)
with zipfile.ZipFile(steamcmd_zip_path, "r") as zip_ref:
zip_ref.extractall(cwd())
if check_steamcmd():
show_message("Success", "SteamCMD has been downloaded and extracted.", icon=QMessageBox.Information)
os.remove(steamcmd_zip_path)
else:
show_message("Error", "Failed to find steamcmd.exe after extraction.")
os.remove(steamcmd_zip_path)
except requests.exceptions.RequestException as e:
show_message("Error", f"Failed to download SteamCMD: {e}")
os.remove(steamcmd_zip_path)
except zipfile.BadZipFile:
show_message("Error", "Failed to extract SteamCMD. The downloaded file might be corrupted.")
os.remove(steamcmd_zip_path)
def initUI(self): def initUI(self):
self.setWindowTitle('BOIII Workshop Downloader') self.setWindowTitle('BOIII Workshop Downloader')
self.setWindowIcon(QIcon('ryuk.ico')) self.setWindowIcon(QIcon('ryuk.ico'))
@ -224,20 +285,47 @@ class WorkshopDownloaderApp(QWidget):
layout.addLayout(browse_layout) layout.addLayout(browse_layout)
info_workshop_layout = QHBoxLayout()
self.edit_workshop_id = QLineEdit() self.edit_workshop_id = QLineEdit()
layout.addWidget(self.edit_workshop_id) self.edit_workshop_id.setPlaceholderText("Workshop ID => Press info to see map/mod info")
info_workshop_layout.addWidget(self.edit_workshop_id, 3)
layout.addLayout(info_workshop_layout)
self.info_button = QPushButton("Info")
self.info_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.info_button.clicked.connect(self.show_map_info)
info_workshop_layout.addWidget(self.info_button, 1)
self.label_destination_folder = QLabel("Enter Your BOIII folder:") self.label_destination_folder = QLabel("Enter Your BOIII folder:")
layout.addWidget(self.label_destination_folder) layout.addWidget(self.label_destination_folder, 3)
Boiii_Input = QHBoxLayout()
self.edit_destination_folder = QLineEdit() self.edit_destination_folder = QLineEdit()
layout.addWidget(self.edit_destination_folder) self.edit_destination_folder.setPlaceholderText("Your BOIII Instalation folder")
Boiii_Input.addWidget(self.edit_destination_folder, 90)
layout.addLayout(Boiii_Input)
self.button_BOIII_browse = QPushButton("Select")
self.button_BOIII_browse.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.button_BOIII_browse.clicked.connect(self.open_BOIII_browser)
Boiii_Input.addWidget(self.button_BOIII_browse, 10)
self.label_steamcmd_path = QLabel("Enter SteamCMD path (default):") self.label_steamcmd_path = QLabel("Enter SteamCMD path (default):")
layout.addWidget(self.label_steamcmd_path) layout.addWidget(self.label_steamcmd_path)
steamcmd_path = QHBoxLayout()
self.edit_steamcmd_path = QLineEdit() self.edit_steamcmd_path = QLineEdit()
layout.addWidget(self.edit_steamcmd_path) steamcmd_path.addWidget(self.edit_steamcmd_path, 90)
self.button_steamcmd_browse = QPushButton("Select")
self.button_steamcmd_browse.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.button_steamcmd_browse.clicked.connect(self.open_steamcmd_path_browser)
steamcmd_path.addWidget(self.button_steamcmd_browse, 10)
layout.addLayout(steamcmd_path)
layout.addSpacing(10)
buttons_layout = QHBoxLayout() buttons_layout = QHBoxLayout()
@ -253,11 +341,21 @@ class WorkshopDownloaderApp(QWidget):
layout.addLayout(buttons_layout) layout.addLayout(buttons_layout)
InfoBar = QHBoxLayout()
self.label_speed = QLabel("Network Speed: 0 KB/s") self.label_speed = QLabel("Network Speed: 0 KB/s")
layout.addWidget(self.label_speed) InfoBar.addWidget(self.label_speed, 3)
self.label_file_size = QLabel("File size: 0KB")
InfoBar.addWidget(self.label_file_size, 1)
InfoWidget = QWidget()
InfoWidget.setLayout(InfoBar)
layout.addWidget(InfoWidget)
self.progress_bar = QProgressBar() self.progress_bar = QProgressBar()
layout.addWidget(self.progress_bar) layout.addWidget(self.progress_bar, 75)
self.setLayout(layout) self.setLayout(layout)
@ -267,9 +365,20 @@ class WorkshopDownloaderApp(QWidget):
global stopped global stopped
stopped = False stopped = False
if not check_steamcmd():
self.show_warning_message()
return
steamcmd_path = get_steamcmd_path()
steamcmd_exe_path = os.path.join(steamcmd_path, "steamcmd.exe")
steamcmd_size = os.path.getsize(steamcmd_exe_path)
if steamcmd_size < 3 * 1024 * 1024:
show_message("Warning", "Please wait a bit until SteamCMD downloads and initializes. It might take some time, but it will only happen once.", icon=QMessageBox.Warning)
workshop_id = self.edit_workshop_id.text() workshop_id = self.edit_workshop_id.text()
destination_folder = self.edit_destination_folder.text() destination_folder = self.edit_destination_folder.text()
steamcmd_path = self.edit_steamcmd_path.text() steamcmd_path = self.edit_steamcmd_path.text()
self.label_file_size.setText(f"File size: {get_workshop_file_size(workshop_id, raw=True)}")
if not destination_folder: if not destination_folder:
show_message("Error", "Please select a destination folder.") show_message("Error", "Please select a destination folder.")
@ -300,11 +409,24 @@ class WorkshopDownloaderApp(QWidget):
self.button_stop.setEnabled(False) self.button_stop.setEnabled(False)
self.progress_bar.setValue(0) self.progress_bar.setValue(0)
self.label_speed.setText(f"Network Speed: {0:.2f} KB/s") self.label_speed.setText(f"Network Speed: {0:.2f} KB/s")
self.label_file_size.setText(f"File size: 0KB")
def open_BOIII_browser(self):
selected_folder = QFileDialog.getExistingDirectory(self, "Select BOIII Folder", "")
if selected_folder:
self.edit_destination_folder.setText(selected_folder)
def open_steamcmd_path_browser(self):
selected_folder = QFileDialog.getExistingDirectory(self, "Select SteamCMD Folder", "")
if selected_folder:
self.edit_steamcmd_path.setText(selected_folder)
def on_download_finished(self): def on_download_finished(self):
self.button_download.setEnabled(True) self.button_download.setEnabled(True)
self.progress_bar.setValue(0) self.progress_bar.setValue(0)
self.label_speed.setText(f"Network Speed: {0:.2f} KB/s") self.label_speed.setText(f"Network Speed: {0:.2f} KB/s")
self.label_file_size.setText(f"File size: 0KB")
self.button_stop.setEnabled(False)
self.save_config(self.edit_destination_folder.text(), self.edit_steamcmd_path.text()) self.save_config(self.edit_destination_folder.text(), self.edit_steamcmd_path.text())
def open_browser(self): def open_browser(self):
@ -330,6 +452,72 @@ class WorkshopDownloaderApp(QWidget):
with open(CONFIG_FILE_PATH, "w") as config_file: with open(CONFIG_FILE_PATH, "w") as config_file:
config.write(config_file) config.write(config_file)
def show_map_info(self):
workshop_id = self.edit_workshop_id.text()
if not workshop_id:
QMessageBox.warning(self, "Warning", "Please enter a Workshop ID first.")
return
self.label_file_size.setText(f"File size: {get_workshop_file_size(workshop_id, raw=True)}")
try:
url = f"https://steamcommunity.com/sharedfiles/filedetails/?id={workshop_id}"
response = requests.get(url)
response.raise_for_status()
content = response.text
soup = BeautifulSoup(content, "html.parser")
map_mod_type = soup.find("div", class_="rightDetailsBlock").text.strip()
map_name = soup.find("div", class_="workshopItemTitle").text.strip()
map_size = soup.find("div", class_="detailsStatRight").text.strip()
stars_div = soup.find("div", class_="fileRatingDetails")
stars = stars_div.find("img")["src"]
try:
preview_image_element = soup.find("img", id="previewImage")
workshop_item_image_url = preview_image_element["src"]
except:
preview_image_element = soup.find("img", id="previewImageMain")
workshop_item_image_url = preview_image_element["src"]
image_response = requests.get(workshop_item_image_url)
image_response.raise_for_status()
stars_response = requests.get(stars)
stars_response.raise_for_status()
pixmap = QPixmap()
pixmap.loadFromData(image_response.content)
pixmap_stars = QPixmap()
pixmap_stars.loadFromData(stars_response.content)
label = QLabel(self)
label.setPixmap(pixmap)
label.setAlignment(Qt.AlignCenter)
label_stars = QLabel(self)
label_stars.setPixmap(pixmap_stars)
label_stars.setAlignment(Qt.AlignCenter)
msg_box = QMessageBox(self)
msg_box.setWindowTitle("Map/Mod Information")
msg_box.setIconPixmap(pixmap)
msg_box.setText(f"Name: {map_name}\nType: {map_mod_type}\nSize: {map_size}")
layout = QVBoxLayout()
layout.addWidget(label)
layout.addWidget(label_stars)
msg_box.setLayout(layout)
msg_box.setStandardButtons(QMessageBox.Ok)
msg_box.setDetailedText(f"Stars: {stars}\nLink: {url}")
msg_box.exec_()
except requests.exceptions.RequestException as e:
QMessageBox.warning(self, "Error", f"Failed to fetch map information.\nError: {e}")
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) app = QApplication(sys.argv)
qdarktheme.setup_theme() qdarktheme.setup_theme()