commit
cc8234d8f8
Binary file not shown.
BIN
boiiiwd_package/resources/default_library_img.png
Normal file
BIN
boiiiwd_package/resources/default_library_img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -25,6 +25,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
self.update_button = ctk.CTkButton(self, image=ctk.CTkImage(Image.open(update_button_image)), command=self.check_for_updates, width=65, height=20,
|
||||
text="", fg_color="transparent")
|
||||
self.update_button.grid(row=0, column=1, padx=(0, 20), pady=(10, 20), sticky="en")
|
||||
self.update_button.configure(state="disabled")
|
||||
self.update_tooltip = CTkToolTip(self.update_button, message="Check items for updates", topmost=True)
|
||||
filter_tooltip = CTkToolTip(self.filter_refresh_button, message="Refresh library", topmost=True)
|
||||
self.label_list = []
|
||||
@ -221,6 +222,15 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
button_view_list.grid_remove()
|
||||
button.grid_remove()
|
||||
|
||||
def add_item_helper(self, text, image_path, workshop_id, folder, invalid_warn=False, item_type=None):
|
||||
image = ctk.CTkImage(Image.open(image_path))
|
||||
self.add_item(text, image=image, workshop_id=workshop_id, folder=folder, invalid_warn=invalid_warn)
|
||||
|
||||
# sort by type then alphabet (name), index 5 is type 0 is name/text
|
||||
def sorting_key(self, item):
|
||||
item_type, item_name = item[5], item[0]
|
||||
return (0, item_name) if item_type == "map" else (1, item_name)
|
||||
|
||||
def load_items(self, boiiiFolder, dont_add=False):
|
||||
if self.refresh_next_time and not dont_add:
|
||||
self.refresh_next_time = False
|
||||
@ -244,6 +254,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
total_size = 0
|
||||
|
||||
folders_to_process = [mods_folder, maps_folder]
|
||||
ui_items_to_add = []
|
||||
|
||||
items_file = os.path.join(application_path, LIBRARY_FILE)
|
||||
if not self.is_valid_json_format(items_file):
|
||||
@ -303,9 +314,9 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
|
||||
self.added_items.add(text_to_add)
|
||||
if image_path is b_mod_img or image_path is b_map_img and not dont_add:
|
||||
self.add_item(text_to_add, image=ctk.CTkImage(Image.open(image_path)), workshop_id=workshop_id, folder=zone_path.parent, invalid_warn=True)
|
||||
ui_items_to_add.append((text_to_add, image_path, workshop_id, zone_path.parent, True, item_type))
|
||||
elif not dont_add:
|
||||
self.add_item(text_to_add, image=ctk.CTkImage(Image.open(image_path)), workshop_id=workshop_id, folder=zone_path.parent)
|
||||
ui_items_to_add.append((text_to_add, image_path, workshop_id, zone_path.parent, False, item_type))
|
||||
id_found, folder_found = self.item_exists_in_file(items_file, workshop_id, curr_folder_name)
|
||||
item_info = {
|
||||
"id": workshop_id,
|
||||
@ -338,6 +349,11 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
if not workshop_id in self.ids_added and curr_folder_name not in self.item_block_list:
|
||||
self.ids_added.add(workshop_id)
|
||||
|
||||
# sort items by type then alphabet
|
||||
ui_items_to_add.sort(key=self.sorting_key)
|
||||
for item in ui_items_to_add:
|
||||
self.add_item_helper(*item)
|
||||
|
||||
if not self.file_cleaned and os.path.exists(items_file):
|
||||
self.file_cleaned = True
|
||||
self.clean_json_file(items_file)
|
||||
@ -347,8 +363,13 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
else:
|
||||
self.hide_no_items_message()
|
||||
|
||||
if all(item in self.item_block_list for item in self.added_folders):
|
||||
self.show_no_items_message(only_up=True)
|
||||
|
||||
if map_count > 0 or mod_count > 0:
|
||||
return f"Maps: {map_count} - Mods: {mod_count} - Total size: {convert_bytes_to_readable(total_size)}"
|
||||
|
||||
self.show_no_items_message(only_up=True)
|
||||
return "No items in current selected folder"
|
||||
|
||||
def update_item(self, boiiiFolder, id, item_type, foldername):
|
||||
@ -444,11 +465,17 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
url = f"https://steamcommunity.com/sharedfiles/filedetails/?id={workshop_id}"
|
||||
webbrowser.open(url)
|
||||
|
||||
def show_no_items_message(self):
|
||||
def show_no_items_message(self, only_up=False):
|
||||
self.update_button.configure(state="disabled")
|
||||
self.update_tooltip.configure(message="Updater Disabled, No items found")
|
||||
if only_up:
|
||||
return
|
||||
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):
|
||||
self.update_tooltip.configure(message="Check items for updates")
|
||||
self.update_button.configure(state="normal")
|
||||
self.no_items_label.configure(text="")
|
||||
self.no_items_label.forget()
|
||||
|
||||
@ -473,6 +500,11 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
for button_view in self.button_view_list:
|
||||
button_view.configure(state="normal")
|
||||
# return
|
||||
|
||||
json_path = Path(folder) / "zone" / "workshop.json"
|
||||
folder_size_bytes = get_folder_size(json_path.parent.parent)
|
||||
map_size = convert_bytes_to_readable(folder_size_bytes)
|
||||
|
||||
if online and valid_id!=False:
|
||||
try:
|
||||
url = f"https://steamcommunity.com/sharedfiles/filedetails/?id={workshop_id}"
|
||||
@ -486,7 +518,6 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
type_txt = soup.find("div", class_="rightDetailsBlock").text.strip()
|
||||
map_mod_type = type_txt if "File Size" not in type_txt else "Not specified"
|
||||
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()
|
||||
@ -545,7 +576,6 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
button_view.configure(state="normal")
|
||||
return
|
||||
else:
|
||||
json_path = Path(folder) / "zone" / "workshop.json"
|
||||
creation_timestamp = None
|
||||
for ff_file in json_path.parent.glob("*.ff"):
|
||||
if ff_file.exists():
|
||||
@ -559,13 +589,11 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
name = re.sub(r'\^\w+', '', extract_json_data(json_path, "Title")) or "None"
|
||||
map_name = name[:45] + "..." if len(name) > 45 else name
|
||||
map_mod_type = extract_json_data(json_path, "Type") or "None"
|
||||
folder_size_bytes = get_folder_size(json_path.parent.parent)
|
||||
map_size = convert_bytes_to_readable(folder_size_bytes)
|
||||
preview_iamge = json_path.parent / "previewimage.png"
|
||||
if preview_iamge.exists():
|
||||
image = Image.open(preview_iamge)
|
||||
else:
|
||||
image = Image.open(os.path.join(RESOURCES_DIR, "ryuk.png"))
|
||||
image = Image.open(os.path.join(RESOURCES_DIR, "default_library_img.png"))
|
||||
image_size = image.size
|
||||
offline_date = datetime.fromtimestamp(creation_timestamp).strftime("%d %b, %Y @ %I:%M%p")
|
||||
date_updated = "Offline"
|
||||
@ -589,7 +617,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
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,
|
||||
def toplevel_info_window(self, map_name, map_mod_type_txt, map_size, image, image_size,
|
||||
date_created ,date_updated, stars_image, stars_image_size, ratings_text,
|
||||
url, workshop_id, invalid_warn, folder, description ,online,offline_date=None):
|
||||
def main_thread():
|
||||
@ -599,12 +627,14 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
if os.path.exists(os.path.join(RESOURCES_DIR, "ryuk.ico")):
|
||||
top.after(210, lambda: top.iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico")))
|
||||
top.title("Map/Mod Information")
|
||||
top.attributes('-topmost', 'true')
|
||||
size_text = "Size (Workshop):"
|
||||
_, _, x, y = get_window_size_from_registry()
|
||||
top.geometry(f"+{x+50}+{y-50}")
|
||||
top.maxsize(450, 10000)
|
||||
top.minsize(300, 500)
|
||||
# top.attributes('-topmost', 'true')
|
||||
|
||||
if offline_date:
|
||||
down_date = offline_date
|
||||
size_text = "Size (On Disk):"
|
||||
else:
|
||||
down_date = self.get_item_by_id(items_file, workshop_id, 'date')
|
||||
|
||||
@ -661,6 +691,15 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
except:
|
||||
show_message("Up to date!", "No updates found!", icon="info")
|
||||
|
||||
def show_full_text(event, widget, full_text):
|
||||
widget_text = type_label.cget("text")
|
||||
label_type = widget_text.split(':')[0]
|
||||
# + 30 which is desc_threshold + 5 is the ... dots and a white space
|
||||
if len(widget_text) == len(label_type) + 30 + 5:
|
||||
widget.configure(text=f"{label_type}: {full_text}")
|
||||
else:
|
||||
widget.configure(text=f"{label_type}: {full_text[:30]}...")
|
||||
|
||||
# frames
|
||||
stars_frame = ctk.CTkFrame(top)
|
||||
stars_frame.grid(row=0, column=0, columnspan=2, padx=20, pady=(20, 0), sticky="nsew")
|
||||
@ -677,32 +716,37 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
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)
|
||||
name_label = ctk.CTkLabel(info_frame, text=f"Name: {map_name}", wraplength=420, justify="left")
|
||||
name_label.grid(row=0, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
desc_threshold = 30
|
||||
shortened_description = re.sub(r'\n', '', description).strip()
|
||||
shortened_description = re.sub(r'[\\/\n\r]', '', description).strip()
|
||||
shortened_description = re.sub(r'([^a-zA-Z0-9\s:().])', '', shortened_description)
|
||||
shortened_description = f"{shortened_description[:desc_threshold]}... (View)"\
|
||||
if len(shortened_description) > desc_threshold else shortened_description
|
||||
description_lab = ctk.CTkLabel(info_frame, text=f"Description: {shortened_description}")
|
||||
description_lab.grid(row=1, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
description_lab.grid(row=1, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
if len(description) > desc_threshold:
|
||||
description_lab_tooltip = CTkToolTip(description_lab, message="View description", topmost=True)
|
||||
description_lab.configure(cursor="hand2")
|
||||
description_lab.bind("<Button-1>", lambda e: show_description(e))
|
||||
|
||||
id_label = ctk.CTkLabel(info_frame, text=f"ID: {workshop_id} | Folder: {os.path.basename(folder)}")
|
||||
id_label.grid(row=2, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
id_label.grid(row=2, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
type_label = ctk.CTkLabel(info_frame, text=f"Type: {map_mod_type}")
|
||||
type_label.grid(row=3, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
map_mod_type = map_mod_type_txt[:desc_threshold] + "..." if len(map_mod_type_txt) > desc_threshold else map_mod_type_txt
|
||||
type_label = ctk.CTkLabel(info_frame, text=f"Type: {map_mod_type}", wraplength=350, justify="left")
|
||||
type_label.grid(row=3, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
if len(map_mod_type) > desc_threshold:
|
||||
type_label_tooltip = CTkToolTip(type_label, message="View all types", topmost=True)
|
||||
type_label.configure(cursor="hand2")
|
||||
type_label.bind("<Button-1>", lambda e: show_full_text(e, type_label, map_mod_type_txt))
|
||||
|
||||
size_label = ctk.CTkLabel(info_frame, text=f"{size_text} {map_size}")
|
||||
size_label.grid(row=4, 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=4, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
date_created_label = ctk.CTkLabel(info_frame, text=f"Posted: {date_created}")
|
||||
date_created_label.grid(row=5, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
date_created_label.grid(row=5, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
if date_updated != "Not updated" and date_updated != "Offline":
|
||||
date_updated_label = ctk.CTkLabel(info_frame, text=f"Updated: {date_updated} 🔗")
|
||||
@ -712,10 +756,10 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
webbrowser.open(f"https://steamcommunity.com/sharedfiles/filedetails/changelog/{workshop_id}"))
|
||||
else:
|
||||
date_updated_label = ctk.CTkLabel(info_frame, text=f"Updated: {date_updated}")
|
||||
date_updated_label.grid(row=6, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
date_updated_label.grid(row=6, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
date_updated_label = ctk.CTkLabel(info_frame, text=f"Downloaded at: {down_date}")
|
||||
date_updated_label.grid(row=7, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
date_updated_label = ctk.CTkLabel(info_frame, text=f"Downloaded: {down_date}")
|
||||
date_updated_label.grid(row=7, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
stars_image_label = ctk.CTkLabel(stars_frame)
|
||||
stars_width, stars_height = stars_image_size
|
||||
@ -728,13 +772,11 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
ratings.pack(side="right", padx=(10, 20), pady=(10, 10))
|
||||
|
||||
image_label = ctk.CTkLabel(image_frame)
|
||||
width, height = image_size
|
||||
max_width = 300
|
||||
i_width, i_height = tuple([int(max_width/image_size[0] * x) for x in image_size])
|
||||
# preview image is too big if offline, // to round floats
|
||||
if width > 1000 or height > 1000:
|
||||
width = width // 2
|
||||
height = height // 2
|
||||
|
||||
image_widget = ctk.CTkImage(image, size=(int(width), int(height)))
|
||||
image_widget = ctk.CTkImage(image, size=(int(i_width), int(i_height)))
|
||||
image_label.configure(image=image_widget, text="")
|
||||
image_label.pack(expand=True, fill="both", padx=(10, 20), pady=(10, 10))
|
||||
|
||||
@ -777,9 +819,10 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
buttons_frame.grid_columnconfigure(2, weight=1)
|
||||
|
||||
finally:
|
||||
top.after(10, top.focus_force)
|
||||
for button_view in self.button_view_list:
|
||||
button_view.configure(state="normal")
|
||||
self.after(0, main_thread)
|
||||
main_app.app.after(0, main_thread)
|
||||
|
||||
@if_internet_available
|
||||
def check_for_updates(self, on_launch=False):
|
||||
@ -835,20 +878,24 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
||||
return
|
||||
|
||||
def check_for_update():
|
||||
lib_data = None
|
||||
try:
|
||||
lib_data = None
|
||||
|
||||
if not os.path.exists(os.path.join(application_path, LIBRARY_FILE)):
|
||||
show_message("Error checking for item updates! -> Setting is on", "Please visit library tab at least once with the correct boiii path!, you also need to have at lease 1 item!")
|
||||
if not os.path.exists(os.path.join(application_path, LIBRARY_FILE)):
|
||||
show_message("Error checking for item updates! -> Setting is on", "Please visit library tab at least once with the correct boiii path!, you also need to have at lease 1 item!")
|
||||
return
|
||||
|
||||
with open(LIBRARY_FILE, 'r') as file:
|
||||
lib_data = json.load(file)
|
||||
|
||||
for item in lib_data:
|
||||
item_id = item["id"]
|
||||
item_date = item["date"]
|
||||
if_id_needs_update(item_id, item_date, item["text"])
|
||||
except:
|
||||
show_message("Error checking for item updates!", "Please visit library tab at least once with the correct boiii path!, you also need to have at lease 1 item!")
|
||||
return
|
||||
|
||||
with open(LIBRARY_FILE, 'r') as file:
|
||||
lib_data = json.load(file)
|
||||
|
||||
for item in lib_data:
|
||||
item_id = item["id"]
|
||||
item_date = item["date"]
|
||||
if_id_needs_update(item_id, item_date, item["text"])
|
||||
|
||||
check_for_update()
|
||||
|
||||
to_update_len = len(self.to_update)
|
||||
|
@ -650,14 +650,18 @@ class BOIIIWD(ctk.CTk):
|
||||
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,
|
||||
def toplevel_info_window(self, map_name, map_mod_type_txt, map_size, image, image_size,
|
||||
date_created ,date_updated, stars_image, stars_image_size,
|
||||
ratings_text, url, workshop_id, description):
|
||||
def main_thread():
|
||||
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')
|
||||
_, _, x, y = get_window_size_from_registry()
|
||||
top.geometry(f"+{x+50}+{y-50}")
|
||||
top.maxsize(450, 10000)
|
||||
top.minsize(300, 500)
|
||||
# top.attributes('-topmost', 'true')
|
||||
|
||||
def close_window():
|
||||
top.destroy()
|
||||
@ -693,6 +697,15 @@ class BOIIIWD(ctk.CTk):
|
||||
|
||||
self.after(0, main_thread)
|
||||
|
||||
def show_full_text(event, widget, full_text):
|
||||
widget_text = type_label.cget("text")
|
||||
label_type = widget_text.split(':')[0]
|
||||
# + 30 which is desc_threshold + 5 is the ... dots and a white space
|
||||
if len(widget_text) == len(label_type) + 30 + 5:
|
||||
widget.configure(text=f"{label_type}: {full_text}")
|
||||
else:
|
||||
widget.configure(text=f"{label_type}: {full_text[:30]}...")
|
||||
|
||||
# frames
|
||||
stars_frame = ctk.CTkFrame(top)
|
||||
stars_frame.grid(row=0, column=0, columnspan=2, padx=20, pady=(20, 0), sticky="nsew")
|
||||
@ -709,29 +722,34 @@ class BOIIIWD(ctk.CTk):
|
||||
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)
|
||||
name_label = ctk.CTkLabel(info_frame, text=f"Name: {map_name}", wraplength=420, justify="left")
|
||||
name_label.grid(row=0, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
desc_threshold = 30
|
||||
shortened_description = re.sub(r'\n', '', description).strip()
|
||||
shortened_description = re.sub(r'[\\/\n\r]', '', description).strip()
|
||||
shortened_description = re.sub(r'([^a-zA-Z0-9\s:().])', '', shortened_description)
|
||||
shortened_description = f"{shortened_description[:desc_threshold]}... (View)"\
|
||||
if len(shortened_description) > desc_threshold else shortened_description
|
||||
description_lab = ctk.CTkLabel(info_frame, text=f"Description: {shortened_description}")
|
||||
description_lab.grid(row=1, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
description_lab.grid(row=1, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
if len(description) > desc_threshold:
|
||||
description_lab_tooltip = CTkToolTip(description_lab, message="View description", topmost=True)
|
||||
description_lab.configure(cursor="hand2")
|
||||
description_lab.bind("<Button-1>", lambda e: show_description(e))
|
||||
|
||||
type_label = ctk.CTkLabel(info_frame, text=f"Type: {map_mod_type}")
|
||||
type_label.grid(row=2, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
map_mod_type = map_mod_type_txt[:desc_threshold] + "..." if len(map_mod_type_txt) > desc_threshold else map_mod_type_txt
|
||||
type_label = ctk.CTkLabel(info_frame, text=f"Type: {map_mod_type}", wraplength=350, justify="left")
|
||||
type_label.grid(row=2, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
if len(map_mod_type) > desc_threshold:
|
||||
type_label_tooltip = CTkToolTip(type_label, message="View all types", topmost=True)
|
||||
type_label.configure(cursor="hand2")
|
||||
type_label.bind("<Button-1>", lambda e: show_full_text(e, type_label, map_mod_type_txt))
|
||||
|
||||
size_label = ctk.CTkLabel(info_frame, text=f"Size: {map_size}")
|
||||
size_label.grid(row=3, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
size_label = ctk.CTkLabel(info_frame, text=f"Size (Workshop): {map_size}")
|
||||
size_label.grid(row=3, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
date_created_label = ctk.CTkLabel(info_frame, text=f"Posted: {date_created}")
|
||||
date_created_label.grid(row=4, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
date_created_label.grid(row=4, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
if date_updated != "Not updated":
|
||||
date_updated_label = ctk.CTkLabel(info_frame, text=f"Updated: {date_updated} 🔗")
|
||||
@ -742,7 +760,7 @@ class BOIIIWD(ctk.CTk):
|
||||
else:
|
||||
date_updated_label = ctk.CTkLabel(info_frame, text=f"Updated: {date_updated}")
|
||||
|
||||
date_updated_label.grid(row=5, column=0, columnspan=2, sticky="w", padx=20, pady=5)
|
||||
date_updated_label.grid(row=5, column=0, columnspan=2, sticky="w", padx=20, pady=2.5)
|
||||
|
||||
stars_image_label = ctk.CTkLabel(stars_frame)
|
||||
stars_width, stars_height = stars_image_size
|
||||
@ -755,8 +773,9 @@ class BOIIIWD(ctk.CTk):
|
||||
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)))
|
||||
max_width = 300
|
||||
i_width, i_height = tuple([int(max_width/image_size[0] * x) for x in image_size])
|
||||
image_widget = ctk.CTkImage(image, size=(int(i_width), int(i_height)))
|
||||
image_label.configure(image=image_widget, text="")
|
||||
image_label.pack(expand=True, fill="both", padx=(10, 20), pady=(10, 10))
|
||||
|
||||
@ -772,6 +791,7 @@ class BOIIIWD(ctk.CTk):
|
||||
top.grid_rowconfigure(2, weight=1)
|
||||
top.grid_columnconfigure(0, weight=1)
|
||||
top.grid_columnconfigure(1, weight=1)
|
||||
top.after(10, top.focus_force)
|
||||
|
||||
self.after(0, main_thread)
|
||||
|
||||
@ -871,6 +891,9 @@ class BOIIIWD(ctk.CTk):
|
||||
creationflags=show_console
|
||||
)
|
||||
|
||||
if process.poll() is not None:
|
||||
continue
|
||||
|
||||
#wait for process
|
||||
while True:
|
||||
if not self.is_downloading:
|
||||
@ -878,7 +901,7 @@ class BOIIIWD(ctk.CTk):
|
||||
start_time = time.time()
|
||||
self.is_downloading = True
|
||||
elapsed_time = time.time() - start_time
|
||||
if process.poll() != None:
|
||||
if process.poll() is not None:
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
@ -907,6 +930,7 @@ class BOIIIWD(ctk.CTk):
|
||||
reset_steamcmd(no_warn=True)
|
||||
self.settings_tab.steam_fail_counter = 0
|
||||
self.fail_threshold = 0
|
||||
continue
|
||||
else:
|
||||
process = subprocess.Popen(
|
||||
[steamcmd_path + "\steamcmd.exe"] + command.split(),
|
||||
@ -922,7 +946,7 @@ class BOIIIWD(ctk.CTk):
|
||||
if not self.is_downloading:
|
||||
if self.check_steamcmd_stdout(stdout_path, wsid):
|
||||
self.is_downloading = True
|
||||
if process.poll() != None:
|
||||
if process.poll() is not None:
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
@ -1004,6 +1028,8 @@ class BOIIIWD(ctk.CTk):
|
||||
|
||||
text = self.queuetextarea.get("1.0", "end")
|
||||
items = []
|
||||
items_ws_sizes = {}
|
||||
|
||||
if "," in text:
|
||||
items = [n.strip() for n in text.split(",")]
|
||||
else:
|
||||
@ -1051,6 +1077,7 @@ class BOIIIWD(ctk.CTk):
|
||||
|
||||
ws_file_size = get_workshop_file_size(workshop_id)
|
||||
file_size = ws_file_size
|
||||
items_ws_sizes[workshop_id] = ws_file_size
|
||||
self.total_queue_size += ws_file_size
|
||||
|
||||
if file_size is None:
|
||||
@ -1065,11 +1092,19 @@ class BOIIIWD(ctk.CTk):
|
||||
if self.already_installed:
|
||||
item_ids = ", ".join(self.already_installed)
|
||||
if self.settings_tab.skip_already_installed:
|
||||
skipped_items = []
|
||||
for item in self.already_installed:
|
||||
if item in items:
|
||||
items.remove(item)
|
||||
show_message("Heads up!, map/s skipped => skip is on in settings", f"These item IDs may already be installed and are skipped:\n{item_ids}", icon="info")
|
||||
if not any(isinstance(item, int) for item in items):
|
||||
skipped_items.append(item)
|
||||
self.total_queue_size -= items_ws_sizes[item]
|
||||
if skipped_items and items:
|
||||
show_message("Heads up! Maps skipped => Skip is on in settings",
|
||||
f"These item IDs may already be installed and are skipped:\n{', '.join(skipped_items)}",
|
||||
icon="info")
|
||||
if not items:
|
||||
show_message("Download stopped => Skip is on in settings", "All items have been skipped since they are already installed.",
|
||||
icon="info")
|
||||
self.stop_download()
|
||||
return
|
||||
else:
|
||||
@ -1129,8 +1164,8 @@ class BOIIIWD(ctk.CTk):
|
||||
prev_item_size = sum(os.path.getsize(os.path.join(prev_item_path, f)) for f in os.listdir(prev_item_path))
|
||||
elif os.path.exists(prev_item_path_2):
|
||||
prev_item_size = sum(os.path.getsize(os.path.join(prev_item_path_2, f)) for f in os.listdir(prev_item_path_2))
|
||||
else:
|
||||
prev_item_size = get_workshop_file_size(previous_item)
|
||||
if prev_item_size == 0 or not prev_item_size:
|
||||
prev_item_size = items_ws_sizes[previous_item]
|
||||
if prev_item_size:
|
||||
self.total_queue_size -= prev_item_size
|
||||
self.item_skipped = False
|
||||
|
@ -502,222 +502,219 @@ class SettingsTab(ctk.CTkFrame):
|
||||
reset_steamcmd()
|
||||
|
||||
def from_steam_to_boiii_toplevel(self):
|
||||
def main_thread():
|
||||
try:
|
||||
# to make sure json file is up to date
|
||||
main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
||||
top = ctk.CTkToplevel(self)
|
||||
if os.path.exists(os.path.join(RESOURCES_DIR, "ryuk.ico")):
|
||||
top.after(210, lambda: top.iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico")))
|
||||
top.title("Steam to boiii -> Workshop items")
|
||||
top.attributes('-topmost', 'true')
|
||||
top.resizable(False, False)
|
||||
# Create input boxes
|
||||
center_frame = ctk.CTkFrame(top)
|
||||
center_frame.grid(row=0, column=0, padx=20, pady=20)
|
||||
try:
|
||||
# to make sure json file is up to date
|
||||
main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
||||
top = ctk.CTkToplevel(self)
|
||||
if os.path.exists(os.path.join(RESOURCES_DIR, "ryuk.ico")):
|
||||
top.after(210, lambda: top.iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico")))
|
||||
top.title("Steam to boiii")
|
||||
_, _, x, y = get_window_size_from_registry()
|
||||
top.geometry(f"+{x}+{y}")
|
||||
# top.attributes('-topmost', 'true')
|
||||
top.resizable(False, False)
|
||||
# Create input boxes
|
||||
center_frame = ctk.CTkFrame(top)
|
||||
|
||||
# Create input boxes
|
||||
steam_folder_label = ctk.CTkLabel(center_frame, text="Steam Folder:")
|
||||
steam_folder_label.grid(row=0, column=0, padx=(20, 20), pady=(10, 0), sticky='w')
|
||||
steam_folder_entry = ctk.CTkEntry(center_frame, width=225)
|
||||
steam_folder_entry.grid(row=1, column=0, columnspan=2, padx=(0, 20), pady=(10, 10), sticky='nes')
|
||||
button_steam_browse = ctk.CTkButton(center_frame, text="Select", width=10)
|
||||
button_steam_browse.grid(row=1, column=2, padx=(0, 20), pady=(10, 10), sticky="wnes")
|
||||
# Create input boxes
|
||||
steam_folder_label = ctk.CTkLabel(center_frame, text="Steam Folder:")
|
||||
steam_folder_entry = ctk.CTkEntry(center_frame, width=225)
|
||||
button_steam_browse = ctk.CTkButton(center_frame, text="Select", width=10)
|
||||
boiii_folder_label = ctk.CTkLabel(center_frame, text="boiii Folder:")
|
||||
boiii_folder_entry = ctk.CTkEntry(center_frame, width=225)
|
||||
button_BOIII_browse = ctk.CTkButton(center_frame, text="Select", width=10)
|
||||
# Create option to choose between cut or copy
|
||||
operation_label = ctk.CTkLabel(center_frame, text="Choose operation:")
|
||||
copy_var = ctk.BooleanVar()
|
||||
cut_var = ctk.BooleanVar()
|
||||
copy_check = ctk.CTkCheckBox(center_frame, text="Copy", variable=copy_var)
|
||||
cut_check = ctk.CTkCheckBox(center_frame, text="Cut", variable=cut_var)
|
||||
|
||||
boiii_folder_label = ctk.CTkLabel(center_frame, text="boiii Folder:")
|
||||
boiii_folder_label.grid(row=2, column=0, padx=(20, 20), pady=(10, 0), sticky='w')
|
||||
boiii_folder_entry = ctk.CTkEntry(center_frame, width=225)
|
||||
boiii_folder_entry.grid(row=3, column=0, columnspan=2, padx=(0, 20), pady=(10, 10), sticky='nes')
|
||||
button_BOIII_browse = ctk.CTkButton(center_frame, text="Select", width=10)
|
||||
button_BOIII_browse.grid(row=3, column=2, padx=(0, 20), pady=(10, 10), sticky="wnes")
|
||||
# Create progress bar
|
||||
progress_bar = ctk.CTkProgressBar(center_frame, mode="determinate", height=20, corner_radius=7)
|
||||
progress_text = ctk.CTkLabel(progress_bar, text="0%", font=("Helvetica", 12), fg_color="transparent", text_color="white", height=0, width=0, corner_radius=0)
|
||||
copy_button = ctk.CTkButton(center_frame, text="Start (Copy)")
|
||||
|
||||
# Create option to choose between cut or copy
|
||||
operation_label = ctk.CTkLabel(center_frame, text="Choose operation:")
|
||||
operation_label.grid(row=4, column=0, padx=(20, 20), pady=(10, 10), sticky='wnes')
|
||||
copy_var = ctk.BooleanVar()
|
||||
cut_var = ctk.BooleanVar()
|
||||
copy_check = ctk.CTkCheckBox(center_frame, text="Copy", variable=copy_var)
|
||||
cut_check = ctk.CTkCheckBox(center_frame, text="Cut", variable=cut_var)
|
||||
copy_check.grid(row=4, column=1, padx=(0, 10), pady=(10, 10), sticky='wnes')
|
||||
cut_check.grid(row=4, column=2, padx=(0, 10), pady=(10, 10), sticky='nes')
|
||||
# funcs
|
||||
# had to use this shit again cuz of threading issues with widgets
|
||||
def copy_with_progress(src, dst):
|
||||
try:
|
||||
total_files = sum([len(files) for root, dirs, files in os.walk(src)])
|
||||
progress = 0
|
||||
|
||||
# Create progress bar
|
||||
progress_bar = ctk.CTkProgressBar(center_frame, mode="determinate", height=20, corner_radius=7)
|
||||
progress_bar.grid(row=5, column=0, columnspan=3, padx=(20, 20), pady=(10, 10), sticky='wnes')
|
||||
progress_text = ctk.CTkLabel(progress_bar, text="0%", font=("Helvetica", 12), fg_color="transparent", text_color="white", height=0, width=0, corner_radius=0)
|
||||
progress_text.place(relx=0.5, rely=0.5, anchor="center")
|
||||
def copy_progress(src, dst):
|
||||
nonlocal progress
|
||||
shutil.copy2(src, dst)
|
||||
progress += 1
|
||||
top.after(0, progress_text.configure(text=f"Copying files: {progress}/{total_files}"))
|
||||
value = (progress / total_files) * 100
|
||||
valuep = value / 100
|
||||
progress_bar.set(valuep)
|
||||
|
||||
copy_button = ctk.CTkButton(center_frame, text="Start (Copy)")
|
||||
copy_button.grid(row=6, column=0, columnspan=3,padx=(20, 20), pady=(10, 10), sticky='wnes')
|
||||
|
||||
# funcs
|
||||
# had to use this shit again cuz of threading issues with widgets
|
||||
def copy_with_progress(src, dst):
|
||||
try:
|
||||
total_files = sum([len(files) for root, dirs, files in os.walk(src)])
|
||||
progress = 0
|
||||
shutil.copytree(src, dst, dirs_exist_ok=True, copy_function=copy_progress)
|
||||
except Exception as E:
|
||||
show_message("Error", f"Error copying files: {E}", icon="cancel")
|
||||
finally:
|
||||
top.after(0, progress_text.configure(text="0%"))
|
||||
top.after(0, progress_bar.set(0.0))
|
||||
|
||||
def copy_progress(src, dst):
|
||||
nonlocal progress
|
||||
shutil.copy2(src, dst)
|
||||
progress += 1
|
||||
top.after(0, progress_text.configure(text=f"Copying files: {progress}/{total_files}"))
|
||||
value = (progress / total_files) * 100
|
||||
valuep = value / 100
|
||||
progress_bar.set(valuep)
|
||||
def check_status(var, op_var):
|
||||
if var.get():
|
||||
op_var.set(False)
|
||||
if cut_var.get():
|
||||
copy_button.configure(text=f"Start (Cut)")
|
||||
if copy_var.get():
|
||||
copy_button.configure(text=f"Start (Copy)")
|
||||
|
||||
try:
|
||||
shutil.copytree(src, dst, dirs_exist_ok=True, copy_function=copy_progress)
|
||||
except Exception as E:
|
||||
show_message("Error", f"Error copying files: {E}", icon="cancel")
|
||||
finally:
|
||||
top.after(0, progress_text.configure(text="0%"))
|
||||
top.after(0, progress_bar.set(0.0))
|
||||
def open_BOIII_browser():
|
||||
selected_folder = ctk.filedialog.askdirectory(title="Select boiii Folder")
|
||||
if selected_folder:
|
||||
boiii_folder_entry.delete(0, "end")
|
||||
boiii_folder_entry.insert(0, selected_folder)
|
||||
|
||||
def check_status(var, op_var):
|
||||
if var.get():
|
||||
op_var.set(False)
|
||||
if cut_var.get():
|
||||
copy_button.configure(text=f"Start (Cut)")
|
||||
if copy_var.get():
|
||||
copy_button.configure(text=f"Start (Copy)")
|
||||
def open_steam_browser():
|
||||
selected_folder = ctk.filedialog.askdirectory(title="Select Steam Folder (ex: C:\Program Files (x86)\Steam)")
|
||||
if selected_folder:
|
||||
steam_folder_entry.delete(0, "end")
|
||||
steam_folder_entry.insert(0, selected_folder)
|
||||
save_config("steam_folder" ,steam_folder_entry.get())
|
||||
|
||||
def open_BOIII_browser():
|
||||
selected_folder = ctk.filedialog.askdirectory(title="Select boiii Folder")
|
||||
if selected_folder:
|
||||
boiii_folder_entry.delete(0, "end")
|
||||
boiii_folder_entry.insert(0, selected_folder)
|
||||
def start_copy_operation():
|
||||
def start_thread():
|
||||
try:
|
||||
if not cut_var.get() and not copy_var.get():
|
||||
show_message("Choose operation!", "Please choose an operation, Copy or Cut files from steam!")
|
||||
return
|
||||
|
||||
def open_steam_browser():
|
||||
selected_folder = ctk.filedialog.askdirectory(title="Select Steam Folder (ex: C:\Program Files (x86)\Steam)")
|
||||
if selected_folder:
|
||||
steam_folder_entry.delete(0, "end")
|
||||
steam_folder_entry.insert(0, selected_folder)
|
||||
save_config("steam_folder" ,steam_folder_entry.get())
|
||||
copy_button.configure(state="disabled")
|
||||
steam_folder = steam_folder_entry.get()
|
||||
ws_folder = os.path.join(steam_folder, "steamapps/workshop/content/311210")
|
||||
boiii_folder = boiii_folder_entry.get()
|
||||
|
||||
def start_copy_operation():
|
||||
def start_thread():
|
||||
try:
|
||||
if not cut_var.get() and not copy_var.get():
|
||||
show_message("Choose operation!", "Please choose an operation, Copy or Cut files from steam!")
|
||||
return
|
||||
if not os.path.exists(steam_folder) and not os.path.exists(ws_folder):
|
||||
show_message("Not found", "Either you have no items downloaded from Steam or wrong path, please recheck path (ex: C:\Program Files (x86)\Steam)")
|
||||
return
|
||||
|
||||
copy_button.configure(state="disabled")
|
||||
steam_folder = steam_folder_entry.get()
|
||||
ws_folder = os.path.join(steam_folder, "steamapps/workshop/content/311210")
|
||||
boiii_folder = boiii_folder_entry.get()
|
||||
if not os.path.exists(boiii_folder):
|
||||
show_message("Not found", "boiii folder not found, please recheck path")
|
||||
return
|
||||
|
||||
if not os.path.exists(steam_folder) and not os.path.exists(ws_folder):
|
||||
show_message("Not found", "Either you have no items downloaded from Steam or wrong path, please recheck path (ex: C:\Program Files (x86)\Steam)")
|
||||
return
|
||||
top.after(0, progress_text.configure(text="Loading..."))
|
||||
|
||||
if not os.path.exists(boiii_folder):
|
||||
show_message("Not found", "boiii folder not found, please recheck path")
|
||||
return
|
||||
map_folder = os.path.join(ws_folder)
|
||||
|
||||
top.after(0, progress_text.configure(text="Loading..."))
|
||||
subfolders = [f for f in os.listdir(map_folder) if os.path.isdir(os.path.join(map_folder, f))]
|
||||
total_folders = len(subfolders)
|
||||
|
||||
map_folder = os.path.join(ws_folder)
|
||||
if not subfolders:
|
||||
show_message("No items found", f"No items found in \n{map_folder}")
|
||||
return
|
||||
|
||||
subfolders = [f for f in os.listdir(map_folder) if os.path.isdir(os.path.join(map_folder, f))]
|
||||
total_folders = len(subfolders)
|
||||
for i, dir_name in enumerate(subfolders, start=1):
|
||||
json_file_path = os.path.join(map_folder, dir_name, "workshop.json")
|
||||
copy_button.configure(text=f"Working on -> {i}/{total_folders}")
|
||||
|
||||
if not subfolders:
|
||||
show_message("No items found", f"No items found in \n{map_folder}")
|
||||
return
|
||||
if os.path.exists(json_file_path):
|
||||
workshop_id = extract_json_data(json_file_path, "PublisherID")
|
||||
mod_type = extract_json_data(json_file_path, "Type")
|
||||
items_file = os.path.join(application_path, LIBRARY_FILE)
|
||||
item_exists,_ = main_app.app.library_tab.item_exists_in_file(items_file, workshop_id)
|
||||
|
||||
for i, dir_name in enumerate(subfolders, start=1):
|
||||
json_file_path = os.path.join(map_folder, dir_name, "workshop.json")
|
||||
copy_button.configure(text=f"Working on -> {i}/{total_folders}")
|
||||
|
||||
if os.path.exists(json_file_path):
|
||||
workshop_id = extract_json_data(json_file_path, "PublisherID")
|
||||
mod_type = extract_json_data(json_file_path, "Type")
|
||||
items_file = os.path.join(application_path, LIBRARY_FILE)
|
||||
item_exists,_ = main_app.app.library_tab.item_exists_in_file(items_file, workshop_id)
|
||||
|
||||
if item_exists:
|
||||
get_folder_name = main_app.app.library_tab.get_item_by_id(items_file, workshop_id, return_option="folder_name")
|
||||
if get_folder_name:
|
||||
folder_name = get_folder_name
|
||||
else:
|
||||
try:
|
||||
folder_name = extract_json_data(json_file_path, main_app.app.settings_tab.folder_options.get())
|
||||
except:
|
||||
folder_name = extract_json_data(json_file_path, "publisherID")
|
||||
if item_exists:
|
||||
get_folder_name = main_app.app.library_tab.get_item_by_id(items_file, workshop_id, return_option="folder_name")
|
||||
if get_folder_name:
|
||||
folder_name = get_folder_name
|
||||
else:
|
||||
try:
|
||||
folder_name = extract_json_data(json_file_path, main_app.app.settings_tab.folder_options.get())
|
||||
except:
|
||||
folder_name = extract_json_data(json_file_path, "publisherID")
|
||||
|
||||
if mod_type == "mod":
|
||||
path_folder = os.path.join(boiii_folder, "mods")
|
||||
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
||||
elif mod_type == "map":
|
||||
path_folder = os.path.join(boiii_folder, "usermaps")
|
||||
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
||||
else:
|
||||
show_message("Error", "Invalid workshop type in workshop.json, are you sure this is a map or a mod?.", icon="cancel")
|
||||
continue
|
||||
|
||||
if not item_exists:
|
||||
while os.path.exists(os.path.join(path_folder, folder_name)):
|
||||
folder_name += f"_{workshop_id}"
|
||||
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
||||
|
||||
os.makedirs(folder_name_path, exist_ok=True)
|
||||
|
||||
try:
|
||||
copy_with_progress(os.path.join(map_folder, dir_name), folder_name_path)
|
||||
except Exception as E:
|
||||
show_message("Error", f"Error copying files: {E}", icon="cancel")
|
||||
continue
|
||||
|
||||
if cut_var.get():
|
||||
remove_tree(os.path.join(map_folder, dir_name))
|
||||
|
||||
main_app.app.library_tab.update_item(main_app.app.edit_destination_folder.get(), workshop_id, mod_type, folder_name)
|
||||
else:
|
||||
# if its last folder to check
|
||||
if i == total_folders:
|
||||
show_message("Error", f"workshop.json not found in {dir_name}", icon="cancel")
|
||||
main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
||||
return
|
||||
try:
|
||||
folder_name = extract_json_data(json_file_path, main_app.app.settings_tab.folder_options.get())
|
||||
except:
|
||||
folder_name = extract_json_data(json_file_path, "publisherID")
|
||||
|
||||
if mod_type == "mod":
|
||||
path_folder = os.path.join(boiii_folder, "mods")
|
||||
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
||||
elif mod_type == "map":
|
||||
path_folder = os.path.join(boiii_folder, "usermaps")
|
||||
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
||||
else:
|
||||
show_message("Error", "Invalid workshop type in workshop.json, are you sure this is a map or a mod?.", icon="cancel")
|
||||
continue
|
||||
|
||||
if subfolders:
|
||||
main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
||||
main_app.app.show_complete_message(message=f"All items were moved\nYou can run the game now!\nPS: You have to restart the game\n(pressing launch will launch/restarts)")
|
||||
if not item_exists:
|
||||
while os.path.exists(os.path.join(path_folder, folder_name)):
|
||||
folder_name += f"_{workshop_id}"
|
||||
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
||||
|
||||
finally:
|
||||
if cut_var.get():
|
||||
copy_button.configure(text=f"Start (Cut)")
|
||||
if copy_var.get():
|
||||
copy_button.configure(text=f"Start (Copy)")
|
||||
copy_button.configure(state="normal")
|
||||
top.after(0, progress_bar.set(0))
|
||||
top.after(0, progress_text.configure(text="0%"))
|
||||
os.makedirs(folder_name_path, exist_ok=True)
|
||||
|
||||
# prevents app hanging
|
||||
threading.Thread(target=start_thread).start()
|
||||
try:
|
||||
copy_with_progress(os.path.join(map_folder, dir_name), folder_name_path)
|
||||
except Exception as E:
|
||||
show_message("Error", f"Error copying files: {E}", icon="cancel")
|
||||
continue
|
||||
|
||||
# config
|
||||
progress_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="boiiiwd_theme.json")), "progress_bar_fill_color")
|
||||
progress_bar.configure(progress_color=progress_color)
|
||||
steam_folder_entry.insert(1, check_config("steam_folder", ""))
|
||||
boiii_folder_entry.insert(1, main_app.app.edit_destination_folder.get())
|
||||
button_BOIII_browse.configure(command=open_BOIII_browser)
|
||||
button_steam_browse.configure(command=open_steam_browser)
|
||||
copy_button.configure(command=start_copy_operation)
|
||||
cut_check.configure(command = lambda: check_status(cut_var, copy_var))
|
||||
copy_check.configure(command = lambda: check_status(copy_var, cut_var))
|
||||
main_app.app.create_context_menu(steam_folder_entry)
|
||||
main_app.app.create_context_menu(boiii_folder_entry)
|
||||
copy_var.set(True)
|
||||
progress_bar.set(0)
|
||||
if cut_var.get():
|
||||
remove_tree(os.path.join(map_folder, dir_name))
|
||||
|
||||
except Exception as e:
|
||||
show_message("Error", f"{e}", icon="cancel")
|
||||
main_app.app.library_tab.update_item(main_app.app.edit_destination_folder.get(), workshop_id, mod_type, folder_name)
|
||||
else:
|
||||
# if its last folder to check
|
||||
if i == total_folders:
|
||||
show_message("Error", f"workshop.json not found in {dir_name}", icon="cancel")
|
||||
main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
||||
return
|
||||
continue
|
||||
|
||||
main_app.app.after(0, main_thread)
|
||||
if subfolders:
|
||||
main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
||||
main_app.app.show_complete_message(message=f"All items were moved\nYou can run the game now!\nPS: You have to restart the game\n(pressing launch will launch/restarts)")
|
||||
|
||||
finally:
|
||||
if cut_var.get():
|
||||
copy_button.configure(text=f"Start (Cut)")
|
||||
if copy_var.get():
|
||||
copy_button.configure(text=f"Start (Copy)")
|
||||
copy_button.configure(state="normal")
|
||||
top.after(0, progress_bar.set(0))
|
||||
top.after(0, progress_text.configure(text="0%"))
|
||||
|
||||
# prevents app hanging
|
||||
threading.Thread(target=start_thread).start()
|
||||
|
||||
# config
|
||||
center_frame.grid(row=0, column=0, padx=20, pady=20)
|
||||
button_steam_browse.grid(row=1, column=2, padx=(0, 20), pady=(10, 10), sticky="wnes")
|
||||
steam_folder_label.grid(row=0, column=0, padx=(20, 20), pady=(10, 0), sticky='w')
|
||||
steam_folder_entry.grid(row=1, column=0, columnspan=2, padx=(0, 20), pady=(10, 10), sticky='nes')
|
||||
boiii_folder_label.grid(row=2, column=0, padx=(20, 20), pady=(10, 0), sticky='w')
|
||||
boiii_folder_entry.grid(row=3, column=0, columnspan=2, padx=(0, 20), pady=(10, 10), sticky='nes')
|
||||
button_BOIII_browse.grid(row=3, column=2, padx=(0, 20), pady=(10, 10), sticky="wnes")
|
||||
operation_label.grid(row=4, column=0, padx=(20, 20), pady=(10, 10), sticky='wnes')
|
||||
copy_check.grid(row=4, column=1, padx=(0, 10), pady=(10, 10), sticky='wnes')
|
||||
cut_check.grid(row=4, column=2, padx=(0, 10), pady=(10, 10), sticky='nes')
|
||||
progress_bar.grid(row=5, column=0, columnspan=3, padx=(20, 20), pady=(10, 10), sticky='wnes')
|
||||
progress_text.place(relx=0.5, rely=0.5, anchor="center")
|
||||
copy_button.grid(row=6, column=0, columnspan=3,padx=(20, 20), pady=(10, 10), sticky='wnes')
|
||||
progress_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="boiiiwd_theme.json")), "progress_bar_fill_color")
|
||||
progress_bar.configure(progress_color=progress_color)
|
||||
steam_folder_entry.insert(1, check_config("steam_folder", ""))
|
||||
boiii_folder_entry.insert(1, main_app.app.edit_destination_folder.get())
|
||||
button_BOIII_browse.configure(command=open_BOIII_browser)
|
||||
button_steam_browse.configure(command=open_steam_browser)
|
||||
copy_button.configure(command=start_copy_operation)
|
||||
cut_check.configure(command = lambda: check_status(cut_var, copy_var))
|
||||
copy_check.configure(command = lambda: check_status(copy_var, cut_var))
|
||||
main_app.app.create_context_menu(steam_folder_entry)
|
||||
main_app.app.create_context_menu(boiii_folder_entry)
|
||||
copy_var.set(True)
|
||||
progress_bar.set(0)
|
||||
top.after(120, top.focus_force)
|
||||
|
||||
except Exception as e:
|
||||
show_message("Error", f"{e}", icon="cancel")
|
||||
|
@ -46,7 +46,8 @@ class UpdateWindow(ctk.CTkToplevel):
|
||||
def __init__(self, master, update_url):
|
||||
super().__init__(master)
|
||||
self.title("BOIIIWD Self-Updater")
|
||||
self.geometry("400x150")
|
||||
_, _, x, y = get_window_size_from_registry()
|
||||
self.geometry(f"400x150+{x}+{y}")
|
||||
if os.path.exists(os.path.join(RESOURCES_DIR, "ryuk.ico")):
|
||||
self.after(250, lambda: self.iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico")))
|
||||
self.protocol("WM_DELETE_WINDOW", self.cancel_update)
|
||||
|
Loading…
Reference in New Issue
Block a user