almost done with v0.3.0, added eveything missing just a setting
This commit is contained in:
parent
ac28bc043c
commit
a0281cdd73
Binary file not shown.
@ -28,6 +28,7 @@ class CTkToolTip(Toplevel):
|
|||||||
border_color: str = None,
|
border_color: str = None,
|
||||||
alpha: float = 0.95,
|
alpha: float = 0.95,
|
||||||
padding: tuple = (10, 2),
|
padding: tuple = (10, 2),
|
||||||
|
topmost: bool = False,
|
||||||
is_noti: bool = False,
|
is_noti: bool = False,
|
||||||
noti_event: any = None,
|
noti_event: any = None,
|
||||||
noti_dur: float = 3.0,
|
noti_dur: float = 3.0,
|
||||||
@ -40,6 +41,9 @@ class CTkToolTip(Toplevel):
|
|||||||
if not is_noti:
|
if not is_noti:
|
||||||
self.withdraw()
|
self.withdraw()
|
||||||
|
|
||||||
|
if topmost:
|
||||||
|
self.attributes('-topmost', 'true')
|
||||||
|
|
||||||
# Disable ToolTip's title bar
|
# Disable ToolTip's title bar
|
||||||
self.overrideredirect(True)
|
self.overrideredirect(True)
|
||||||
|
|
||||||
|
199
boiiiwd.py
199
boiiiwd.py
@ -1,15 +1,16 @@
|
|||||||
from CTkMessagebox import CTkMessagebox
|
from CTkMessagebox import CTkMessagebox
|
||||||
from tkinter import Menu, END, Event
|
from tkinter import Menu, END, Event
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
from datetime import datetime
|
||||||
import customtkinter as ctk
|
import customtkinter as ctk
|
||||||
from CTkToolTip import *
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from CTkToolTip import *
|
||||||
|
from CTkListbox import *
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import configparser
|
import configparser
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
import datetime
|
|
||||||
import requests
|
import requests
|
||||||
import zipfile
|
import zipfile
|
||||||
import shutil
|
import shutil
|
||||||
@ -367,8 +368,30 @@ def get_item_name(id):
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def show_noti(widget ,message, event=None, noti_dur=3.0):
|
def show_noti(widget ,message, event=None, noti_dur=3.0, topmost=False):
|
||||||
CTkToolTip(widget, message=message, is_noti=True, noti_event=event, noti_dur=noti_dur)
|
CTkToolTip(widget, message=message, is_noti=True, noti_event=event, noti_dur=noti_dur, topmost=topmost)
|
||||||
|
|
||||||
|
def check_item_date(down_date, date_updated):
|
||||||
|
current_year = datetime.now().year
|
||||||
|
date_format_with_year = "%d %b, %Y @ %I:%M%p"
|
||||||
|
date_format_with_added_year = "%d %b @ %I:%M%p, %Y"
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
download_datetime = datetime.strptime(down_date, date_format_with_year)
|
||||||
|
except ValueError:
|
||||||
|
download_datetime = datetime.strptime(down_date + f", {current_year}", date_format_with_added_year)
|
||||||
|
|
||||||
|
try:
|
||||||
|
upload_datetime = datetime.strptime(date_updated, date_format_with_year)
|
||||||
|
except ValueError:
|
||||||
|
upload_datetime = datetime.strptime(date_updated + f", {current_year}", date_format_with_added_year)
|
||||||
|
|
||||||
|
if upload_datetime >= download_datetime:
|
||||||
|
return True
|
||||||
|
elif upload_datetime < download_datetime:
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
# End helper functions
|
# End helper functions
|
||||||
class UpdateWindow(ctk.CTkToplevel):
|
class UpdateWindow(ctk.CTkToplevel):
|
||||||
@ -497,9 +520,15 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
self.filter_entry.bind("<KeyRelease>", self.filter_items)
|
self.filter_entry.bind("<KeyRelease>", self.filter_items)
|
||||||
self.filter_entry.grid(row=0, column=0, padx=(10, 20), pady=(10, 20), sticky="we")
|
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")
|
filter_refresh_button_image = os.path.join(RESOURCES_DIR, "Refresh_icon.svg.png")
|
||||||
|
update_button_image = os.path.join(RESOURCES_DIR, "update_icon.png")
|
||||||
self.filter_refresh_button = ctk.CTkButton(self, image=ctk.CTkImage(Image.open(filter_refresh_button_image)), command=self.refresh_items, width=20, height=20,
|
self.filter_refresh_button = ctk.CTkButton(self, image=ctk.CTkImage(Image.open(filter_refresh_button_image)), command=self.refresh_items, width=20, height=20,
|
||||||
fg_color="transparent", text="")
|
fg_color="transparent", text="")
|
||||||
self.filter_refresh_button.grid(row=0, column=1, padx=(10, 20), pady=(10, 20), sticky="enw")
|
self.filter_refresh_button.grid(row=0, column=1, padx=(10, 0), pady=(10, 20), sticky="nw")
|
||||||
|
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_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 = []
|
self.label_list = []
|
||||||
self.button_list = []
|
self.button_list = []
|
||||||
self.button_view_list = []
|
self.button_view_list = []
|
||||||
@ -510,7 +539,6 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
label = ctk.CTkLabel(self, text=item, image=image, compound="left", padx=5, anchor="w")
|
label = ctk.CTkLabel(self, text=item, image=image, compound="left", padx=5, anchor="w")
|
||||||
button = ctk.CTkButton(self, text="Remove", width=60, height=24, fg_color="#3d3f42")
|
button = ctk.CTkButton(self, text="Remove", width=60, height=24, fg_color="#3d3f42")
|
||||||
button_view = ctk.CTkButton(self, text="Details", width=55, height=24, fg_color="#3d3f42")
|
button_view = ctk.CTkButton(self, text="Details", width=55, height=24, fg_color="#3d3f42")
|
||||||
button_update = ctk.CTkButton(self, text="Update", width=55, height=24, fg_color="#3d3f42")
|
|
||||||
button.configure(command=lambda: self.remove_item(item, folder, workshop_id))
|
button.configure(command=lambda: self.remove_item(item, folder, workshop_id))
|
||||||
button_view.configure(command=lambda: self.show_map_info(workshop_id))
|
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_view_tooltip = CTkToolTip(button_view, message="Opens up a window that shows basic details")
|
||||||
@ -660,7 +688,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
if mode_type:
|
if mode_type:
|
||||||
text_to_add += f" | Mode: {mode_type}"
|
text_to_add += f" | Mode: {mode_type}"
|
||||||
text_to_add += f" | ID: {workshop_id} | Size: {size}"
|
text_to_add += f" | ID: {workshop_id} | Size: {size}"
|
||||||
date_added = datetime.datetime.now().strftime("%d %b, %Y @ %I:%M%p")
|
date_added = datetime.now().strftime("%d %b, %Y @ %I:%M%p")
|
||||||
items_file = os.path.join(cwd(), LIBRARY_FILE)
|
items_file = os.path.join(cwd(), LIBRARY_FILE)
|
||||||
if text_to_add not in self.added_items:
|
if text_to_add not in self.added_items:
|
||||||
self.added_items.add(text_to_add)
|
self.added_items.add(text_to_add)
|
||||||
@ -829,7 +857,6 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
top.after(210, lambda: top.iconbitmap(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.title("Map/Mod Information")
|
||||||
top.attributes('-topmost', 'true')
|
top.attributes('-topmost', 'true')
|
||||||
current_year = datetime.datetime.now().year
|
|
||||||
down_date = self.get_item_by_id(LIBRARY_FILE, workshop_id, 'date')
|
down_date = self.get_item_by_id(LIBRARY_FILE, workshop_id, 'date')
|
||||||
|
|
||||||
def close_window():
|
def close_window():
|
||||||
@ -839,21 +866,10 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
webbrowser.open(url)
|
webbrowser.open(url)
|
||||||
|
|
||||||
def check_for_updates():
|
def check_for_updates():
|
||||||
date_format_with_year = "%d %b, %Y @ %I:%M%p"
|
|
||||||
date_format_with_added_year = "%d %b @ %I:%M%p, %Y"
|
|
||||||
try:
|
try:
|
||||||
try:
|
|
||||||
download_datetime = datetime.datetime.strptime(down_date, date_format_with_year)
|
|
||||||
except ValueError:
|
|
||||||
download_datetime = datetime.datetime.strptime(down_date + f", {current_year}", date_format_with_added_year)
|
|
||||||
|
|
||||||
try:
|
if check_item_date(down_date, date_updated):
|
||||||
upload_datetime = datetime.datetime.strptime(date_updated, date_format_with_year)
|
if show_message("There is an update.", "Press download to redownload!", icon="info", _return=True, option_1="No", option_2="Download"):
|
||||||
except ValueError:
|
|
||||||
upload_datetime = datetime.datetime.strptime(date_updated + f", {current_year}", date_format_with_added_year)
|
|
||||||
|
|
||||||
if upload_datetime >= download_datetime:
|
|
||||||
if show_message("There is an update.", "Press update to redownload!", icon="info", _return=True, option_1="No", option_2="Download"):
|
|
||||||
if app.is_downloading:
|
if app.is_downloading:
|
||||||
show_message("Error", "Please wait for the current download to finish or stop it then restart.", icon="cancel")
|
show_message("Error", "Please wait for the current download to finish or stop it then restart.", icon="cancel")
|
||||||
return
|
return
|
||||||
@ -863,11 +879,9 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
app.download_map(update=True)
|
app.download_map(update=True)
|
||||||
top.destroy()
|
top.destroy()
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
elif upload_datetime < download_datetime:
|
|
||||||
show_message("Up to date!", "No updates found!", icon="info")
|
show_message("Up to date!", "No updates found!", icon="info")
|
||||||
except:
|
except:
|
||||||
print(f"Error {date_updated}")
|
|
||||||
show_message("Up to date!", "No updates found!", icon="info")
|
show_message("Up to date!", "No updates found!", icon="info")
|
||||||
|
|
||||||
# frames
|
# frames
|
||||||
@ -949,6 +963,139 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
button_view.configure(state="normal")
|
button_view.configure(state="normal")
|
||||||
self.after(0, main_thread)
|
self.after(0, main_thread)
|
||||||
|
|
||||||
|
def check_for_updates(self):
|
||||||
|
self.after(1, self.update_button.configure(state="disabled"))
|
||||||
|
self.update_tooltip.configure(message='Still loading please wait...')
|
||||||
|
cevent = Event()
|
||||||
|
cevent.x_root = self.update_button.winfo_rootx()
|
||||||
|
cevent.y_root = self.update_button.winfo_rooty()
|
||||||
|
show_noti(self.update_button, "Please wait, window will popup shortly", event=cevent, noti_dur=3.0, topmost=True)
|
||||||
|
threading.Thread(target=self.update_items_window).start()
|
||||||
|
|
||||||
|
# yeah im lazy as shit this is what were working with for now
|
||||||
|
def update_items_window(self):
|
||||||
|
try:
|
||||||
|
top = ctk.CTkToplevel(master=None)
|
||||||
|
top.withdraw()
|
||||||
|
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("Item updater - List of items that need updating! - Click to select 1 or more")
|
||||||
|
top.geometry("600x400")
|
||||||
|
top.attributes('-topmost', 'true')
|
||||||
|
top.resizable(False, False)
|
||||||
|
to_update = set()
|
||||||
|
selected_id_list = []
|
||||||
|
cevent = Event()
|
||||||
|
|
||||||
|
listbox = CTkListbox(top, multiple_selection=True)
|
||||||
|
listbox.grid(row=0, column=0, sticky="nsew")
|
||||||
|
|
||||||
|
update_button = ctk.CTkButton(top, text="Update")
|
||||||
|
update_button.grid(row=1, column=0, pady=10)
|
||||||
|
|
||||||
|
def if_id_needs_update(item_id, item_date):
|
||||||
|
try:
|
||||||
|
url = f"https://steamcommunity.com/sharedfiles/filedetails/?id={item_id}"
|
||||||
|
response = requests.get(url)
|
||||||
|
response.raise_for_status()
|
||||||
|
content = response.text
|
||||||
|
soup = BeautifulSoup(content, "html.parser")
|
||||||
|
details_stats_container = soup.find("div", class_="detailsStatsContainerRight")
|
||||||
|
details_stat_elements = details_stats_container.find_all("div", class_="detailsStatRight")
|
||||||
|
try:
|
||||||
|
date_updated = details_stat_elements[2].text.strip()
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
date_updated = details_stat_elements[1].text.strip()
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if check_item_date(item_date, date_updated):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
show_message("Error", f"Error occured\n{e}", icon="cancel")
|
||||||
|
return
|
||||||
|
|
||||||
|
def add_checkbox_item(index, item_text):
|
||||||
|
listbox.insert(index, item_text)
|
||||||
|
|
||||||
|
def check_for_update():
|
||||||
|
with open(LIBRARY_FILE, 'r') as file:
|
||||||
|
data = json.load(file)
|
||||||
|
|
||||||
|
for item in data:
|
||||||
|
item_id = item["id"]
|
||||||
|
item_date = item["date"]
|
||||||
|
if if_id_needs_update(item_id, item_date):
|
||||||
|
to_update.add(item["text"])
|
||||||
|
|
||||||
|
def load_items():
|
||||||
|
for index, item_text in enumerate(to_update):
|
||||||
|
if index == len(to_update) - 1:
|
||||||
|
add_checkbox_item("end", item_text)
|
||||||
|
top.deiconify()
|
||||||
|
return
|
||||||
|
add_checkbox_item(index, item_text)
|
||||||
|
|
||||||
|
|
||||||
|
def update_list(selected_option):
|
||||||
|
selected_id_list.clear()
|
||||||
|
|
||||||
|
if selected_option:
|
||||||
|
for option in selected_option:
|
||||||
|
parts = option.split('ID: ')
|
||||||
|
if len(parts) > 1:
|
||||||
|
id_part = parts[1].split('|')[0].strip()
|
||||||
|
selected_id_list.append(id_part)
|
||||||
|
|
||||||
|
def update_btn_fun():
|
||||||
|
if len(selected_id_list) == 1:
|
||||||
|
if app.is_downloading:
|
||||||
|
show_message("Error", "Please wait for the current download to finish or stop it then start.", icon="cancel")
|
||||||
|
return
|
||||||
|
app.edit_workshop_id.delete(0, "end")
|
||||||
|
app.edit_workshop_id.insert(0, selected_id_list[0])
|
||||||
|
app.main_button_event()
|
||||||
|
app.download_map(update=True)
|
||||||
|
top.destroy()
|
||||||
|
return
|
||||||
|
|
||||||
|
elif len(selected_id_list) > 1:
|
||||||
|
if app.is_downloading:
|
||||||
|
show_message("Error", "Please wait for the current download to finish or stop it then start.", icon="cancel")
|
||||||
|
return
|
||||||
|
comma_separated_ids = ",".join(selected_id_list)
|
||||||
|
app.queuetextarea.delete("1.0", "end")
|
||||||
|
app.queuetextarea.insert("1.0", comma_separated_ids)
|
||||||
|
app.queue_button_event()
|
||||||
|
app.download_map(update=True)
|
||||||
|
top.destroy()
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
cevent.x_root = update_button.winfo_rootx()
|
||||||
|
cevent.y_root = update_button.winfo_rooty()
|
||||||
|
show_noti(update_button ,"Please select 1 or more items", event=cevent, noti_dur=0.8, topmost=True)
|
||||||
|
|
||||||
|
listbox.configure(command=update_list)
|
||||||
|
update_button.configure(command=update_btn_fun)
|
||||||
|
|
||||||
|
top.grid_rowconfigure(0, weight=1)
|
||||||
|
top.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
check_for_update()
|
||||||
|
load_items()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
show_message("Error", f"{e}", icon="cancel")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.update_tooltip.configure(message='Check items for updates')
|
||||||
|
self.after(1, self.update_button.configure(state="normal"))
|
||||||
|
|
||||||
class SettingsTab(ctk.CTkFrame):
|
class SettingsTab(ctk.CTkFrame):
|
||||||
def __init__(self, master=None):
|
def __init__(self, master=None):
|
||||||
super().__init__(master)
|
super().__init__(master)
|
||||||
@ -1292,7 +1439,7 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
def boiiiwd_custom_theme(self, disable_only=None):
|
def boiiiwd_custom_theme(self, disable_only=None):
|
||||||
file_to_rename = os.path.join(cwd(), "boiiiwd_theme.json")
|
file_to_rename = os.path.join(cwd(), "boiiiwd_theme.json")
|
||||||
if os.path.exists(file_to_rename):
|
if os.path.exists(file_to_rename):
|
||||||
timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
new_name = f"boiiiwd_theme_{timestamp}.json"
|
new_name = f"boiiiwd_theme_{timestamp}.json"
|
||||||
os.rename(file_to_rename, os.path.join(cwd(), new_name))
|
os.rename(file_to_rename, os.path.join(cwd(), new_name))
|
||||||
|
|
||||||
@ -2274,7 +2421,7 @@ class BOIIIWD(ctk.CTk):
|
|||||||
def run_steamcmd_command(self, command, map_folder, wsid, queue=None):
|
def run_steamcmd_command(self, command, map_folder, wsid, queue=None):
|
||||||
steamcmd_path = get_steamcmd_path()
|
steamcmd_path = get_steamcmd_path()
|
||||||
stdout = os.path.join(steamcmd_path, "logs", "workshop_log.txt")
|
stdout = os.path.join(steamcmd_path, "logs", "workshop_log.txt")
|
||||||
timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(stdout, 'w') as file:
|
with open(stdout, 'w') as file:
|
||||||
|
BIN
resources/update_icon.png
Normal file
BIN
resources/update_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
Loading…
Reference in New Issue
Block a user