This commit is contained in:
faroukbmiled 2023-08-19 01:05:04 +01:00
parent 237a6df9a5
commit 50cf36b345

View File

@ -1,7 +1,6 @@
from CTkMessagebox import CTkMessagebox from CTkMessagebox import CTkMessagebox
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import customtkinter as ctk import customtkinter as ctk
from pathlib import Path
from CTkToolTip import * from CTkToolTip import *
from PIL import Image from PIL import Image
import configparser import configparser
@ -25,6 +24,7 @@ GITHUB_REPO = "faroukbmiled/BOIIIWD"
LATEST_RELEASE_URL = "https://github.com/faroukbmiled/BOIIIWD/releases/latest/download/Release.zip" LATEST_RELEASE_URL = "https://github.com/faroukbmiled/BOIIIWD/releases/latest/download/Release.zip"
UPDATER_FOLDER = "update" UPDATER_FOLDER = "update"
CONFIG_FILE_PATH = "config.ini" CONFIG_FILE_PATH = "config.ini"
RESOURCES_DIR = os.path.join(os.path.dirname(__file__), 'resources')
# fuck it we ball, ill get rid of globals when i finish everything cant be bothered rn # fuck it we ball, ill get rid of globals when i finish everything cant be bothered rn
global stopped, steampid, console, clean_on_finish, continuous, estimated_progress global stopped, steampid, console, clean_on_finish, continuous, estimated_progress
@ -254,10 +254,10 @@ def save_config(name, value):
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 extract_json_data(json_path): def extract_json_data(json_path, key):
with open(json_path, "r") as json_file: with open(json_path, "r") as json_file:
data = json.load(json_file) data = json.load(json_file)
return data["Type"], data["FolderName"] return data[key]
def convert_bytes_to_readable(size_in_bytes, no_symb=None): def convert_bytes_to_readable(size_in_bytes, no_symb=None):
for unit in ['B', 'KB', 'MB', 'GB', 'TB']: for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
@ -328,6 +328,14 @@ def convert_seconds(seconds):
hours, minutes = divmod(minutes, 60) hours, minutes = divmod(minutes, 60)
return hours, minutes, seconds return hours, minutes, seconds
def get_folder_size(folder_path):
total_size = 0
for dirpath, dirnames, filenames in os.walk(folder_path):
for filename in filenames:
file_path = os.path.join(dirpath, filename)
total_size += os.path.getsize(file_path)
return total_size
# End helper functions # End helper functions
class UpdateWindow(ctk.CTkToplevel): class UpdateWindow(ctk.CTkToplevel):
@ -337,7 +345,7 @@ class UpdateWindow(ctk.CTkToplevel):
super().__init__(master) super().__init__(master)
self.title("BOIIIWD Self-Updater") self.title("BOIIIWD Self-Updater")
self.geometry("400x150") self.geometry("400x150")
self.after(250, lambda: self.iconbitmap('ryuk.ico')) self.after(250, lambda: self.iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico")))
self.protocol("WM_DELETE_WINDOW", self.cancel_update) self.protocol("WM_DELETE_WINDOW", self.cancel_update)
self.attributes('-topmost', 'true') self.attributes('-topmost', 'true')
@ -432,21 +440,292 @@ class UpdateWindow(ctk.CTkToplevel):
self.up_cancelled = True self.up_cancelled = True
self.withdraw() self.withdraw()
class LibraryTab(ctk.CTkFrame): class LibraryTab(ctk.CTkScrollableFrame):
def __init__(self, master=None): def __init__(self, master, **kwargs):
super().__init__(master)
# Left and right frames, use fg_color="transparent" super().__init__(master, **kwargs)
self.grid_rowconfigure(0, weight=1) self.added_items = set()
self.grid_columnconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1)
left_frame = ctk.CTkFrame(self)
left_frame.grid(row=0, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") self.radiobutton_variable = ctk.StringVar()
left_frame.grid_columnconfigure(1, weight=1) self.label_list = []
right_frame = ctk.CTkFrame(self) self.button_list = []
right_frame.grid(row=0, column=1, padx=(20, 20), pady=(20, 0), sticky="nsew") self.button_view_list = []
right_frame.grid_columnconfigure(1, weight=1) self.filter_type = True
self.update_idletasks()
def add_item(self, item, image=None, item_type="map", workshop_id=None, folder=None):
label = ctk.CTkLabel(self, text=item, image=image, compound="left", padx=5, anchor="w")
button = ctk.CTkButton(self, text="Remove", width=60, height=24)
button_view = ctk.CTkButton(self, text="Details", width=60, height=24)
button.configure(command=lambda: self.remove_item(item, folder))
button_view.configure(command=lambda: self.show_map_info(workshop_id))
button_view_tooltip = CTkToolTip(button_view, message="Opens up a window that shows basic details")
button_tooltip = CTkToolTip(button, message="Removes the map/mod from your game")
label.grid(row=len(self.label_list) + 1, column=0, pady=(0, 10), padx=(5, 10), sticky="w")
button.grid(row=len(self.button_list) + 1, column=2, pady=(0, 10), padx=(0, 10))
button_view.grid(row=len(self.button_view_list) + 1, column=1, pady=(0, 10), padx=(0, 10))
self.label_list.append(label)
self.button_list.append(button)
self.button_view_list.append(button_view)
def filter_items(self, event):
filter_text = self.filter_entry.get().lower()
for label, button, button_view_list in zip(self.label_list, self.button_list, self.button_view_list):
item_text = label.cget("text").lower()
if filter_text in item_text:
label.grid()
button.grid()
button_view_list.grid()
else:
label.grid_remove()
button_view_list.grid_remove()
button.grid_remove()
def load_items(self, boiiiFolder):
# if you add this under init the whole app shrinks for some reason
global boiiiFolderGlobal
boiiiFolderGlobal = boiiiFolder
self.filter_entry = ctk.CTkEntry(self, placeholder_text="Your search query here, or type in mod or map to see only that")
self.filter_entry.bind("<KeyRelease>", self.filter_items)
self.filter_entry.grid(row=0, column=0, padx=(10, 20), pady=(10, 20), sticky="we")
filter_refresh_button_image = os.path.join(RESOURCES_DIR, "Refresh_icon.svg.png")
self.filter_refresh_button = ctk.CTkButton(self, image=ctk.CTkImage(Image.open(filter_refresh_button_image)), command=self.refresh_items, width=60, height=24,
fg_color="transparent", text="")
self.filter_refresh_button.grid(row=0, column=1, sticky="e")
maps_folder = os.path.join(boiiiFolder, "mods")
mods_folder = os.path.join(boiiiFolder, "usermaps")
folders_to_process = [maps_folder, mods_folder]
for folder_path in folders_to_process:
for root, _, _ in os.walk(folder_path):
zone_path = os.path.join(root, "zone")
if os.path.exists(zone_path):
json_path = os.path.join(zone_path, "workshop.json")
if os.path.exists(json_path):
name = extract_json_data(json_path, "Title").replace(">", "").replace("^", "")
name = name[:24] + "..." if len(name) > 24 else name
item_type = extract_json_data(json_path, "Type")
workshop_id = extract_json_data(json_path, "PublisherID")
size = convert_bytes_to_readable(get_folder_size(root))
text_to_add = f"Name: {name} | Type: {item_type} | ID: {workshop_id} | Size: {size}"
if text_to_add not in self.added_items:
self.added_items.add(text_to_add)
if item_type == "mod":
image_path = os.path.join(RESOURCES_DIR, "rtaImage.png")
else:
image_path = os.path.join(RESOURCES_DIR, "103248.png")
self.add_item(text_to_add, image=ctk.CTkImage(Image.open(image_path)), item_type=item_type, workshop_id=workshop_id, folder=root)
if not self.added_items:
self.show_no_items_message()
else:
self.hide_no_items_message()
def remove_item(self, item, folder):
for label, button, button_view_list in zip(self.label_list, self.button_list, self.button_view_list):
if item == label.cget("text"):
try:
shutil.rmtree(folder)
except Exception as e:
show_message("Error" ,f"Error removing folder '{folder}': {e}", icon="cancel")
return
label.destroy()
button.destroy()
button_view_list.destroy()
self.label_list.remove(label)
self.button_list.remove(button)
self.button_view_list.remove(button_view_list)
def refresh_items(self):
for label, button, button_view_list in zip(self.label_list, self.button_list, self.button_view_list):
label.destroy()
button.destroy()
button_view_list.destroy()
self.label_list.clear()
self.button_list.clear()
self.button_view_list.clear()
self.added_items.clear()
self.load_items(boiiiFolderGlobal)
def view_item(self, workshop_id):
url = f"https://steamcommunity.com/sharedfiles/filedetails/?id={workshop_id}"
webbrowser.open(url)
def show_no_items_message(self):
self.no_items_label = ctk.CTkLabel(self, text="", anchor="w")
self.no_items_label.grid(row=1, column=0, padx=10, pady=(0, 10), sticky="n")
self.no_items_label.configure(text="No items found in the selected folder. \nMake sure you have a mod/map downloaded and or have the right boiii folder selected.")
def hide_no_items_message(self):
try:
self.no_items_label.configure(text="")
except:
pass
# i know i know ,please make a pull request i cant be bother
def show_map_info(self, workshop):
for button_view in self.button_view_list:
button_view.configure(state="disabled")
def show_map_thread():
workshop_id = workshop
if not workshop_id.isdigit():
try:
if extract_workshop_id(workshop_id).strip().isdigit():
workshop_id = extract_workshop_id(workshop_id).strip()
else:
show_message("Warning", "Not a valid Workshop ID.")
except:
show_message("Warning", "Not a valid Workshop ID.")
return
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")
try:
map_mod_type = soup.find("div", class_="rightDetailsBlock").text.strip()
map_name = soup.find("div", class_="workshopItemTitle").text.strip()
map_size = map_size = get_workshop_file_size(workshop_id, raw=True)
details_stats_container = soup.find("div", class_="detailsStatsContainerRight")
details_stat_elements = details_stats_container.find_all("div", class_="detailsStatRight")
date_created = details_stat_elements[1].text.strip()
try:
ratings = soup.find('div', class_='numRatings')
ratings_text = ratings.get_text()
except:
ratings = "Not found"
ratings_text= "Not enough ratings"
try:
date_updated = details_stat_elements[2].text.strip()
except:
date_updated = "Not updated"
stars_div = soup.find("div", class_="fileRatingDetails")
starts = stars_div.find("img")["src"]
except:
show_message("Warning", "Not a valid Workshop ID\nCouldn't get information.")
for button_view in self.button_view_list:
button_view.configure(state="normal")
return
try:
preview_image_element = soup.find("img", id="previewImage")
workshop_item_image_url = preview_image_element["src"]
except:
try:
preview_image_element = soup.find("img", id="previewImageMain")
workshop_item_image_url = preview_image_element["src"]
except Exception as e:
show_message("Warning", f"Failed to get preview image ,probably wrong link/id if not please open an issue on github.\n{e}")
for button_view in self.button_view_list:
button_view.configure(state="normal")
return
starts_image_response = requests.get(starts)
stars_image = Image.open(io.BytesIO(starts_image_response.content))
stars_image_size = stars_image.size
image_response = requests.get(workshop_item_image_url)
image_response.raise_for_status()
image = Image.open(io.BytesIO(image_response.content))
image_size = image.size
self.toplevel_info_window(map_name, map_mod_type, map_size, image, image_size, date_created ,
date_updated, stars_image, stars_image_size, ratings_text, url)
except requests.exceptions.RequestException as e:
show_message("Error", f"Failed to fetch map information.\nError: {e}", icon="cancel")
for button_view in self.button_view_list:
button_view.configure(state="normal")
return
info_thread = threading.Thread(target=show_map_thread)
info_thread.start()
def toplevel_info_window(self, map_name, map_mod_type, map_size, image, image_size,
date_created ,date_updated, stars_image, stars_image_size, ratings_text, url):
try:
top = ctk.CTkToplevel(self)
top.after(210, lambda: top.iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico")))
top.title("Map/Mod Information")
top.attributes('-topmost', 'true')
def close_window():
top.destroy()
def view_map_mod():
webbrowser.open(url)
# frames
stars_frame = ctk.CTkFrame(top)
stars_frame.grid(row=0, column=0, columnspan=2, padx=20, pady=(20, 0), sticky="nsew")
stars_frame.columnconfigure(0, weight=0)
stars_frame.rowconfigure(0, weight=1)
image_frame = ctk.CTkFrame(top)
image_frame.grid(row=1, column=0, columnspan=2, padx=20, pady=0, sticky="nsew")
info_frame = ctk.CTkFrame(top)
info_frame.grid(row=2, column=0, columnspan=2, padx=20, pady=20, sticky="nsew")
buttons_frame = ctk.CTkFrame(top)
buttons_frame.grid(row=3, column=0, columnspan=2, padx=20, pady=(0, 20), sticky="nsew")
# fillers
name_label = ctk.CTkLabel(info_frame, text=f"Name: {map_name}")
name_label.grid(row=0, column=0, columnspan=2, sticky="w", padx=20, pady=5)
type_label = ctk.CTkLabel(info_frame, text=f"Type: {map_mod_type}")
type_label.grid(row=1, column=0, columnspan=2, sticky="w", padx=20, pady=5)
size_label = ctk.CTkLabel(info_frame, text=f"Size: {map_size}")
size_label.grid(row=2, column=0, columnspan=2, sticky="w", padx=20, pady=5)
date_created_label = ctk.CTkLabel(info_frame, text=f"Posted: {date_created}")
date_created_label.grid(row=3, column=0, columnspan=2, sticky="w", padx=20, pady=5)
date_updated_label = ctk.CTkLabel(info_frame, text=f"Updated: {date_updated}")
date_updated_label.grid(row=4, column=0, columnspan=2, sticky="w", padx=20, pady=5)
stars_image_label = ctk.CTkLabel(stars_frame)
stars_width, stars_height = stars_image_size
stars_image_widget = ctk.CTkImage(stars_image, size=(int(stars_width), int(stars_height)))
stars_image_label.configure(image=stars_image_widget, text="")
stars_image_label.pack(side="left", padx=(10, 20), pady=(10, 10))
ratings = ctk.CTkLabel(stars_frame)
ratings.configure(text=ratings_text)
ratings.pack(side="right", padx=(10, 20), pady=(10, 10))
image_label = ctk.CTkLabel(image_frame)
width, height = image_size
image_widget = ctk.CTkImage(image, size=(int(width), int(height)))
image_label.configure(image=image_widget, text="")
image_label.pack(expand=True, fill="both", padx=(10, 20), pady=(10, 10))
# Buttons
close_button = ctk.CTkButton(buttons_frame, text="View", command=view_map_mod)
close_button.pack(side="left", padx=(10, 20), pady=(10, 10))
view_button = ctk.CTkButton(buttons_frame, text="Close", command=close_window)
view_button.pack(side="right", padx=(10, 20), pady=(10, 10))
top.grid_rowconfigure(0, weight=0)
top.grid_rowconfigure(1, weight=0)
top.grid_rowconfigure(2, weight=1)
top.grid_columnconfigure(0, weight=1)
top.grid_columnconfigure(1, weight=1)
finally:
for button_view in self.button_view_list:
button_view.configure(state="normal")
class SettingsTab(ctk.CTkFrame): class SettingsTab(ctk.CTkFrame):
def __init__(self, master=None): def __init__(self, master=None):
@ -630,7 +909,7 @@ class BOIIIWD(ctk.CTk):
# configure window # configure window
self.title("BOIII Workshop Downloader - Main") self.title("BOIII Workshop Downloader - Main")
self.geometry(f"{910}x{560}") self.geometry(f"{910}x{560}")
self.wm_iconbitmap('ryuk.ico') self.wm_iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico"))
self.protocol("WM_DELETE_WINDOW", self.on_closing) self.protocol("WM_DELETE_WINDOW", self.on_closing)
# configure grid layout (4x4) # configure grid layout (4x4)
@ -638,10 +917,11 @@ class BOIIIWD(ctk.CTk):
self.grid_columnconfigure((2, 3), weight=0) self.grid_columnconfigure((2, 3), weight=0)
self.grid_rowconfigure((0, 1, 2), weight=1) self.grid_rowconfigure((0, 1, 2), weight=1)
self.settings_tab = SettingsTab(self) self.settings_tab = SettingsTab(self)
self.library_tab = LibraryTab(self) self.library_tab = LibraryTab(self, corner_radius=3)
# create sidebar frame with widgets # create sidebar frame with widgets
self.sidebar_icon = ctk.CTkImage(light_image=Image.open("ryuk.png"), dark_image=Image.open("ryuk.png"), size=(40, 40)) ryuks_icon = os.path.join(RESOURCES_DIR, "ryuk.png")
self.sidebar_icon = ctk.CTkImage(light_image=Image.open(ryuks_icon), dark_image=Image.open(ryuks_icon), size=(40, 40))
self.sidebar_frame = ctk.CTkFrame(self, width=140, corner_radius=10) self.sidebar_frame = ctk.CTkFrame(self, width=140, corner_radius=10)
self.sidebar_frame.grid(row=0, column=0, rowspan=4, padx=(10, 10), pady=(10, 10), sticky="nsew") self.sidebar_frame.grid(row=0, column=0, rowspan=4, padx=(10, 10), pady=(10, 10), sticky="nsew")
self.sidebar_frame.grid_rowconfigure(4, weight=1) self.sidebar_frame.grid_rowconfigure(4, weight=1)
@ -759,7 +1039,7 @@ class BOIIIWD(ctk.CTk):
self.sidebar_library.configure(text="Library", command=self.library_button_event) self.sidebar_library.configure(text="Library", command=self.library_button_event)
self.sidebar_queue.configure(state="disabled", text="Queue") self.sidebar_queue.configure(state="disabled", text="Queue")
self.sidebar_settings.configure(command=self.settings_button_event, text="Settings") self.sidebar_settings.configure(command=self.settings_button_event, text="Settings")
self.sidebar_library_tooltip = CTkToolTip(self.sidebar_library, message="Beta") self.sidebar_library_tooltip = CTkToolTip(self.sidebar_library, message="Experimental")
self.sidebar_queue_tooltip = CTkToolTip(self.sidebar_queue, message="Coming soon") self.sidebar_queue_tooltip = CTkToolTip(self.sidebar_queue, message="Coming soon")
# load ui configs # load ui configs
@ -803,9 +1083,6 @@ class BOIIIWD(ctk.CTk):
ctk.set_widget_scaling(new_scaling_float) ctk.set_widget_scaling(new_scaling_float)
save_config("scaling", str(new_scaling_float)) save_config("scaling", str(new_scaling_float))
def sidebar_button_event(self):
print("sidebar_button click")
def hide_main_widgets(self): def hide_main_widgets(self):
self.optionsframe.grid_forget() self.optionsframe.grid_forget()
self.slider_progressbar_frame.grid_forget() self.slider_progressbar_frame.grid_forget()
@ -828,6 +1105,7 @@ class BOIIIWD(ctk.CTk):
def show_library_widgets(self): def show_library_widgets(self):
self.title("BOIII Workshop Downloader - Library") self.title("BOIII Workshop Downloader - Library")
self.library_tab.load_items(self.edit_destination_folder.get())
self.library_tab.grid(row=0, rowspan=3, column=1, padx=(20, 20), pady=(20, 20), sticky="nsew") self.library_tab.grid(row=0, rowspan=3, column=1, padx=(20, 20), pady=(20, 20), sticky="nsew")
def main_button_event(self): def main_button_event(self):
@ -879,6 +1157,8 @@ class BOIIIWD(ctk.CTk):
scaling_float = float(new_scaling)*100 scaling_float = float(new_scaling)*100
scaling_int = math.trunc(scaling_float) scaling_int = math.trunc(scaling_float)
self.scaling_optionemenu.set(f"{scaling_int}%") self.scaling_optionemenu.set(f"{scaling_int}%")
self.edit_steamcmd_path.delete(0, "end")
self.edit_steamcmd_path.insert(0, cwd())
create_default_config() create_default_config()
def open_BOIII_browser(self): def open_BOIII_browser(self):
@ -963,7 +1243,6 @@ class BOIIIWD(ctk.CTk):
except: except:
show_message("Warning", "Please enter a valid Workshop ID.") show_message("Warning", "Please enter a valid Workshop ID.")
return return
print(self.button_download._state)
if self.button_download._state == "normal": if self.button_download._state == "normal":
self.after(1, lambda mid=workshop_id: self.label_file_size.configure(text=f"File size: {get_workshop_file_size(mid ,raw=True)}")) self.after(1, lambda mid=workshop_id: self.label_file_size.configure(text=f"File size: {get_workshop_file_size(mid ,raw=True)}"))
@ -1023,6 +1302,7 @@ class BOIIIWD(ctk.CTk):
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
show_message("Error", f"Failed to fetch map information.\nError: {e}", icon="cancel") show_message("Error", f"Failed to fetch map information.\nError: {e}", icon="cancel")
return
info_thread = threading.Thread(target=show_map_thread) info_thread = threading.Thread(target=show_map_thread)
info_thread.start() info_thread.start()
@ -1030,7 +1310,7 @@ class BOIIIWD(ctk.CTk):
def toplevel_info_window(self, map_name, map_mod_type, map_size, image, image_size, def toplevel_info_window(self, map_name, map_mod_type, map_size, image, image_size,
date_created ,date_updated, stars_image, stars_image_size, ratings_text, url): date_created ,date_updated, stars_image, stars_image_size, ratings_text, url):
top = ctk.CTkToplevel(self) top = ctk.CTkToplevel(self)
top.after(210, lambda: top.iconbitmap("ryuk.ico")) top.after(210, lambda: top.iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico")))
top.title("Map/Mod Information") top.title("Map/Mod Information")
top.attributes('-topmost', 'true') top.attributes('-topmost', 'true')
@ -1136,6 +1416,16 @@ class BOIIIWD(ctk.CTk):
destination_folder = self.edit_destination_folder.get().strip() destination_folder = self.edit_destination_folder.get().strip()
ws_file_size = get_workshop_file_size(workshop_id) ws_file_size = get_workshop_file_size(workshop_id)
if not destination_folder or not os.path.exists(destination_folder):
show_message("Error", "Please select a valid destination folder.")
self.stop_download
return
if not steamcmd_path or not os.path.exists(steamcmd_path):
show_message("Error", "Please enter a valid SteamCMD path.")
self.stop_download
return
if not workshop_id.isdigit(): if not workshop_id.isdigit():
try: try:
if extract_workshop_id(workshop_id).strip().isdigit(): if extract_workshop_id(workshop_id).strip().isdigit():
@ -1161,16 +1451,6 @@ class BOIIIWD(ctk.CTk):
self.stop_download self.stop_download
return return
if not destination_folder or not os.path.exists(destination_folder):
show_message("Error", "Please select a valid destination folder.")
self.stop_download
return
if not steamcmd_path or not os.path.exists(steamcmd_path):
show_message("Error", "Please enter a valid SteamCMD path.")
self.stop_download
return
self.after(1, lambda mid=workshop_id: self.label_file_size.configure(text=f"File size: {get_workshop_file_size(mid ,raw=True)}")) self.after(1, lambda mid=workshop_id: self.label_file_size.configure(text=f"File size: {get_workshop_file_size(mid ,raw=True)}"))
download_folder = os.path.join(get_steamcmd_path(), "steamapps", "workshop", "downloads", "311210", workshop_id) download_folder = os.path.join(get_steamcmd_path(), "steamapps", "workshop", "downloads", "311210", workshop_id)
map_folder = os.path.join(get_steamcmd_path(), "steamapps", "workshop", "content", "311210", workshop_id) map_folder = os.path.join(get_steamcmd_path(), "steamapps", "workshop", "content", "311210", workshop_id)
@ -1222,11 +1502,11 @@ class BOIIIWD(ctk.CTk):
elapsed_hours, elapsed_minutes, elapsed_seconds = convert_seconds(time_elapsed) elapsed_hours, elapsed_minutes, elapsed_seconds = convert_seconds(time_elapsed)
print(f"raw_net {raw_net_speed}\ncurrent_net_speed: {current_net_speed}\nest_downloaded_bytes {est_downloaded_bytes}\npercentage_complete {percentage_complete}\nprogress {progress}") # print(f"raw_net {raw_net_speed}\ncurrent_net_speed: {current_net_speed}\nest_downloaded_bytes {est_downloaded_bytes}\npercentage_complete {percentage_complete}\nprogress {progress}")
self.after(1, self.progress_bar.set(progress)) self.after(1, self.progress_bar.set(progress))
self.after(1, lambda v=net_speed: self.label_speed.configure(text=f"Network Speed: {v:.2f} {speed_unit}")) self.after(1, lambda v=net_speed: self.label_speed.configure(text=f"Network Speed: {v:.2f} {speed_unit}"))
self.after(1, lambda p=percentage_complete: self.progress_text.configure(text=f"{p:.2f}%")) self.after(1, lambda p=min(percentage_complete ,99): self.progress_text.configure(text=f"{p:.2f}%"))
self.after(1, lambda h=elapsed_hours, m=elapsed_minutes, s=elapsed_seconds: self.elapsed_time.configure(text=f"Elapsed Time: {int(h):02d}:{int(m):02d}:{int(s):02d}")) self.after(1, lambda h=elapsed_hours, m=elapsed_minutes, s=elapsed_seconds: self.elapsed_time.configure(text=f"Elapsed Time: {int(h):02d}:{int(m):02d}:{int(s):02d}"))
time.sleep(1) time.sleep(1)
@ -1270,7 +1550,8 @@ class BOIIIWD(ctk.CTk):
json_file_path = os.path.join(map_folder, "workshop.json") json_file_path = os.path.join(map_folder, "workshop.json")
if os.path.exists(json_file_path): if os.path.exists(json_file_path):
mod_type, folder_name = extract_json_data(json_file_path) mod_type = extract_json_data(json_file_path, "Type")
folder_name = extract_json_data(json_file_path, "FolderName")
if mod_type == "mod": if mod_type == "mod":
mods_folder = os.path.join(destination_folder, "mods") mods_folder = os.path.join(destination_folder, "mods")
@ -1279,7 +1560,7 @@ class BOIIIWD(ctk.CTk):
usermaps_folder = os.path.join(destination_folder, "usermaps") usermaps_folder = os.path.join(destination_folder, "usermaps")
folder_name_path = os.path.join(usermaps_folder, folder_name, "zone") folder_name_path = os.path.join(usermaps_folder, folder_name, "zone")
else: else:
show_message("Error", "Invalid map type in workshop.json.", icon="cancel") show_message("Error", "Invalid workshop type in workshop.json, are you sure this is a map or a mod?.", icon="cancel")
self.stop_download self.stop_download
return return