Update to latest version
This commit is contained in:
parent
38f74dadc3
commit
1a4f0c1292
5
.gitignore
vendored
5
.gitignore
vendored
@ -162,5 +162,8 @@ cython_debug/
|
|||||||
# Other
|
# Other
|
||||||
*.ini
|
*.ini
|
||||||
*.conf
|
*.conf
|
||||||
dist/
|
|
||||||
.vscode
|
.vscode
|
||||||
|
test/
|
||||||
|
steamcmd
|
||||||
|
t7xwd_library.json
|
||||||
|
*.exe
|
119
README.md
119
README.md
@ -1,90 +1,45 @@
|
|||||||
# T7x Workshop Downloader (T7xWD)
|
# T7xWD
|
||||||
- A Feature-rich GUI Steam Workshop downloader for BO3 ([T7x client](https://github.com/Ezz-lol/T7x-free)) built using CustomTkinter <br>
|
- A Feature-rich GUI Steam Workshop downloader for [Call of Duty®: Black Ops III](https://store.steampowered.com/app/311210/Call_of_Duty_Black_Ops_III/) built using CustomTkinter <br>
|
||||||
|
|
||||||
<div style="display: flex; justify-content: space-between;">
|
<table>
|
||||||
<!-- Left Side -->
|
<tr>
|
||||||
<div style="flex: 1; margin-right: 5px;">
|
<td align="center">
|
||||||
<img src="https://github.com/faroukbmiled/BOIIIWD/assets/51106560/0aa8295f-ba07-4778-8140-200021df4ba9" width="400" />
|
<img src="https://github.com/faroukbmiled/BOIIIWD/assets/51106560/4d199e21-c9a0-4dfc-b831-866fbff1d1a1" max-width="400" />
|
||||||
<img src="https://github.com/faroukbmiled/BOIIIWD/assets/51106560/b4f27fe1-88f2-4158-b7ba-c8aec57b9968" width="400" />
|
</td>
|
||||||
</div>
|
<td align="center">
|
||||||
<!-- Right Side -->
|
<img src="https://github.com/faroukbmiled/BOIIIWD/assets/51106560/25174889-4524-455f-9836-f4ea5240e07f" max-width="400" />
|
||||||
<div style="flex: 1; margin-left: 5px;">
|
</td>
|
||||||
<img src="https://github.com/faroukbmiled/BOIIIWD/assets/51106560/86c07cf2-b04b-42d0-ae06-8526bffafb34" width="400" />
|
<td align="center">
|
||||||
<img src="https://github.com/faroukbmiled/BOIIIWD/assets/51106560/4c5877eb-81a7-4ae7-99db-3096ab57b12b" width="400" />
|
<img src="https://github.com/faroukbmiled/BOIIIWD/assets/51106560/df54a0d7-f9ab-4061-b8b7-06d9e5992c90" max-width="400" />
|
||||||
</div>
|
</td>
|
||||||
</div>
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
## Usage (exe):
|
## Usage:
|
||||||
- Run [T7xWD.exe](https://git.rimmyscorner.com/Rim/T7x-Workshop-Downloader/releases/download/latest/T7xWD.exe) and use it (it'll ask you to download steamcmd within the app if not found)
|
- Run [T7xWD.exe](https://github.com/faroukbmiled/T7xWD/releases/latest/download/Release.zip) ([VirusTotal Scan](https://www.virustotal.com/gui/file/5ca1367a82893a1f412b59a52431e9ac4219a67a50c294ee86a7d41473826b14/detection))
|
||||||
- That's it slap in your workshop item link or just the id then hit Download and wait for it to finish, when it does just launch your game (Please check [Notes](#notes) before you ask anything)
|
- [Optional] Run as script:```python T7xwd_package\T7xwd.py```
|
||||||
- If the exe is getting flagged as a virus by your ac it is obviously a false positive, if you still do not trust it you can [compile/freeze](#freezing) it yourself ([VirusTotal Scan](https://www.virustotal.com/gui/file/9df159098638ab8a8bec7205eeb271cb5891c19cdbb81bcd5368dfc1ef213f76/detection))
|
|
||||||
|
|
||||||
## Usage (script):
|
|
||||||
- ```pip install -r requirements.txt``` -> use my modified [CTkToolTip](./CTkToolTip) and [CTkListbox](./CTkListbox) for v0.2.8 and up
|
|
||||||
- ```python T7xwd_package\T7xwd.py```
|
|
||||||
- Slap in your workshop item link for example: "https://steamcommunity.com/sharedfiles/filedetails/?id=3011930738" or just the id 3011930738
|
|
||||||
|
|
||||||
## Features:
|
## Features:
|
||||||
- Improves steamcmd's stability while downloading
|
- Improved download stability
|
||||||
- Auto installs mods and maps to T7x
|
- Auto installs mods and maps
|
||||||
- Queue -> download items in queue
|
- Queue -> download items in queue
|
||||||
- Library tab -> lists your downloaded items
|
- Library tab -> lists your downloaded items
|
||||||
- Item updater -> Checks your items for updates (redownloads them,no way for now to "update" them only) -> Under Library tab
|
- Item updater -> checks your items for updates
|
||||||
- Steam to T7x -> Item mover (moves items (mods,maps) from steam to T7x client) -> Under settings tab
|
- Workshop Transfer -> copy/move items from the workshop folder into the game directory
|
||||||
- Themes -> Under settings tab
|
- Custom Themes
|
||||||
- Bunch of useful settings -> Under settings tab
|
|
||||||
|
|
||||||
<a name="freezing"></a>
|
## Notes:
|
||||||
## Freezing into an exe (pyinstaller):
|
- Steamcmd will be downloaded if it is not installed <br>
|
||||||
- ```pip install -r requirements.txt``` -> use my modified [CTkToolTip](./CTkToolTip) and [CTkListbox](./CTkListbox) for v0.2.8 and up.
|
- Initializing SteamCMD for the first time could take some time depending on your internet speed <br>
|
||||||
|
|
||||||
|
#### Mouse Bindings:
|
||||||
|
Library Tab:
|
||||||
|
|
||||||
|
* Mouse1 -> copy id
|
||||||
|
* Ctrl + Mouse1 -> append to clipboard
|
||||||
|
* Mouse2 (scroll wheel button) -> open item path in file explorer
|
||||||
|
* Mouse3 (Right click) -> copy path
|
||||||
|
|
||||||
|
## Building from Source:
|
||||||
|
- ```pip install -r requirements.txt``` -> use my modified [CTkToolTip](./CTkToolTip) and [CTkListbox](./CTkListbox)
|
||||||
- ```python build.py```
|
- ```python build.py```
|
||||||
|
|
||||||
## Queue tab (beta)
|
|
||||||
|
|
||||||
- added Queue tab which has a text field that you can slap in workshop ids/links in 2 formats, for example:<br>
|
|
||||||
|
|
||||||
|
|
||||||
```3010399939,2976006537,2118338989```
|
|
||||||
or <br>
|
|
||||||
```3010399939
|
|
||||||
2976006537
|
|
||||||
2118338989
|
|
||||||
2113146805
|
|
||||||
```
|
|
||||||
|
|
||||||
## Hidden Config Options:
|
|
||||||
- Added a way to update invalid Items (in details) -> add ```update_invalid = yes``` to config.ini
|
|
||||||
- Added a way to download Beta items that normally will throw invalid item warning -> add ```skip_invalid = no``` to config.ini
|
|
||||||
|
|
||||||
<a name="notes"></a>
|
|
||||||
### Notes:
|
|
||||||
* It saves your input except for workshop id <br>
|
|
||||||
* If you do not know where to find your map in-game check this [video](https://youtu.be/XIQjfXXlgQs?t=260) out ,for mods find "mods" in the game's main menu <br>
|
|
||||||
* Initializing SteamCMD for the first time could take some time depending on your internet speed <br>
|
|
||||||
* New item update window: Right click on an item (mouse3) -> will open the item in the browser (Steam Workshop) <br>
|
|
||||||
* T7xWD requires having "T7xwd_library.json" in the app's directory for the new features to work -> clicking on the library tab will generate the JSON file (please don't touch it) <br>
|
|
||||||
* v0.3.1 and up program will use windows registry to save window coordinates (height , width ,x_pos, y_pos)
|
|
||||||
* For Item Updater to recognize your Item as a valid one is to have it's folder named either "FolderName ,"PublisherID" or "FolderName_PublisherID" (taken from workshop.json from each item) -> Invalid items will have a warning icon in library and will not be checked for updates -> Downloading items from T7xwd will be valid by default
|
|
||||||
* Invalid items will still work in game but will not be checked for updates
|
|
||||||
|
|
||||||
#### PS (Library tab): <br>
|
|
||||||
* Mouse1 -> copy id <br>
|
|
||||||
* Mouse2 (scroll wheel btn) -> Open item path in explorer <br>
|
|
||||||
* Mouse3 -> Copy path <br>
|
|
||||||
* Ctrl + Mouse 1 (after Mouse1) -> Append to clipboard
|
|
||||||
|
|
||||||
### Known bugs: <br>
|
|
||||||
* Rare UI bug => instead of showing a warning message, its window goes invisible and leads to the whole ui becoming unclickable (end the task from task manager) <br>
|
|
||||||
* Possible logic bugs related to the progress bar , sometimes it carries on progressing when you pressed stop => please raise an issue if this happens often <br>
|
|
||||||
* If the exe is getting flagged as a virus by your ac it is obviously a false positive, if you still do not trust it you can [compile/freeze](#freezing) it yourself <br>
|
|
||||||
* [VirusTotal](https://www.virustotal.com/gui/file/9df159098638ab8a8bec7205eeb271cb5891c19cdbb81bcd5368dfc1ef213f76/detection) <br>
|
|
||||||
|
|
||||||
### todos:
|
|
||||||
- [x] add a menu that shows you current installed mods/maps
|
|
||||||
- [x] fix the progress bar => progress bar logic based on an estimation
|
|
||||||
- [x] other improvements regarding the download (steamcmd likes to fail sometimes for no reason) => added a way to keep looping when steamcmd crashes and it will eventually finishes
|
|
||||||
- [x] add a queue window that you can slap in a bunch of items to download sequentially and or simultaneously
|
|
||||||
- [ ] add an option to login with your account => delayed (do we really need it?)
|
|
||||||
|
|
||||||
### Themes:
|
|
||||||
- If you choose "custom" theme a file called T7xwd_theme.json will be created in the current folder (where the exe at) , Don't add anything or edit any keyes just modify the colours, If you mess up something you can just rename the file and it'll go back to the default theme (you can always press custom again and the file will be created again, based on which theme you choose before)
|
|
||||||
|
7
build.py
7
build.py
@ -1,5 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import PyInstaller.__main__
|
import PyInstaller.__main__
|
||||||
from distutils.sysconfig import get_python_lib
|
from distutils.sysconfig import get_python_lib
|
||||||
|
|
||||||
@ -29,5 +28,7 @@ PyInstaller.__main__.run([
|
|||||||
"--add-data", f"{site_packages_path}/CTkToolTip;CTkToolTip",
|
"--add-data", f"{site_packages_path}/CTkToolTip;CTkToolTip",
|
||||||
])
|
])
|
||||||
|
|
||||||
current_directory = os.path.dirname(__file__)
|
# create symbolic hardlink to main directory
|
||||||
shutil.copy2(os.path.join(current_directory, "dist", "T7xWD.exe"), current_directory)
|
if os.path.exists("T7xWD.exe"):
|
||||||
|
os.remove("T7xWD.exe")
|
||||||
|
os.link('dist/T7xWD.exe', 'T7xWD.exe')
|
||||||
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@ -3,12 +3,13 @@ from src.imports import *
|
|||||||
|
|
||||||
# Start helper functions
|
# Start helper functions
|
||||||
|
|
||||||
#testing app offline
|
# testing app offline
|
||||||
# import socket
|
# import socket
|
||||||
# def guard(*args, **kwargs):
|
# def guard(*args, **kwargs):
|
||||||
# pass
|
# pass
|
||||||
# socket.socket = guard
|
# socket.socket = guard
|
||||||
|
|
||||||
|
|
||||||
def check_config(name, fallback=None):
|
def check_config(name, fallback=None):
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read(CONFIG_FILE_PATH)
|
config.read(CONFIG_FILE_PATH)
|
||||||
@ -16,6 +17,7 @@ def check_config(name, fallback=None):
|
|||||||
return config.get("Settings", name, fallback=fallback)
|
return config.get("Settings", name, fallback=fallback)
|
||||||
return config.get("Settings", name, fallback="")
|
return config.get("Settings", name, fallback="")
|
||||||
|
|
||||||
|
|
||||||
def save_config(name, value):
|
def save_config(name, value):
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read(CONFIG_FILE_PATH)
|
config.read(CONFIG_FILE_PATH)
|
||||||
@ -24,25 +26,32 @@ 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 check_custom_theme(theme_name):
|
def check_custom_theme(theme_name):
|
||||||
if os.path.exists(os.path.join(APPLICATION_PATH, theme_name)):
|
if os.path.exists(os.path.join(APPLICATION_PATH, theme_name)):
|
||||||
return os.path.join(APPLICATION_PATH, theme_name)
|
return os.path.join(APPLICATION_PATH, theme_name)
|
||||||
else:
|
else:
|
||||||
try: return os.path.join(RESOURCES_DIR, theme_name)
|
try:
|
||||||
except: return os.path.join(RESOURCES_DIR, "T7xwd_theme.json")
|
return os.path.join(RESOURCES_DIR, theme_name)
|
||||||
|
except:
|
||||||
|
return os.path.join(RESOURCES_DIR, "T7xwd_theme.json")
|
||||||
|
|
||||||
|
|
||||||
# theme initialization
|
# theme initialization
|
||||||
ctk.set_appearance_mode(check_config("appearance", "Dark")) # Modes: "System" (standard), "Dark", "Light"
|
# Modes: "System" (standard), "Dark", "Light"
|
||||||
|
ctk.set_appearance_mode(check_config("appearance", "Dark"))
|
||||||
try:
|
try:
|
||||||
ctk.set_default_color_theme(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")))
|
ctk.set_default_color_theme(check_custom_theme(
|
||||||
|
check_config("theme", fallback="T7xwd_theme.json")))
|
||||||
except:
|
except:
|
||||||
save_config("theme", "T7xwd_theme.json")
|
save_config("theme", "T7xwd_theme.json")
|
||||||
ctk.set_default_color_theme(os.path.join(RESOURCES_DIR, "T7xwd_theme.json"))
|
ctk.set_default_color_theme(os.path.join(
|
||||||
|
RESOURCES_DIR, "T7xwd_theme.json"))
|
||||||
|
|
||||||
|
|
||||||
def get_latest_release_version():
|
def get_latest_release_version():
|
||||||
try:
|
try:
|
||||||
release_api_url = f"https://git.rimmyscorner.com/api/v1/repos/{GITHUB_REPO}/releases/latest"
|
release_api_url = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"
|
||||||
|
|
||||||
response = requests.get(release_api_url)
|
response = requests.get(release_api_url)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
@ -51,6 +60,7 @@ def get_latest_release_version():
|
|||||||
show_message("Warning", f"Error while checking for updates: \n{e}")
|
show_message("Warning", f"Error while checking for updates: \n{e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def create_update_script(current_exe, new_exe, updater_folder, program_name):
|
def create_update_script(current_exe, new_exe, updater_folder, program_name):
|
||||||
script_content = f"""
|
script_content = f"""
|
||||||
@echo off
|
@echo off
|
||||||
@ -76,6 +86,7 @@ def create_update_script(current_exe, new_exe, updater_folder, program_name):
|
|||||||
|
|
||||||
return script_path
|
return script_path
|
||||||
|
|
||||||
|
|
||||||
def if_internet_available(func):
|
def if_internet_available(func):
|
||||||
if func == "return":
|
if func == "return":
|
||||||
try:
|
try:
|
||||||
@ -83,23 +94,28 @@ def if_internet_available(func):
|
|||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
try:
|
try:
|
||||||
requests.get("https://www.google.com", timeout=3)
|
requests.get("https://www.google.com", timeout=3)
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
except:
|
except:
|
||||||
show_message("Offline", "No internet connection. Please check your internet connection and try again.")
|
show_message(
|
||||||
|
"Offline", "No internet connection. Please check your internet connection and try again.")
|
||||||
return
|
return
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
@if_internet_available
|
@if_internet_available
|
||||||
def check_for_updates_func(window, ignore_up_todate=False):
|
def check_for_updates_func(window, ignore_up_todate=False):
|
||||||
try:
|
try:
|
||||||
latest_version = get_latest_release_version()
|
latest_version = get_latest_release_version()
|
||||||
current_version = VERSION
|
current_version = VERSION
|
||||||
int_latest_version = int(latest_version.replace("v", "").replace(".", ""))
|
int_latest_version = int(
|
||||||
int_current_version = int(current_version.replace("v", "").replace(".", ""))
|
latest_version.replace("v", "").replace(".", ""))
|
||||||
|
int_current_version = int(
|
||||||
|
current_version.replace("v", "").replace(".", ""))
|
||||||
|
|
||||||
if latest_version and int_latest_version > int_current_version:
|
if latest_version and int_latest_version > int_current_version:
|
||||||
msg_box = CTkMessagebox(title="Update Available", message=f"An update is available! Install now?\n\nCurrent Version: {current_version}\nLatest Version: {latest_version}", option_1="View", option_2="No", option_3="Yes", fade_in_duration=int(1), sound=True)
|
msg_box = CTkMessagebox(title="Update Available", message=f"An update is available! Install now?\n\nCurrent Version: {current_version}\nLatest Version: {latest_version}", option_1="View", option_2="No", option_3="Yes", fade_in_duration=int(1), sound=True)
|
||||||
@ -107,7 +123,8 @@ def check_for_updates_func(window, ignore_up_todate=False):
|
|||||||
result = msg_box.get()
|
result = msg_box.get()
|
||||||
|
|
||||||
if result == "View":
|
if result == "View":
|
||||||
webbrowser.open(f"https://git.rimmyscorner.com/{GITHUB_REPO}/releases/latest")
|
webbrowser.open(
|
||||||
|
f"https://github.com/{GITHUB_REPO}/releases/latest")
|
||||||
|
|
||||||
if result == "Yes":
|
if result == "Yes":
|
||||||
from src.update_window import UpdateWindow
|
from src.update_window import UpdateWindow
|
||||||
@ -125,15 +142,18 @@ def check_for_updates_func(window, ignore_up_todate=False):
|
|||||||
elif int_latest_version == int_current_version:
|
elif int_latest_version == int_current_version:
|
||||||
if ignore_up_todate:
|
if ignore_up_todate:
|
||||||
return
|
return
|
||||||
msg_box = CTkMessagebox(title="Up to Date!", message="No Updates Available!", option_1="Ok", sound=True)
|
msg_box = CTkMessagebox(
|
||||||
|
title="Up to Date!", message="No Updates Available!", option_1="Ok", sound=True)
|
||||||
result = msg_box.get()
|
result = msg_box.get()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
show_message("Error!", "An error occured while checking for updates!\nCheck your internet and try again")
|
show_message(
|
||||||
|
"Error!", "An error occured while checking for updates!\nCheck your internet and try again")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
show_message("Error", f"Error while checking for updates: \n{e}", icon="cancel")
|
show_message("Error", f"Error while checking for updates: \n{e}", icon="cancel")
|
||||||
|
|
||||||
|
|
||||||
def extract_workshop_id(link):
|
def extract_workshop_id(link):
|
||||||
try:
|
try:
|
||||||
pattern = r'(?<=id=)(\d+)'
|
pattern = r'(?<=id=)(\d+)'
|
||||||
@ -146,6 +166,7 @@ def extract_workshop_id(link):
|
|||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def check_steamcmd():
|
def check_steamcmd():
|
||||||
steamcmd_path = get_steamcmd_path()
|
steamcmd_path = get_steamcmd_path()
|
||||||
steamcmd_exe_path = os.path.join(steamcmd_path, "steamcmd.exe")
|
steamcmd_exe_path = os.path.join(steamcmd_path, "steamcmd.exe")
|
||||||
@ -155,25 +176,31 @@ def check_steamcmd():
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def initialize_steam(master):
|
def initialize_steam(master):
|
||||||
try:
|
try:
|
||||||
steamcmd_path = get_steamcmd_path()
|
steamcmd_path = get_steamcmd_path()
|
||||||
steamcmd_exe_path = os.path.join(steamcmd_path, "steamcmd.exe")
|
steamcmd_exe_path = os.path.join(steamcmd_path, "steamcmd.exe")
|
||||||
process = subprocess.Popen([steamcmd_exe_path, "+quit"], creationflags=subprocess.CREATE_NEW_CONSOLE)
|
process = subprocess.Popen(
|
||||||
|
[steamcmd_exe_path, "+quit"], creationflags=subprocess.CREATE_NEW_CONSOLE)
|
||||||
master.attributes('-alpha', 0.0)
|
master.attributes('-alpha', 0.0)
|
||||||
process.wait()
|
process.wait()
|
||||||
if is_steamcmd_initialized():
|
if is_steamcmd_initialized():
|
||||||
show_message("SteamCMD has terminated!", "T7xWD is ready for action.", icon="info")
|
show_message("SteamCMD has terminated!",
|
||||||
|
"T7xWD is ready for action.", icon="info")
|
||||||
else:
|
else:
|
||||||
show_message("SteamCMD has terminated!!", "SteamCMD isn't initialized yet")
|
show_message("SteamCMD has terminated!!",
|
||||||
|
"SteamCMD isn't initialized yet")
|
||||||
except:
|
except:
|
||||||
show_message("Error!", "An error occurred please check your paths and try again.", icon="cancel")
|
show_message(
|
||||||
|
"Error!", "An error occurred please check your paths and try again.", icon="cancel")
|
||||||
master.attributes('-alpha', 1.0)
|
master.attributes('-alpha', 1.0)
|
||||||
|
|
||||||
|
|
||||||
@if_internet_available
|
@if_internet_available
|
||||||
def valid_id(workshop_id):
|
def valid_id(workshop_id):
|
||||||
data = item_steam_api(workshop_id)
|
data = item_steam_api(workshop_id)
|
||||||
if check_config("skip_invalid", "skip") == "no":
|
if check_config("skip_invalid", "on") == "off":
|
||||||
if data:
|
if data:
|
||||||
return True
|
return True
|
||||||
if "consumer_app_id" in data['response']['publishedfiledetails'][0]:
|
if "consumer_app_id" in data['response']['publishedfiledetails'][0]:
|
||||||
@ -181,6 +208,7 @@ def valid_id(workshop_id):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
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"
|
||||||
@ -191,27 +219,31 @@ def convert_speed(speed_bytes):
|
|||||||
else:
|
else:
|
||||||
return speed_bytes / (1024 * 1024 * 1024), "GB/s"
|
return speed_bytes / (1024 * 1024 * 1024), "GB/s"
|
||||||
|
|
||||||
|
|
||||||
def create_default_config():
|
def create_default_config():
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config["Settings"] = {
|
config["Settings"] = {
|
||||||
"SteamCMDPath": APPLICATION_PATH,
|
"SteamCMDPath": APPLICATION_PATH,
|
||||||
"DestinationFolder": "",
|
"DestinationFolder": "",
|
||||||
"checkforupdtes": "on",
|
"checkforupdates": "on",
|
||||||
"console": "off"
|
"console": "off"
|
||||||
}
|
}
|
||||||
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 get_steamcmd_path():
|
def get_steamcmd_path():
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read(CONFIG_FILE_PATH)
|
config.read(CONFIG_FILE_PATH)
|
||||||
return config.get("Settings", "SteamCMDPath", fallback=APPLICATION_PATH)
|
return config.get("Settings", "SteamCMDPath", fallback=APPLICATION_PATH)
|
||||||
|
|
||||||
|
|
||||||
def extract_json_data(json_path, key):
|
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.get(key, '')
|
return data.get(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']:
|
||||||
if size_in_bytes < 1024.0:
|
if size_in_bytes < 1024.0:
|
||||||
@ -220,6 +252,7 @@ def convert_bytes_to_readable(size_in_bytes, no_symb=None):
|
|||||||
return f"{size_in_bytes:.2f} {unit}"
|
return f"{size_in_bytes:.2f} {unit}"
|
||||||
size_in_bytes /= 1024.0
|
size_in_bytes /= 1024.0
|
||||||
|
|
||||||
|
|
||||||
def get_workshop_file_size(workshop_id, raw=None):
|
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)
|
||||||
@ -230,6 +263,10 @@ def get_workshop_file_size(workshop_id, raw=None):
|
|||||||
if raw:
|
if raw:
|
||||||
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(",", "")
|
||||||
|
if "GB" in file_size_text:
|
||||||
|
file_size_in_gb = float(file_size_text.replace(" GB", ""))
|
||||||
|
file_size_in_bytes = int(file_size_in_gb * 1024 * 1024 * 1024)
|
||||||
|
else:
|
||||||
file_size_in_mb = float(file_size_text.replace(" MB", ""))
|
file_size_in_mb = float(file_size_text.replace(" MB", ""))
|
||||||
file_size_in_bytes = int(file_size_in_mb * 1024 * 1024)
|
file_size_in_bytes = int(file_size_in_mb * 1024 * 1024)
|
||||||
return convert_bytes_to_readable(file_size_in_bytes)
|
return convert_bytes_to_readable(file_size_in_bytes)
|
||||||
@ -237,16 +274,23 @@ def get_workshop_file_size(workshop_id, raw=None):
|
|||||||
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(",", "")
|
||||||
|
if "GB" in file_size_text:
|
||||||
|
file_size_in_gb = float(file_size_text.replace(" GB", ""))
|
||||||
|
file_size_in_bytes = int(file_size_in_gb * 1024 * 1024 * 1024)
|
||||||
|
else:
|
||||||
file_size_in_mb = float(file_size_text.replace(" MB", ""))
|
file_size_in_mb = float(file_size_text.replace(" MB", ""))
|
||||||
file_size_in_bytes = int(file_size_in_mb * 1024 * 1024)
|
file_size_in_bytes = int(file_size_in_mb * 1024 * 1024)
|
||||||
return file_size_in_bytes
|
return file_size_in_bytes
|
||||||
return None
|
return None
|
||||||
except:
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def show_message(title, message, icon="warning", _return=False, option_1="No", option_2="Ok"):
|
def show_message(title, message, icon="warning", _return=False, option_1="No", option_2="Ok"):
|
||||||
if _return:
|
if _return:
|
||||||
msg = CTkMessagebox(title=title, message=message, icon=icon, option_1=option_1, option_2=option_2, sound=True)
|
msg = CTkMessagebox(title=title, message=message, icon=icon,
|
||||||
|
option_1=option_1, option_2=option_2, sound=True)
|
||||||
response = msg.get()
|
response = msg.get()
|
||||||
if response == option_1:
|
if response == option_1:
|
||||||
return False
|
return False
|
||||||
@ -259,18 +303,22 @@ def show_message(title, message, icon="warning", _return=False, option_1="No", o
|
|||||||
CTkMessagebox(title=title, message=message, icon=icon, sound=True)
|
CTkMessagebox(title=title, message=message, icon=icon, sound=True)
|
||||||
main_app.app.after(0, callback)
|
main_app.app.after(0, callback)
|
||||||
|
|
||||||
def launch_T7x_func(path):
|
|
||||||
procname = "t7x.exe"
|
def launch_game_func(path, procname="BlackOps3.exe", flags=""):
|
||||||
|
if not procname.endswith(('.exe', '.bat', '.sh', '.lnk')):
|
||||||
|
procname += '.exe'
|
||||||
try:
|
try:
|
||||||
if procname in (p.name() for p in psutil.process_iter()):
|
if procname in (p.name() for p in psutil.process_iter()):
|
||||||
for proc in psutil.process_iter():
|
for proc in psutil.process_iter():
|
||||||
if proc.name() == procname:
|
if proc.name() == procname:
|
||||||
proc.kill()
|
proc.kill()
|
||||||
T7x_path = os.path.join(path, procname)
|
game_path = os.path.join(path, procname)
|
||||||
subprocess.Popen([T7x_path ,"-launch"] , cwd=path)
|
subprocess.Popen([game_path, flags], cwd=path)
|
||||||
show_message("Please wait!", "The game has launched in the background it will open up in a sec!", icon="info")
|
show_message(
|
||||||
|
"Please wait!", "The game has launched in the background it will open up in a sec!", icon="info")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
show_message("Error: Failed to launch T7x", f"Failed to launch t7x.exe\nMake sure to put in your correct T7x path\n{e}")
|
show_message(f"Error: Failed to launch game", f"Failed to start {procname}\n\nMake sure the game path is correct.\n\n{e}")
|
||||||
|
|
||||||
|
|
||||||
def remove_tree(folder_path, show_error=None):
|
def remove_tree(folder_path, show_error=None):
|
||||||
if show_error:
|
if show_error:
|
||||||
@ -283,11 +331,13 @@ def remove_tree(folder_path, show_error=None):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def convert_seconds(seconds):
|
def convert_seconds(seconds):
|
||||||
minutes, seconds = divmod(seconds, 60)
|
minutes, seconds = divmod(seconds, 60)
|
||||||
hours, minutes = divmod(minutes, 60)
|
hours, minutes = divmod(minutes, 60)
|
||||||
return hours, minutes, seconds
|
return hours, minutes, seconds
|
||||||
|
|
||||||
|
|
||||||
def get_folder_size(folder_path):
|
def get_folder_size(folder_path):
|
||||||
total_size = 0
|
total_size = 0
|
||||||
for path, dirs, files in os.walk(folder_path):
|
for path, dirs, files in os.walk(folder_path):
|
||||||
@ -296,6 +346,7 @@ def get_folder_size(folder_path):
|
|||||||
total_size += os.stat(fp).st_size
|
total_size += os.stat(fp).st_size
|
||||||
return total_size
|
return total_size
|
||||||
|
|
||||||
|
|
||||||
def is_steamcmd_initialized():
|
def is_steamcmd_initialized():
|
||||||
steamcmd_path = get_steamcmd_path()
|
steamcmd_path = get_steamcmd_path()
|
||||||
steamcmd_exe_path = os.path.join(steamcmd_path, "steamcmd.exe")
|
steamcmd_exe_path = os.path.join(steamcmd_path, "steamcmd.exe")
|
||||||
@ -304,6 +355,7 @@ def is_steamcmd_initialized():
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def get_button_state_colors(file_path, state):
|
def get_button_state_colors(file_path, state):
|
||||||
try:
|
try:
|
||||||
with open(file_path, 'r') as json_file:
|
with open(file_path, 'r') as json_file:
|
||||||
@ -321,10 +373,12 @@ def get_button_state_colors(file_path, state):
|
|||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def reset_steamcmd(no_warn=None):
|
def reset_steamcmd(no_warn=None):
|
||||||
steamcmd_path = get_steamcmd_path()
|
steamcmd_path = get_steamcmd_path()
|
||||||
|
|
||||||
directories_to_reset = ["steamapps", "dumps", "logs", "depotcache", "appcache","userdata",]
|
directories_to_reset = ["steamapps", "dumps",
|
||||||
|
"logs", "depotcache", "appcache", "userdata",]
|
||||||
|
|
||||||
for directory in directories_to_reset:
|
for directory in directories_to_reset:
|
||||||
directory_path = os.path.join(steamcmd_path, directory)
|
directory_path = os.path.join(steamcmd_path, directory)
|
||||||
@ -338,10 +392,13 @@ def reset_steamcmd(no_warn=None):
|
|||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
|
|
||||||
if not no_warn:
|
if not no_warn:
|
||||||
show_message("Success!", "SteamCMD has been reset successfully!", icon="info")
|
show_message(
|
||||||
|
"Success!", "SteamCMD has been reset successfully!", icon="info")
|
||||||
else:
|
else:
|
||||||
if not no_warn:
|
if not no_warn:
|
||||||
show_message("Warning!", "steamapps folder was not found, maybe already removed?", icon="warning")
|
show_message(
|
||||||
|
"Warning!", "steamapps folder was not found, maybe already removed?", icon="warning")
|
||||||
|
|
||||||
|
|
||||||
def get_item_name(id):
|
def get_item_name(id):
|
||||||
try:
|
try:
|
||||||
@ -355,8 +412,52 @@ def get_item_name(id):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# you gotta use my modded CTkToolTip originaly by Akascape
|
# you gotta use my modded CTkToolTip originaly by Akascape
|
||||||
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, topmost=topmost)
|
|
||||||
|
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, topmost=topmost)
|
||||||
|
|
||||||
|
|
||||||
|
def get_update_time_from_html(workshop_id):
|
||||||
|
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"
|
||||||
|
url = f"https://steamcommunity.com/sharedfiles/filedetails/?id={workshop_id}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(url)
|
||||||
|
response.raise_for_status()
|
||||||
|
content = response.text
|
||||||
|
|
||||||
|
soup = BeautifulSoup(content, "html.parser")
|
||||||
|
|
||||||
|
details_stats_container = soup.find(
|
||||||
|
"div", class_="detailsStatsContainerRight")
|
||||||
|
if details_stats_container:
|
||||||
|
details_stat_elements = details_stats_container.find_all(
|
||||||
|
"div", class_="detailsStatRight")
|
||||||
|
try:
|
||||||
|
date_updated = details_stat_elements[2].text.strip()
|
||||||
|
except:
|
||||||
|
date_updated = None
|
||||||
|
|
||||||
|
if not date_updated:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
date_updated = datetime.strptime(
|
||||||
|
date_updated, date_format_with_year)
|
||||||
|
except ValueError:
|
||||||
|
date_updated = datetime.strptime(
|
||||||
|
date_updated + f", {current_year}", date_format_with_added_year)
|
||||||
|
|
||||||
|
return int(date_updated.timestamp())
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting update time for URL {url}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def check_item_date(down_date, date_updated, format=False):
|
def check_item_date(down_date, date_updated, format=False):
|
||||||
current_year = datetime.now().year
|
current_year = datetime.now().year
|
||||||
@ -364,15 +465,19 @@ def check_item_date(down_date, date_updated, format=False):
|
|||||||
date_format_with_added_year = "%d %b @ %I:%M%p, %Y"
|
date_format_with_added_year = "%d %b @ %I:%M%p, %Y"
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
download_datetime = datetime.strptime(down_date, date_format_with_year)
|
download_datetime = datetime.strptime(
|
||||||
|
down_date, date_format_with_year)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
download_datetime = datetime.strptime(down_date + f", {current_year}", date_format_with_added_year)
|
download_datetime = datetime.strptime(
|
||||||
|
down_date + f", {current_year}", date_format_with_added_year)
|
||||||
|
|
||||||
if format:
|
if format:
|
||||||
try:
|
try:
|
||||||
date_updated = datetime.strptime(date_updated, date_format_with_year)
|
date_updated = datetime.strptime(
|
||||||
|
date_updated, date_format_with_year)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
date_updated = datetime.strptime(date_updated + f", {current_year}", date_format_with_added_year)
|
date_updated = datetime.strptime(
|
||||||
|
date_updated + f", {current_year}", date_format_with_added_year)
|
||||||
|
|
||||||
if date_updated >= download_datetime:
|
if date_updated >= download_datetime:
|
||||||
return True
|
return True
|
||||||
@ -381,6 +486,7 @@ def check_item_date(down_date, date_updated, format=False):
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_window_size_from_registry():
|
def get_window_size_from_registry():
|
||||||
try:
|
try:
|
||||||
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, REGISTRY_KEY_PATH, 0, winreg.KEY_READ) as key:
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, REGISTRY_KEY_PATH, 0, winreg.KEY_READ) as key:
|
||||||
@ -392,16 +498,19 @@ def get_window_size_from_registry():
|
|||||||
except (FileNotFoundError, OSError, ValueError, FileNotFoundError):
|
except (FileNotFoundError, OSError, ValueError, FileNotFoundError):
|
||||||
return None, None, None, None
|
return None, None, None, None
|
||||||
|
|
||||||
|
|
||||||
def save_window_size_to_registry(width, height, x, y):
|
def save_window_size_to_registry(width, height, x, y):
|
||||||
try:
|
try:
|
||||||
with winreg.CreateKey(winreg.HKEY_CURRENT_USER, REGISTRY_KEY_PATH) as key:
|
with winreg.CreateKey(winreg.HKEY_CURRENT_USER, REGISTRY_KEY_PATH) as key:
|
||||||
winreg.SetValueEx(key, "WindowWidth", 0, winreg.REG_SZ, str(width))
|
winreg.SetValueEx(key, "WindowWidth", 0, winreg.REG_SZ, str(width))
|
||||||
winreg.SetValueEx(key, "WindowHeight", 0, winreg.REG_SZ, str(height))
|
winreg.SetValueEx(key, "WindowHeight", 0,
|
||||||
|
winreg.REG_SZ, str(height))
|
||||||
winreg.SetValueEx(key, "WindowX", 0, winreg.REG_SZ, str(x))
|
winreg.SetValueEx(key, "WindowX", 0, winreg.REG_SZ, str(x))
|
||||||
winreg.SetValueEx(key, "WindowY", 0, winreg.REG_SZ, str(y))
|
winreg.SetValueEx(key, "WindowY", 0, winreg.REG_SZ, str(y))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error saving to registry: {e}")
|
print(f"Error saving to registry: {e}")
|
||||||
|
|
||||||
|
|
||||||
def item_steam_api(id):
|
def item_steam_api(id):
|
||||||
try:
|
try:
|
||||||
url = ITEM_INFO_API
|
url = ITEM_INFO_API
|
||||||
@ -416,6 +525,7 @@ def item_steam_api(id):
|
|||||||
print(e)
|
print(e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_item_dates(ids):
|
def get_item_dates(ids):
|
||||||
try:
|
try:
|
||||||
data = {
|
data = {
|
||||||
@ -429,12 +539,44 @@ def get_item_dates(ids):
|
|||||||
|
|
||||||
if "response" in response_data:
|
if "response" in response_data:
|
||||||
item_details = response_data["response"]["publishedfiledetails"]
|
item_details = response_data["response"]["publishedfiledetails"]
|
||||||
return {item["publishedfileid"]: item["time_updated"] for item in item_details}
|
return_list = {item["publishedfileid"]: item.get(
|
||||||
|
"time_updated", None) for item in item_details}
|
||||||
|
return return_list
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print("Error: could not fetch all update times. Breaking early.")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def isNullOrWhiteSpace(str):
|
||||||
|
if (str is None) or (str == "") or (str.isspace()):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def concatenate_sublists(a):
|
||||||
|
out = []
|
||||||
|
for sublist in a:
|
||||||
|
out.extend(sublist)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def nextnonexistentdir(f, dir=os.path.dirname(os.path.realpath(__file__))):
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
def already_exists(i):
|
||||||
|
if i==0 and os.path.exists(os.path.join(dir, (f).strip())):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return os.path.exists(os.path.join(dir, (f + f'_{str(i)}').strip()))
|
||||||
|
|
||||||
|
while already_exists(i):
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
root_i_ext = [f, i]
|
||||||
|
|
||||||
|
return root_i_ext
|
||||||
|
|
||||||
# End helper functions
|
# End helper functions
|
||||||
|
@ -46,4 +46,4 @@ LIBRARY_FILE = "T7xwd_library.json"
|
|||||||
RESOURCES_DIR = os.path.join(os.path.dirname(__file__), '..', 'resources')
|
RESOURCES_DIR = os.path.join(os.path.dirname(__file__), '..', 'resources')
|
||||||
UPDATER_FOLDER = "update"
|
UPDATER_FOLDER = "update"
|
||||||
REGISTRY_KEY_PATH = r"Software\T7xWD"
|
REGISTRY_KEY_PATH = r"Software\T7xWD"
|
||||||
VERSION = "v0.3.3"
|
VERSION = "v0.3.5"
|
@ -231,7 +231,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
item_type, item_name = item[5], item[0]
|
item_type, item_name = item[5], item[0]
|
||||||
return (0, item_name) if item_type == "map" else (1, item_name)
|
return (0, item_name) if item_type == "map" else (1, item_name)
|
||||||
|
|
||||||
def load_items(self, T7xFolder, dont_add=False):
|
def load_items(self, gameFolder, dont_add=False):
|
||||||
if self.refresh_next_time and not dont_add:
|
if self.refresh_next_time and not dont_add:
|
||||||
self.refresh_next_time = False
|
self.refresh_next_time = False
|
||||||
status = self.refresh_items()
|
status = self.refresh_items()
|
||||||
@ -243,8 +243,8 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
self.ids_added.clear()
|
self.ids_added.clear()
|
||||||
self.refresh_next_time = True
|
self.refresh_next_time = True
|
||||||
|
|
||||||
maps_folder = Path(T7xFolder) / "mods"
|
maps_folder = Path(gameFolder) / "mods"
|
||||||
mods_folder = Path(T7xFolder) / "usermaps"
|
mods_folder = Path(gameFolder) / "usermaps"
|
||||||
mod_img = os.path.join(RESOURCES_DIR, "mod_image.png")
|
mod_img = os.path.join(RESOURCES_DIR, "mod_image.png")
|
||||||
map_img = os.path.join(RESOURCES_DIR, "map_image.png")
|
map_img = os.path.join(RESOURCES_DIR, "map_image.png")
|
||||||
b_mod_img = os.path.join(RESOURCES_DIR, "b_mod_image.png")
|
b_mod_img = os.path.join(RESOURCES_DIR, "b_mod_image.png")
|
||||||
@ -262,14 +262,14 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
for folder_path in folders_to_process:
|
for folder_path in folders_to_process:
|
||||||
for zone_path in folder_path.glob("**/zone"):
|
for zone_path in folder_path.glob("*/zone"):
|
||||||
json_path = zone_path / "workshop.json"
|
json_path = zone_path / "workshop.json"
|
||||||
if json_path.exists():
|
if json_path.exists():
|
||||||
|
|
||||||
curr_folder_name = zone_path.parent.name
|
curr_folder_name = zone_path.parent.name
|
||||||
workshop_id = extract_json_data(json_path, "PublisherID") or "None"
|
workshop_id = extract_json_data(json_path, "PublisherID") or "None"
|
||||||
name = re.sub(r'\^\d', '', extract_json_data(json_path, "Title")) or "None"
|
name = re.sub(r'\^\d', '', extract_json_data(json_path, "Title")) or "None"
|
||||||
name = name[:45] + "..." if len(name) > 45 else name
|
name = name[:60] + "..." if len(name) > 60 else name
|
||||||
item_type = extract_json_data(json_path, "Type") or "None"
|
item_type = extract_json_data(json_path, "Type") or "None"
|
||||||
folder_name = extract_json_data(json_path, "FolderName") or "None"
|
folder_name = extract_json_data(json_path, "FolderName") or "None"
|
||||||
folder_size_bytes = get_folder_size(zone_path.parent)
|
folder_size_bytes = get_folder_size(zone_path.parent)
|
||||||
@ -298,7 +298,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
if curr_folder_name not in self.added_folders:
|
if curr_folder_name not in self.added_folders:
|
||||||
image_path = mod_img if item_type == "mod" else map_img
|
image_path = mod_img if item_type == "mod" else map_img
|
||||||
if not (str(curr_folder_name).strip() == str(workshop_id).strip() or str(curr_folder_name).strip() == str(folder_name).strip()
|
if not (str(curr_folder_name).strip() == str(workshop_id).strip() or str(curr_folder_name).strip() == str(folder_name).strip()
|
||||||
or str(curr_folder_name).strip() == f"{folder_name}_{workshop_id}"):
|
or str(curr_folder_name).strip() == f"{folder_name}_{workshop_id}" or str(curr_folder_name).strip() == f"{folder_name}_duplicated"):
|
||||||
try: self.remove_item_by_option(items_file, curr_folder_name, "folder_name")
|
try: self.remove_item_by_option(items_file, curr_folder_name, "folder_name")
|
||||||
except: pass
|
except: pass
|
||||||
self.item_block_list.add(curr_folder_name)
|
self.item_block_list.add(curr_folder_name)
|
||||||
@ -308,6 +308,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
elif (curr_folder_name not in self.added_folders and (workshop_id in self.ids_added or workshop_id == "None")):
|
elif (curr_folder_name not in self.added_folders and (workshop_id in self.ids_added or workshop_id == "None")):
|
||||||
try: self.remove_item_by_option(items_file, curr_folder_name, "folder_name")
|
try: self.remove_item_by_option(items_file, curr_folder_name, "folder_name")
|
||||||
except: pass
|
except: pass
|
||||||
|
self.item_block_list.add(workshop_id)
|
||||||
text_to_add = re.sub(r'ID:\s+(?:\d+|None)', f'Folder: {curr_folder_name}', text_to_add)
|
text_to_add = re.sub(r'ID:\s+(?:\d+|None)', f'Folder: {curr_folder_name}', text_to_add)
|
||||||
image_path = b_mod_img if item_type == "mod" else b_map_img
|
image_path = b_mod_img if item_type == "mod" else b_map_img
|
||||||
text_to_add += " | ⚠️"
|
text_to_add += " | ⚠️"
|
||||||
@ -325,7 +326,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
"folder_name": curr_folder_name,
|
"folder_name": curr_folder_name,
|
||||||
"json_folder_name": folder_name
|
"json_folder_name": folder_name
|
||||||
}
|
}
|
||||||
# when item is blocked ,item_exists_in_file() returns None for folder_found
|
# when item is blocked item_exists_in_file() returns None for folder_found
|
||||||
if not id_found and folder_found == None:
|
if not id_found and folder_found == None:
|
||||||
self.remove_item_by_option(items_file, curr_folder_name, "folder_name")
|
self.remove_item_by_option(items_file, curr_folder_name, "folder_name")
|
||||||
elif not id_found and not folder_found and curr_folder_name not in self.item_block_list and workshop_id not in self.ids_added:
|
elif not id_found and not folder_found and curr_folder_name not in self.item_block_list and workshop_id not in self.ids_added:
|
||||||
@ -339,14 +340,14 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
f.seek(0)
|
f.seek(0)
|
||||||
json.dump(items_data, f, indent=4)
|
json.dump(items_data, f, indent=4)
|
||||||
|
|
||||||
if id_found and not folder_found and curr_folder_name not in self.item_block_list and workshop_id not in self.ids_added:
|
if curr_folder_name not in self.item_block_list:
|
||||||
self.update_or_add_item_by_id(items_file, item_info, workshop_id)
|
self.update_or_add_item_by_id(items_file, item_info, workshop_id)
|
||||||
|
|
||||||
# keep here cuz of item_exists_in_file() testing
|
# keep here cuz of item_exists_in_file() testing
|
||||||
self.added_folders.add(curr_folder_name)
|
self.added_folders.add(curr_folder_name)
|
||||||
# added that cuz it sometimes can add blocked ids first
|
# added that cuz it sometimes can add blocked ids first
|
||||||
# and legit ids will be blocked cuz theyll be added to "ids_added"
|
# and legit ids will be blocked cuz theyll be added to "ids_added"
|
||||||
if not workshop_id in self.ids_added and curr_folder_name not in self.item_block_list:
|
if not workshop_id in self.ids_added and curr_folder_name not in self.item_block_list and workshop_id!='None':
|
||||||
self.ids_added.add(workshop_id)
|
self.ids_added.add(workshop_id)
|
||||||
|
|
||||||
# sort items by type then alphabet
|
# sort items by type then alphabet
|
||||||
@ -354,7 +355,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
for item in ui_items_to_add:
|
for item in ui_items_to_add:
|
||||||
self.add_item_helper(*item)
|
self.add_item_helper(*item)
|
||||||
|
|
||||||
if not self.file_cleaned and os.path.exists(items_file):
|
if os.path.exists(items_file):
|
||||||
self.file_cleaned = True
|
self.file_cleaned = True
|
||||||
self.clean_json_file(items_file)
|
self.clean_json_file(items_file)
|
||||||
|
|
||||||
@ -372,22 +373,22 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
self.show_no_items_message(only_up=True)
|
self.show_no_items_message(only_up=True)
|
||||||
return "No items in current selected folder"
|
return "No items in current selected folder"
|
||||||
|
|
||||||
def update_item(self, T7xFolder, id, item_type, foldername):
|
def update_item(self, gameFolder, id, item_type, foldername):
|
||||||
try:
|
try:
|
||||||
if item_type == "map":
|
if item_type == "map":
|
||||||
folder_path = Path(T7xFolder) / "usermaps" / f"{foldername}"
|
folder_path = Path(gameFolder) / "usermaps" / f"{foldername}"
|
||||||
elif item_type == "mod":
|
elif item_type == "mod":
|
||||||
folder_path = Path(T7xFolder) / "mods" / f"{foldername}"
|
folder_path = Path(gameFolder) / "mods" / f"{foldername}"
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported item_type. It must be 'map' or 'mod'.")
|
raise ValueError("Unsupported item_type. It must be 'map' or 'mod'.")
|
||||||
|
|
||||||
for zone_path in folder_path.glob("**/zone"):
|
for zone_path in folder_path.glob("*/zone"):
|
||||||
json_path = zone_path / "workshop.json"
|
json_path = zone_path / "workshop.json"
|
||||||
if json_path.exists():
|
if json_path.exists():
|
||||||
workshop_id = extract_json_data(json_path, "PublisherID")
|
workshop_id = extract_json_data(json_path, "PublisherID")
|
||||||
if workshop_id == id:
|
if workshop_id == id:
|
||||||
name = extract_json_data(json_path, "Title").replace(">", "").replace("^", "")
|
name = extract_json_data(json_path, "Title").replace(">", "").replace("^", "")
|
||||||
name = name[:45] + "..." if len(name) > 45 else name
|
name = name[:60] + "..." if len(name) > 60 else name
|
||||||
item_type = extract_json_data(json_path, "Type")
|
item_type = extract_json_data(json_path, "Type")
|
||||||
folder_name = extract_json_data(json_path, "FolderName")
|
folder_name = extract_json_data(json_path, "FolderName")
|
||||||
size = convert_bytes_to_readable(get_folder_size(zone_path.parent))
|
size = convert_bytes_to_readable(get_folder_size(zone_path.parent))
|
||||||
@ -456,7 +457,8 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
self.added_items.clear()
|
self.added_items.clear()
|
||||||
self.added_folders.clear()
|
self.added_folders.clear()
|
||||||
self.ids_added.clear()
|
self.ids_added.clear()
|
||||||
status = self.load_items(main_app.app.edit_destination_folder.get().strip())
|
|
||||||
|
status = self.load_items( main_app.app.settings_tab.edit_destination_folder.get().strip())
|
||||||
main_app.app.title(f"T7x Workshop Downloader - Library ➜ {status}")
|
main_app.app.title(f"T7x Workshop Downloader - Library ➜ {status}")
|
||||||
# main_app library event needs a return for status => when refresh_next_time is true
|
# main_app library event needs a return for status => when refresh_next_time is true
|
||||||
return status
|
return status
|
||||||
@ -471,7 +473,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
if only_up:
|
if only_up:
|
||||||
return
|
return
|
||||||
self.no_items_label.grid(row=1, column=0, padx=10, pady=(0, 10), sticky="n")
|
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 T7x folder selected.")
|
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 game folder selected.")
|
||||||
|
|
||||||
def hide_no_items_message(self):
|
def hide_no_items_message(self):
|
||||||
self.update_tooltip.configure(message="Check items for updates")
|
self.update_tooltip.configure(message="Check items for updates")
|
||||||
@ -587,7 +589,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
if json_path.exists():
|
if json_path.exists():
|
||||||
workshop_id = extract_json_data(json_path, "PublisherID") or "None"
|
workshop_id = extract_json_data(json_path, "PublisherID") or "None"
|
||||||
name = re.sub(r'\^\w+', '', extract_json_data(json_path, "Title")) or "None"
|
name = re.sub(r'\^\w+', '', extract_json_data(json_path, "Title")) or "None"
|
||||||
map_name = name[:45] + "..." if len(name) > 45 else name
|
map_name = name[:60] + "..." if len(name) > 60 else name
|
||||||
map_mod_type = extract_json_data(json_path, "Type") or "None"
|
map_mod_type = extract_json_data(json_path, "Type") or "None"
|
||||||
preview_iamge = json_path.parent / "previewimage.png"
|
preview_iamge = json_path.parent / "previewimage.png"
|
||||||
if preview_iamge.exists():
|
if preview_iamge.exists():
|
||||||
@ -693,7 +695,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
main_app.app.edit_workshop_id.delete(0, "end")
|
main_app.app.edit_workshop_id.delete(0, "end")
|
||||||
main_app.app.edit_workshop_id.insert(0, workshop_id)
|
main_app.app.edit_workshop_id.insert(0, workshop_id)
|
||||||
main_app.app.main_button_event()
|
main_app.app.main_button_event()
|
||||||
if invalid_warn and check_config("update_invalid", "no") == "yes":
|
if invalid_warn and check_config("update_invalid", "off") == "on":
|
||||||
main_app.app.download_map(update=True, invalid_item_folder=os.path.basename(folder))
|
main_app.app.download_map(update=True, invalid_item_folder=os.path.basename(folder))
|
||||||
else:
|
else:
|
||||||
main_app.app.download_map(update=True)
|
main_app.app.download_map(update=True)
|
||||||
@ -810,8 +812,8 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
update_btn.configure(state="disabled")
|
update_btn.configure(state="disabled")
|
||||||
update_btn_tooltip.configure(message="Currently offline")
|
update_btn_tooltip.configure(message="Currently offline")
|
||||||
view_button_tooltip.configure(message="Currently offline")
|
view_button_tooltip.configure(message="Currently offline")
|
||||||
if check_config("update_invalid", "no") == "yes":
|
if check_config("update_invalid", "off") == "on":
|
||||||
update_btn_tooltip.configure(message="update_invalid is set to 'yes' in config.ini")
|
update_btn_tooltip.configure(message="update_invalid is set to 'on' in config.ini")
|
||||||
elif invalid_warn:
|
elif invalid_warn:
|
||||||
update_btn.configure(text="Update", state="disabled")
|
update_btn.configure(text="Update", state="disabled")
|
||||||
update_btn_tooltip.configure(message="Disabled due to item being blocked or duplicated")
|
update_btn_tooltip.configure(message="Disabled due to item being blocked or duplicated")
|
||||||
@ -869,10 +871,17 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
item_data = get_item_dates(item_ids)
|
item_data = get_item_dates(item_ids)
|
||||||
|
|
||||||
for item_id, date_updated in item_data.items():
|
for item_id, date_updated in item_data.items():
|
||||||
item_date = item_dates[item_id]
|
if not date_updated:
|
||||||
|
try:
|
||||||
|
new_date = get_update_time_from_html(item_id)
|
||||||
|
date_updated = new_date if new_date else 1
|
||||||
|
except:
|
||||||
|
date_updated = 1
|
||||||
|
item_date = item_dates[str(item_id)] if str(item_id) in item_dates else ""
|
||||||
date_updated = datetime.fromtimestamp(date_updated)
|
date_updated = datetime.fromtimestamp(date_updated)
|
||||||
|
|
||||||
if check_item_date(item_date, date_updated):
|
if check_item_date(item_date, date_updated):
|
||||||
|
if item_date != "":
|
||||||
date_updated = date_updated.strftime("%d %b @ %I:%M%p, %Y")
|
date_updated = date_updated.strftime("%d %b @ %I:%M%p, %Y")
|
||||||
self.to_update.add(texts[item_id] + f" | Updated: {date_updated}")
|
self.to_update.add(texts[item_id] + f" | Updated: {date_updated}")
|
||||||
|
|
||||||
@ -884,7 +893,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
lib_data = None
|
lib_data = None
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(APPLICATION_PATH, LIBRARY_FILE)):
|
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 T7x path!, you also need to have at least 1 item!")
|
show_message("Error checking for item updates! -> Setting is on", "Please visit library tab at least once with the correct game path! You also need to have at least 1 item!")
|
||||||
return
|
return
|
||||||
|
|
||||||
with open(os.path.join(APPLICATION_PATH, LIBRARY_FILE), 'r') as file:
|
with open(os.path.join(APPLICATION_PATH, LIBRARY_FILE), 'r') as file:
|
||||||
@ -897,7 +906,7 @@ class LibraryTab(ctk.CTkScrollableFrame):
|
|||||||
if_ids_need_update(item_ids, item_dates, texts)
|
if_ids_need_update(item_ids, item_dates, texts)
|
||||||
|
|
||||||
except:
|
except:
|
||||||
show_message("Error checking for item updates!", "Please visit the library tab at least once with the correct T7x path!, you also need to have at least 1 item!")
|
show_message("Error checking for item updates!", "Please visit the library tab at least once with the correct game path! You also need to have at least 1 item!")
|
||||||
return
|
return
|
||||||
|
|
||||||
check_for_update()
|
check_for_update()
|
||||||
|
@ -23,37 +23,40 @@ class T7xWD(ctk.CTk):
|
|||||||
self.geometry(f"{920}x{560}")
|
self.geometry(f"{920}x{560}")
|
||||||
|
|
||||||
self.minsize(920, 560)
|
self.minsize(920, 560)
|
||||||
|
ctk.set_window_scaling(float(check_config("scaling", 1.0)) + 0.25)
|
||||||
|
|
||||||
if os.path.exists(os.path.join(RESOURCES_DIR, "ryuk.ico")):
|
if os.path.exists(os.path.join(RESOURCES_DIR, "ryuk.ico")):
|
||||||
self.wm_iconbitmap(os.path.join(RESOURCES_DIR, "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)
|
||||||
|
|
||||||
# Qeue frame/tab, keep here or app will start shrinked eveytime
|
# Queue frame/tab, keep here or app will start shrinked eveytime
|
||||||
self.qeueuframe = ctk.CTkFrame(self)
|
self.queue_tab_enabled = False # Enable Queue Tab
|
||||||
self.qeueuframe.columnconfigure(1, weight=1)
|
|
||||||
self.qeueuframe.columnconfigure(2, weight=1)
|
|
||||||
self.qeueuframe.columnconfigure(3, weight=1)
|
|
||||||
self.qeueuframe.rowconfigure(1, weight=1)
|
|
||||||
self.qeueuframe.rowconfigure(2, weight=1)
|
|
||||||
self.qeueuframe.rowconfigure(3, weight=1)
|
|
||||||
self.qeueuframe.rowconfigure(4, weight=1)
|
|
||||||
|
|
||||||
self.workshop_queue_label = ctk.CTkLabel(self.qeueuframe, text="Workshop IDs/Links -> press help to see examples:")
|
self.queueframe = ctk.CTkFrame(self)
|
||||||
self.workshop_queue_label.grid(row=0, column=0, padx=(20, 20), pady=(20, 20), sticky="wns")
|
self.queueframe.columnconfigure(1, weight=1)
|
||||||
|
self.queueframe.columnconfigure(2, weight=1)
|
||||||
|
self.queueframe.columnconfigure(3, weight=1)
|
||||||
|
self.queueframe.rowconfigure(1, weight=1)
|
||||||
|
self.queueframe.rowconfigure(2, weight=0)
|
||||||
|
self.queueframe.rowconfigure(3, weight=0)
|
||||||
|
self.queueframe.rowconfigure(4, weight=0)
|
||||||
|
|
||||||
self.help_button = ctk.CTkButton(master=self.qeueuframe, text="Help", command=self.help_queue_text_func, width=10, height=10, fg_color="#585858")
|
self.workshop_queue_label = ctk.CTkLabel(self.queueframe, text="Batch Downloader:")
|
||||||
self.help_button.grid(row=0, column=0, padx=(352, 0), pady=(23, 0), sticky="en")
|
self.workshop_queue_label.grid(row=0, column=0, padx=(20, 20), pady=(10, 10), sticky="wns")
|
||||||
|
|
||||||
|
self.help_button = ctk.CTkButton(master=self.queueframe, text="Help", command=self.help_queue_text_func, width=10, height=10, fg_color="#585858")
|
||||||
|
self.help_button.grid(row=0, column=3, padx=(0, 20), pady=(10, 0), sticky="en")
|
||||||
self.help_restore_content = None
|
self.help_restore_content = None
|
||||||
|
|
||||||
self.queuetextarea = ctk.CTkTextbox(master=self.qeueuframe, font=("", 15))
|
self.queuetextarea = ctk.CTkTextbox(master=self.queueframe, font=("", 15))
|
||||||
self.queuetextarea.grid(row=1, column=0, columnspan=4, padx=(20, 20), pady=(0, 20), sticky="nwse")
|
self.queuetextarea.grid(row=1, column=0, columnspan=4, padx=(20, 20), pady=(0, 40), sticky="nwse")
|
||||||
|
|
||||||
self.status_text = ctk.CTkLabel(self.qeueuframe, text="Status: Standby!")
|
self.status_text = ctk.CTkLabel(self.queueframe, text="Status: Standby!")
|
||||||
self.status_text.grid(row=3, column=0, padx=(20, 20), pady=(0, 20), sticky="ws")
|
self.status_text.grid(row=1, column=0, padx=(20, 20), pady=(40, 0), sticky="ws")
|
||||||
|
|
||||||
self.skip_boutton = ctk.CTkButton(master=self.qeueuframe, text="Skip", command=self.skip_current_queue_item, width=10, height=10, fg_color="#585858")
|
self.skip_button = ctk.CTkButton(master=self.queueframe, text="Skip", command=self.skip_current_queue_item, width=10, height=10, fg_color="#585858")
|
||||||
|
|
||||||
self.qeueuframe.grid_remove()
|
self.queueframe.grid_remove()
|
||||||
|
|
||||||
# configure grid layout (4x4)
|
# configure grid layout (4x4)
|
||||||
self.grid_columnconfigure(1, weight=1)
|
self.grid_columnconfigure(1, weight=1)
|
||||||
@ -78,18 +81,22 @@ class T7xWD(ctk.CTk):
|
|||||||
self.txt_label.grid(row=1, column=0, padx=20, pady=(20, 10))
|
self.txt_label.grid(row=1, column=0, padx=20, pady=(20, 10))
|
||||||
self.sidebar_main = ctk.CTkButton(self.sidebar_frame, height=28)
|
self.sidebar_main = ctk.CTkButton(self.sidebar_frame, height=28)
|
||||||
self.sidebar_main.grid(row=2, column=0, padx=10, pady=(20, 6))
|
self.sidebar_main.grid(row=2, column=0, padx=10, pady=(20, 6))
|
||||||
|
if self.queue_tab_enabled:
|
||||||
self.sidebar_queue = ctk.CTkButton(self.sidebar_frame, height=28)
|
self.sidebar_queue = ctk.CTkButton(self.sidebar_frame, height=28)
|
||||||
self.sidebar_queue.grid(row=3, column=0, padx=10, pady=6)
|
self.sidebar_queue.grid(row=3, column=0, padx=10, pady=6)
|
||||||
self.sidebar_library = ctk.CTkButton(self.sidebar_frame, height=28)
|
self.sidebar_library = ctk.CTkButton(self.sidebar_frame, height=28)
|
||||||
self.sidebar_library.grid(row=4, column=0, padx=10, pady=6, sticky="n")
|
self.sidebar_library.grid(row=4, column=0, padx=10, pady=6, sticky="n")
|
||||||
|
self.launch_game = ctk.CTkButton(self.sidebar_frame, text="Launch game", command=self.settings_launch_game, height=28)
|
||||||
|
self.launch_game.grid(row=5, column=0, padx=10, pady=6, sticky="n")
|
||||||
self.sidebar_settings = ctk.CTkButton(self.sidebar_frame, height=28)
|
self.sidebar_settings = ctk.CTkButton(self.sidebar_frame, height=28)
|
||||||
self.sidebar_settings.grid(row=5, column=0, padx=10, pady=6, sticky="n")
|
self.sidebar_settings.grid(row=6, column=0, padx=10, pady=6, sticky="n")
|
||||||
|
|
||||||
# create optionsframe
|
# create optionsframe
|
||||||
self.optionsframe = ctk.CTkFrame(self)
|
self.optionsframe = ctk.CTkFrame(self)
|
||||||
self.optionsframe.grid(row=0, column=1, rowspan=2, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
self.optionsframe.grid(row=0, column=1, rowspan=1, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
||||||
self.txt_main = ctk.CTkLabel(self.optionsframe, text="💎 T7xWD 💎", font=(font, 20))
|
self.txt_main = ctk.CTkLabel(self.optionsframe, text="💎 T7xWD 💎", font=(font, 20))
|
||||||
self.txt_main.grid(row=0, column=1, columnspan=5, padx=0, pady=(20, 20), sticky="n")
|
self.txt_main.grid(row=0, column=1, columnspan=1, padx=0, pady=(20, 20), sticky="n")
|
||||||
|
self.queueframe.grid(row=1, column=1, rowspan=1, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
||||||
|
|
||||||
# create slider and progressbar frame
|
# create slider and progressbar frame
|
||||||
self.slider_progressbar_frame = ctk.CTkFrame(self)
|
self.slider_progressbar_frame = ctk.CTkFrame(self)
|
||||||
@ -103,9 +110,6 @@ class T7xWD(ctk.CTk):
|
|||||||
self.slider_progressbar_frame.rowconfigure(2, weight=1)
|
self.slider_progressbar_frame.rowconfigure(2, weight=1)
|
||||||
self.slider_progressbar_frame.rowconfigure(3, weight=1)
|
self.slider_progressbar_frame.rowconfigure(3, weight=1)
|
||||||
|
|
||||||
# self.spacer = ctk.CTkLabel(master=self.slider_progressbar_frame, text="")
|
|
||||||
# self.spacer.grid(row=0, column=0, columnspan=1)
|
|
||||||
|
|
||||||
self.label_speed = ctk.CTkLabel(master=self.slider_progressbar_frame, text="Awaiting Download!")
|
self.label_speed = ctk.CTkLabel(master=self.slider_progressbar_frame, text="Awaiting Download!")
|
||||||
self.label_speed.grid(row=1, column=0, padx=20, pady=(0, 10), sticky="w")
|
self.label_speed.grid(row=1, column=0, padx=20, pady=(0, 10), sticky="w")
|
||||||
self.elapsed_time = ctk.CTkLabel(master=self.slider_progressbar_frame, text="", anchor="center")
|
self.elapsed_time = ctk.CTkLabel(master=self.slider_progressbar_frame, text="", anchor="center")
|
||||||
@ -127,79 +131,61 @@ class T7xWD(ctk.CTk):
|
|||||||
|
|
||||||
# options frame
|
# options frame
|
||||||
self.optionsframe.columnconfigure(1, weight=1)
|
self.optionsframe.columnconfigure(1, weight=1)
|
||||||
self.optionsframe.columnconfigure(2, weight=1)
|
self.optionsframe.columnconfigure(2, weight=0)
|
||||||
self.optionsframe.columnconfigure(3, weight=1)
|
self.optionsframe.columnconfigure(3, weight=0)
|
||||||
self.optionsframe.rowconfigure(1, weight=1)
|
self.optionsframe.rowconfigure(1, weight=0)
|
||||||
self.optionsframe.rowconfigure(2, weight=1)
|
self.optionsframe.rowconfigure(2, weight=0)
|
||||||
self.optionsframe.rowconfigure(3, weight=1)
|
self.optionsframe.rowconfigure(3, weight=0)
|
||||||
self.optionsframe.rowconfigure(4, weight=1)
|
self.optionsframe.rowconfigure(4, weight=0)
|
||||||
|
|
||||||
self.label_workshop_id = ctk.CTkLabel(master=self.optionsframe, text="Enter the Workshop ID or Link of the map/mod you want to download:\n")
|
self.label_workshop_id = ctk.CTkLabel(master=self.optionsframe, text="Enter a Workshop ID or Link to download:\n")
|
||||||
self.label_workshop_id.grid(row=1, column=1, padx=20, pady=(10, 0), columnspan=4, sticky="ws")
|
self.label_workshop_id.grid(row=1, column=1, padx=(10, 5), pady=(10, 0), columnspan=1, sticky="ws")
|
||||||
|
|
||||||
self.check_if_changed = ctk.StringVar()
|
self.check_if_changed = ctk.StringVar()
|
||||||
self.check_if_changed.trace_add("write", self.id_chnaged_handler)
|
self.check_if_changed.trace_add("write", self.id_changed_handler)
|
||||||
self.edit_workshop_id = ctk.CTkEntry(master=self.optionsframe, textvariable=self.check_if_changed)
|
self.edit_workshop_id = ctk.CTkEntry(master=self.optionsframe, textvariable=self.check_if_changed)
|
||||||
self.edit_workshop_id.grid(row=2, column=1, padx=20, pady=(0, 10), columnspan=4, sticky="ewn")
|
self.edit_workshop_id.grid(row=2, column=1, padx=(5, 5), pady=(0, 10), columnspan=1, sticky="ewn")
|
||||||
|
|
||||||
self.button_browse = ctk.CTkButton(master=self.optionsframe, text="Workshop", command=self.open_browser, width=10)
|
self.button_browse = ctk.CTkButton(master=self.optionsframe, text="Workshop", command=self.open_browser, width=10)
|
||||||
self.button_browse.grid(row=2, column=5, padx=(0, 20), pady=(0, 10), sticky="en")
|
self.button_browse.grid(row=2, column=2, padx=(5, 5), pady=(0, 10), sticky="en")
|
||||||
self.button_browse_tooltip = CTkToolTip(self.button_browse, message="Will open steam workshop for T7x in your browser")
|
self.button_browse_tooltip = CTkToolTip(self.button_browse, message="Will open steam workshop in your browser")
|
||||||
|
|
||||||
self.info_button = ctk.CTkButton(master=self.optionsframe, text="Details", command=self.show_map_info, width=10)
|
self.info_button = ctk.CTkButton(master=self.optionsframe, text="Details", command=self.show_map_info, width=10)
|
||||||
self.info_button.grid(row=2, column=5, padx=(0, 20), pady=(0, 10), sticky="wn")
|
self.info_button.grid(row=2, column=3, padx=(5, 10), pady=(0, 10), sticky="wn")
|
||||||
|
|
||||||
self.label_destination_folder = ctk.CTkLabel(master=self.optionsframe, text='Enter Your T7x folder:')
|
|
||||||
self.label_destination_folder.grid(row=3, column=1, padx=20, pady=(0, 0), columnspan=4, sticky="ws")
|
|
||||||
|
|
||||||
self.edit_destination_folder = ctk.CTkEntry(master=self.optionsframe, placeholder_text="Your T7x Instalation folder")
|
|
||||||
self.edit_destination_folder.grid(row=4, column=1, padx=20, pady=(0, 25), columnspan=4, sticky="ewn")
|
|
||||||
|
|
||||||
self.button_T7x_browse = ctk.CTkButton(master=self.optionsframe, text="Select", command=self.open_T7x_browser)
|
|
||||||
self.button_T7x_browse.grid(row=4, column=5, padx=(0, 20), pady=(0, 10), sticky="ewn")
|
|
||||||
|
|
||||||
self.label_steamcmd_path = ctk.CTkLabel(master=self.optionsframe, text="Enter SteamCMD path:")
|
|
||||||
self.label_steamcmd_path.grid(row=5, column=1, padx=20, pady=(0, 0), columnspan=3, sticky="wn")
|
|
||||||
|
|
||||||
self.edit_steamcmd_path = ctk.CTkEntry(master=self.optionsframe, placeholder_text="Enter your SteamCMD path")
|
|
||||||
self.edit_steamcmd_path.grid(row=6, column=1, padx=20, pady=(0, 30), columnspan=4, sticky="ewn")
|
|
||||||
|
|
||||||
self.button_steamcmd_browse = ctk.CTkButton(master=self.optionsframe, text="Select", command=self.open_steamcmd_path_browser)
|
|
||||||
self.button_steamcmd_browse.grid(row=6, column=5, padx=(0, 20), pady=(0, 30), sticky="ewn")
|
|
||||||
|
|
||||||
|
|
||||||
# set default values
|
# set default values
|
||||||
self.active_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")), "button_active_state_color")
|
self.active_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")), "button_active_state_color")
|
||||||
self.normal_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")), "button_normal_state_color")
|
self.normal_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")), "button_normal_state_color")
|
||||||
self.progress_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")), "progress_bar_fill_color")
|
self.progress_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")), "progress_bar_fill_color")
|
||||||
self.settings_tab.appearance_mode_optionemenu.set("Dark")
|
self.settings_tab.appearance_mode_optionemenu.set("Dark")
|
||||||
self.settings_tab.scaling_optionemenu.set("100%")
|
self.settings_tab.scaling_optionemenu.set("80%")
|
||||||
self.progress_bar.set(0.0)
|
self.progress_bar.set(0.0)
|
||||||
self.progress_bar.configure(progress_color=self.progress_color)
|
self.progress_bar.configure(progress_color=self.progress_color)
|
||||||
self.hide_settings_widgets()
|
self.hide_settings_widgets()
|
||||||
self.button_stop.configure(state="disabled")
|
self.button_stop.configure(state="disabled")
|
||||||
self.is_pressed = False
|
self.is_pressed = False
|
||||||
self.queue_enabled = False
|
|
||||||
self.queue_stop_button = False
|
self.queue_stop_button = False
|
||||||
self.is_downloading = False
|
self.is_downloading = False
|
||||||
|
self.is_steamcmd_updating = False
|
||||||
self.item_skipped = False
|
self.item_skipped = False
|
||||||
|
self.steam_updater_size = "Unknown size"
|
||||||
self.fail_threshold = 0
|
self.fail_threshold = 0
|
||||||
|
|
||||||
# sidebar windows bouttons
|
# sidebar windows buttons
|
||||||
self.sidebar_main.configure(command=self.main_button_event, text="Main ⬇️", fg_color=(self.active_color), state="active")
|
self.sidebar_main.configure(command=self.main_button_event, text="Main ⬇️", fg_color=(self.active_color), state="active")
|
||||||
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(text="Queue 🚧", command=self.queue_button_event)
|
if self.queue_tab_enabled: self.sidebar_queue.configure(text="Queue 🚧", command=self.queue_button_event)
|
||||||
sidebar_settings_button_image = os.path.join(RESOURCES_DIR, "sett10.png")
|
sidebar_settings_button_image = os.path.join(RESOURCES_DIR, "sett10.png")
|
||||||
self.sidebar_settings.configure(command=self.settings_button_event, text="", image=ctk.CTkImage(Image.open(sidebar_settings_button_image), size=(int(35), int(35))), fg_color="transparent", width=45, height=45)
|
self.sidebar_settings.configure(command=self.settings_button_event, text="", image=ctk.CTkImage(Image.open(sidebar_settings_button_image), size=(int(35), int(35))), fg_color="transparent", width=45, height=45)
|
||||||
self.sidebar_settings_tooltip = CTkToolTip(self.sidebar_settings, message="Settings")
|
self.sidebar_settings_tooltip = CTkToolTip(self.sidebar_settings, message="Settings")
|
||||||
self.sidebar_library_tooltip = CTkToolTip(self.sidebar_library, message="Experimental")
|
self.sidebar_library_tooltip = CTkToolTip(self.sidebar_library, message="Experimental")
|
||||||
self.sidebar_queue_tooltip = CTkToolTip(self.sidebar_queue, message="Experimental")
|
if self.queue_tab_enabled: self.sidebar_queue_tooltip = CTkToolTip(self.sidebar_queue, message="Experimental")
|
||||||
self.bind("<Configure>", lambda e: self.save_window_size_position())
|
self.bind("<Configure>", lambda e: self.save_window_size_position())
|
||||||
|
|
||||||
# context_menus
|
# context_menus
|
||||||
self.create_context_menu(self.edit_workshop_id)
|
self.create_context_menu(self.edit_workshop_id)
|
||||||
self.create_context_menu(self.edit_destination_folder)
|
self.create_context_menu(self.settings_tab.edit_destination_folder)
|
||||||
self.create_context_menu(self.edit_steamcmd_path)
|
self.create_context_menu(self.settings_tab.edit_steamcmd_path)
|
||||||
self.create_context_menu(self.queuetextarea, textbox=True)
|
self.create_context_menu(self.queuetextarea, textbox=True)
|
||||||
self.create_context_menu(self.library_tab.filter_entry, textbox=False, library=True)
|
self.create_context_menu(self.library_tab.filter_entry, textbox=False, library=True)
|
||||||
# valid event required for filter_items()
|
# valid event required for filter_items()
|
||||||
@ -210,9 +196,10 @@ class T7xWD(ctk.CTk):
|
|||||||
# load ui configs
|
# load ui configs
|
||||||
self.load_configs()
|
self.load_configs()
|
||||||
|
|
||||||
if check_config("checkforupdtes") == "on":
|
if check_config("checkforupdates") == "on":
|
||||||
self.withdraw()
|
self.withdraw()
|
||||||
check_for_updates_func(self, ignore_up_todate=True)
|
try: check_for_updates_func(self, ignore_up_todate=True)
|
||||||
|
except: pass
|
||||||
self.update()
|
self.update()
|
||||||
self.deiconify()
|
self.deiconify()
|
||||||
|
|
||||||
@ -331,12 +318,16 @@ class T7xWD(ctk.CTk):
|
|||||||
print("Invalid geometry format:", geometry)
|
print("Invalid geometry format:", geometry)
|
||||||
|
|
||||||
def on_closing(self):
|
def on_closing(self):
|
||||||
save_config("DestinationFolder" ,self.edit_destination_folder.get())
|
save_config("DestinationFolder",self.settings_tab.edit_destination_folder.get())
|
||||||
save_config("SteamCMDPath" ,self.edit_steamcmd_path.get())
|
save_config("SteamCMDPath",self.settings_tab.edit_steamcmd_path.get())
|
||||||
|
startupexe = str(self.settings_tab.edit_startup_exe.get())
|
||||||
|
launchargs = str(self.settings_tab.edit_launch_args.get())
|
||||||
|
save_config("GameExecutable",startupexe if not isNullOrWhiteSpace(startupexe) else "BlackOps3")
|
||||||
|
save_config("LaunchParameters",launchargs if not isNullOrWhiteSpace(launchargs) else " ")
|
||||||
self.stop_download(on_close=True)
|
self.stop_download(on_close=True)
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
def id_chnaged_handler(self, some=None, other=None ,shit=None):
|
def id_changed_handler(self, some=None, other=None ,shit=None):
|
||||||
self.after(1, self.label_file_size.configure(text=f"File size: 0KB"))
|
self.after(1, self.label_file_size.configure(text=f"File size: 0KB"))
|
||||||
|
|
||||||
def check_for_updates(self):
|
def check_for_updates(self):
|
||||||
@ -349,16 +340,22 @@ class T7xWD(ctk.CTk):
|
|||||||
def change_scaling_event(self, new_scaling: str):
|
def change_scaling_event(self, new_scaling: str):
|
||||||
new_scaling_float = int(new_scaling.replace("%", "")) / 100
|
new_scaling_float = int(new_scaling.replace("%", "")) / 100
|
||||||
ctk.set_widget_scaling(new_scaling_float)
|
ctk.set_widget_scaling(new_scaling_float)
|
||||||
|
ctk.set_window_scaling(new_scaling_float+0.25)
|
||||||
save_config("scaling", str(new_scaling_float))
|
save_config("scaling", str(new_scaling_float))
|
||||||
|
|
||||||
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()
|
||||||
|
self.hide_queue_widgets()
|
||||||
|
|
||||||
|
def use_queue_download(self):
|
||||||
|
return not self.queuetextarea.get("1.0", "end").isspace()
|
||||||
|
|
||||||
def show_main_widgets(self):
|
def show_main_widgets(self):
|
||||||
self.title("T7x Workshop Downloader - Main")
|
self.title("T7x Workshop Downloader - Main")
|
||||||
self.slider_progressbar_frame.grid(row=2, column=1, rowspan=1, padx=(0, 20), pady=(20, 20), sticky="nsew")
|
self.slider_progressbar_frame.grid(row=2, column=1, rowspan=1, padx=(0, 20), pady=(20, 20), sticky="nsew")
|
||||||
self.optionsframe.grid(row=0, column=1, rowspan=2, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
self.optionsframe.grid(row=0, column=1, rowspan=1, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
||||||
|
self.queueframe.grid(row=1, column=1, rowspan=1, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
||||||
|
|
||||||
def hide_settings_widgets(self):
|
def hide_settings_widgets(self):
|
||||||
self.settings_tab.grid_forget()
|
self.settings_tab.grid_forget()
|
||||||
@ -373,26 +370,24 @@ class T7xWD(ctk.CTk):
|
|||||||
|
|
||||||
def show_library_widgets(self):
|
def show_library_widgets(self):
|
||||||
self.title("T7x Workshop Downloader - Library ➜ Loading... ⏳")
|
self.title("T7x Workshop Downloader - Library ➜ Loading... ⏳")
|
||||||
status = self.library_tab.load_items(self.edit_destination_folder.get())
|
status = self.library_tab.load_items(self.settings_tab.edit_destination_folder.get())
|
||||||
self.library_tab.grid(row=0, rowspan=3, column=1, padx=(0, 20), pady=(20, 20), sticky="nsew")
|
self.library_tab.grid(row=0, rowspan=3, column=1, padx=(0, 20), pady=(20, 20), sticky="nsew")
|
||||||
self.title(f"T7x Workshop Downloader - Library ➜ {status}")
|
self.title(f"T7x Workshop Downloader - Library ➜ {status}")
|
||||||
|
|
||||||
def show_queue_widgets(self):
|
def show_queue_widgets(self):
|
||||||
self.title("T7x Workshop Downloader - Queue")
|
self.title("T7x Workshop Downloader - Queue")
|
||||||
self.optionsframe.grid_forget()
|
self.optionsframe.grid_forget()
|
||||||
self.queue_enabled = True
|
|
||||||
self.slider_progressbar_frame.grid(row=2, column=1, rowspan=1, padx=(0, 20), pady=(20, 20), sticky="nsew")
|
self.slider_progressbar_frame.grid(row=2, column=1, rowspan=1, padx=(0, 20), pady=(20, 20), sticky="nsew")
|
||||||
self.qeueuframe.grid(row=0, column=1, rowspan=2, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
self.queueframe.grid(row=0, column=1, rowspan=2, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
||||||
|
|
||||||
def hide_queue_widgets(self):
|
def hide_queue_widgets(self):
|
||||||
self.queue_enabled = False
|
self.queueframe.grid_forget()
|
||||||
self.qeueuframe.grid_forget()
|
|
||||||
|
|
||||||
def main_button_event(self):
|
def main_button_event(self):
|
||||||
self.sidebar_main.configure(state="active", fg_color=(self.active_color))
|
self.sidebar_main.configure(state="active", fg_color=(self.active_color))
|
||||||
self.sidebar_settings.configure(state="normal", fg_color="transparent")
|
self.sidebar_settings.configure(state="normal", fg_color="transparent")
|
||||||
self.sidebar_library.configure(state="normal", fg_color=(self.normal_color))
|
self.sidebar_library.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.sidebar_queue.configure(state="normal", fg_color=(self.normal_color))
|
if self.queue_tab_enabled: self.sidebar_queue.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.hide_settings_widgets()
|
self.hide_settings_widgets()
|
||||||
self.hide_library_widgets()
|
self.hide_library_widgets()
|
||||||
self.hide_queue_widgets()
|
self.hide_queue_widgets()
|
||||||
@ -401,7 +396,7 @@ class T7xWD(ctk.CTk):
|
|||||||
def settings_button_event(self):
|
def settings_button_event(self):
|
||||||
self.sidebar_main.configure(state="normal", fg_color=(self.normal_color))
|
self.sidebar_main.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.sidebar_library.configure(state="normal", fg_color=(self.normal_color))
|
self.sidebar_library.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.sidebar_queue.configure(state="normal", fg_color=(self.normal_color))
|
if self.queue_tab_enabled: self.sidebar_queue.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.sidebar_settings.configure(state="active", fg_color=(self.active_color))
|
self.sidebar_settings.configure(state="active", fg_color=(self.active_color))
|
||||||
self.hide_main_widgets()
|
self.hide_main_widgets()
|
||||||
self.hide_library_widgets()
|
self.hide_library_widgets()
|
||||||
@ -411,7 +406,7 @@ class T7xWD(ctk.CTk):
|
|||||||
def library_button_event(self):
|
def library_button_event(self):
|
||||||
self.sidebar_main.configure(state="normal", fg_color=(self.normal_color))
|
self.sidebar_main.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.sidebar_settings.configure(state="normal", fg_color="transparent")
|
self.sidebar_settings.configure(state="normal", fg_color="transparent")
|
||||||
self.sidebar_queue.configure(state="normal", fg_color=(self.normal_color))
|
if self.queue_tab_enabled: self.sidebar_queue.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.sidebar_library.configure(state="active", fg_color=(self.active_color))
|
self.sidebar_library.configure(state="active", fg_color=(self.active_color))
|
||||||
self.hide_main_widgets()
|
self.hide_main_widgets()
|
||||||
self.hide_settings_widgets()
|
self.hide_settings_widgets()
|
||||||
@ -422,7 +417,7 @@ class T7xWD(ctk.CTk):
|
|||||||
self.sidebar_main.configure(state="normal", fg_color=(self.normal_color))
|
self.sidebar_main.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.sidebar_settings.configure(state="normal", fg_color="transparent")
|
self.sidebar_settings.configure(state="normal", fg_color="transparent")
|
||||||
self.sidebar_library.configure(state="normal", fg_color=(self.normal_color))
|
self.sidebar_library.configure(state="normal", fg_color=(self.normal_color))
|
||||||
self.sidebar_queue.configure(state="active", fg_color=(self.active_color))
|
if self.queue_tab_enabled: self.sidebar_queue.configure(state="active", fg_color=(self.active_color))
|
||||||
self.hide_settings_widgets()
|
self.hide_settings_widgets()
|
||||||
self.hide_library_widgets()
|
self.hide_library_widgets()
|
||||||
self.show_queue_widgets()
|
self.show_queue_widgets()
|
||||||
@ -431,12 +426,19 @@ class T7xWD(ctk.CTk):
|
|||||||
if os.path.exists(CONFIG_FILE_PATH):
|
if os.path.exists(CONFIG_FILE_PATH):
|
||||||
destination_folder = check_config("DestinationFolder", "")
|
destination_folder = check_config("DestinationFolder", "")
|
||||||
steamcmd_path = check_config("SteamCMDPath", APPLICATION_PATH)
|
steamcmd_path = check_config("SteamCMDPath", APPLICATION_PATH)
|
||||||
|
startup_exe = check_config("GameExecutable", "BlackOps3")
|
||||||
|
launch_params = check_config("LaunchParameters", None)
|
||||||
new_appearance_mode = check_config("appearance", "Dark")
|
new_appearance_mode = check_config("appearance", "Dark")
|
||||||
new_scaling = check_config("scaling", 1.0)
|
new_scaling = check_config("scaling", 1.0)
|
||||||
self.edit_destination_folder.delete(0, "end")
|
self.settings_tab.edit_destination_folder.delete(0, "end")
|
||||||
self.edit_destination_folder.insert(0, destination_folder)
|
self.settings_tab.edit_destination_folder.insert(0, destination_folder)
|
||||||
self.edit_steamcmd_path.delete(0, "end")
|
self.settings_tab.edit_steamcmd_path.delete(0, "end")
|
||||||
self.edit_steamcmd_path.insert(0, steamcmd_path)
|
self.settings_tab.edit_steamcmd_path.insert(0, steamcmd_path)
|
||||||
|
self.settings_tab.edit_startup_exe.delete(0, "end")
|
||||||
|
self.settings_tab.edit_startup_exe.insert(0, startup_exe)
|
||||||
|
if not isNullOrWhiteSpace(launch_params):
|
||||||
|
self.settings_tab.edit_launch_args.delete(0, "end")
|
||||||
|
self.settings_tab.edit_launch_args.insert(0, launch_params)
|
||||||
ctk.set_appearance_mode(new_appearance_mode)
|
ctk.set_appearance_mode(new_appearance_mode)
|
||||||
ctk.set_widget_scaling(float(new_scaling))
|
ctk.set_widget_scaling(float(new_scaling))
|
||||||
self.settings_tab.appearance_mode_optionemenu.set(new_appearance_mode)
|
self.settings_tab.appearance_mode_optionemenu.set(new_appearance_mode)
|
||||||
@ -452,18 +454,20 @@ class T7xWD(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.settings_tab.scaling_optionemenu.set(f"{scaling_int}%")
|
self.settings_tab.scaling_optionemenu.set(f"{scaling_int}%")
|
||||||
self.edit_steamcmd_path.delete(0, "end")
|
self.settings_tab.edit_steamcmd_path.delete(0, "end")
|
||||||
self.edit_steamcmd_path.insert(0, APPLICATION_PATH)
|
self.settings_tab.edit_steamcmd_path.insert(0, APPLICATION_PATH)
|
||||||
|
self.settings_tab.edit_startup_exe.delete(0, "end")
|
||||||
|
self.settings_tab.edit_startup_exe.insert(0, "BlackOps3")
|
||||||
create_default_config()
|
create_default_config()
|
||||||
|
|
||||||
def help_queue_text_func(self, event=None):
|
def help_queue_text_func(self, event=None):
|
||||||
textarea_content = self.queuetextarea.get("1.0", "end").strip()
|
textarea_content = self.queuetextarea.get("1.0", "end").strip()
|
||||||
help_text = "3010399939,2976006537,2118338989,...\nor:\n3010399939\n2976006537\n2113146805\n..."
|
help_text = "3010399939,2976006537,2118338989 \n\nor:\n\n3010399939\n2976006537\n2113146805"
|
||||||
if any(char.strip() for char in textarea_content):
|
if any(char.strip() for char in textarea_content):
|
||||||
if help_text in textarea_content:
|
if help_text in textarea_content:
|
||||||
self.workshop_queue_label.configure(text="Workshop IDs/Links => press help to see examples:")
|
self.workshop_queue_label.configure(text="Batch Downloader:")
|
||||||
self.help_button.configure(text="Help")
|
self.help_button.configure(text="Help")
|
||||||
self.queuetextarea.configure(state="normal")
|
self.queuetextarea.configure(state="normal",text_color="#fcfcfc")
|
||||||
self.queuetextarea.delete(1.0, "end")
|
self.queuetextarea.delete(1.0, "end")
|
||||||
self.queuetextarea.insert(1.0, "")
|
self.queuetextarea.insert(1.0, "")
|
||||||
if self.help_restore_content:
|
if self.help_restore_content:
|
||||||
@ -473,36 +477,36 @@ class T7xWD(ctk.CTk):
|
|||||||
else:
|
else:
|
||||||
if not help_text in textarea_content:
|
if not help_text in textarea_content:
|
||||||
self.help_restore_content = textarea_content
|
self.help_restore_content = textarea_content
|
||||||
self.workshop_queue_label.configure(text="Workshop IDs/Links => press help to see examples:")
|
self.workshop_queue_label.configure(text="Batch Downloader:")
|
||||||
self.help_button.configure(text="Restore")
|
self.help_button.configure(text="Restore")
|
||||||
self.queuetextarea.configure(state="normal")
|
self.queuetextarea.configure(state="normal",text_color="#fcfcfc")
|
||||||
self.queuetextarea.delete(1.0, "end")
|
self.queuetextarea.delete(1.0, "end")
|
||||||
self.queuetextarea.insert(1.0, "")
|
self.queuetextarea.insert(1.0, "")
|
||||||
self.workshop_queue_label.configure(text="Workshop IDs/Links => press restore to remove examples:")
|
self.workshop_queue_label.configure(text="Batch Downloader Example:")
|
||||||
self.queuetextarea.insert(1.0, help_text)
|
self.queuetextarea.insert(1.0, help_text)
|
||||||
self.queuetextarea.configure(state="disabled")
|
self.queuetextarea.configure(state="disabled", text_color="gray74")
|
||||||
else:
|
else:
|
||||||
self.help_restore_content = textarea_content
|
self.help_restore_content = textarea_content
|
||||||
self.workshop_queue_label.configure(text="Workshop IDs/Links => press restore to remove examples:")
|
self.workshop_queue_label.configure(text="Batch Downloader Example:")
|
||||||
self.help_button.configure(text="Restore")
|
self.help_button.configure(text="Restore")
|
||||||
self.queuetextarea.insert(1.0, help_text)
|
self.queuetextarea.insert(1.0, help_text)
|
||||||
self.queuetextarea.configure(state="disabled")
|
self.queuetextarea.configure(state="disabled", text_color="gray74")
|
||||||
|
|
||||||
def open_T7x_browser(self):
|
def open_T7x_browser(self):
|
||||||
selected_folder = ctk.filedialog.askdirectory(title="Select T7x Folder")
|
selected_folder = ctk.filedialog.askdirectory(title="Select Game Folder")
|
||||||
if selected_folder:
|
if selected_folder:
|
||||||
self.edit_destination_folder.delete(0, "end")
|
self.settings_tab.edit_destination_folder.delete(0, "end")
|
||||||
self.edit_destination_folder.insert(0, selected_folder)
|
self.settings_tab.edit_destination_folder.insert(0, selected_folder)
|
||||||
save_config("DestinationFolder" ,self.edit_destination_folder.get())
|
save_config("DestinationFolder" ,self.settings_tab.edit_destination_folder.get())
|
||||||
save_config("SteamCMDPath" ,self.edit_steamcmd_path.get())
|
save_config("SteamCMDPath" ,self.settings_tab.edit_steamcmd_path.get())
|
||||||
|
|
||||||
def open_steamcmd_path_browser(self):
|
def open_steamcmd_path_browser(self):
|
||||||
selected_folder = ctk.filedialog.askdirectory(title="Select SteamCMD Folder")
|
selected_folder = ctk.filedialog.askdirectory(title="Select SteamCMD Folder")
|
||||||
if selected_folder:
|
if selected_folder:
|
||||||
self.edit_steamcmd_path.delete(0, "end")
|
self.settings_tab.edit_steamcmd_path.delete(0, "end")
|
||||||
self.edit_steamcmd_path.insert(0, selected_folder)
|
self.settings_tab.edit_steamcmd_path.insert(0, selected_folder)
|
||||||
save_config("DestinationFolder" ,self.edit_destination_folder.get())
|
save_config("DestinationFolder" ,self.settings_tab.edit_destination_folder.get())
|
||||||
save_config("SteamCMDPath" ,self.edit_steamcmd_path.get())
|
save_config("SteamCMDPath" ,self.settings_tab.edit_steamcmd_path.get())
|
||||||
|
|
||||||
def show_steam_warning_message(self):
|
def show_steam_warning_message(self):
|
||||||
def callback():
|
def callback():
|
||||||
@ -519,12 +523,15 @@ class T7xWD(ctk.CTk):
|
|||||||
link = "https://steamcommunity.com/app/311210/workshop/"
|
link = "https://steamcommunity.com/app/311210/workshop/"
|
||||||
webbrowser.open(link)
|
webbrowser.open(link)
|
||||||
|
|
||||||
|
def settings_launch_game(self):
|
||||||
|
launch_game_func(check_config("destinationfolder"), self.settings_tab.edit_startup_exe.get(), self.settings_tab.edit_launch_args.get())
|
||||||
|
|
||||||
@if_internet_available
|
@if_internet_available
|
||||||
def download_steamcmd(self):
|
def download_steamcmd(self):
|
||||||
self.edit_steamcmd_path.delete(0, "end")
|
self.settings_tab.edit_steamcmd_path.delete(0, "end")
|
||||||
self.edit_steamcmd_path.insert(0, APPLICATION_PATH)
|
self.settings_tab.edit_steamcmd_path.insert(0, APPLICATION_PATH)
|
||||||
save_config("DestinationFolder" ,self.edit_destination_folder.get())
|
save_config("DestinationFolder" ,self.settings_tab.edit_destination_folder.get())
|
||||||
save_config("SteamCMDPath" ,self.edit_steamcmd_path.get())
|
save_config("SteamCMDPath" ,self.settings_tab.edit_steamcmd_path.get())
|
||||||
steamcmd_url = "https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"
|
steamcmd_url = "https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"
|
||||||
steamcmd_zip_path = os.path.join(APPLICATION_PATH, "steamcmd.zip")
|
steamcmd_zip_path = os.path.join(APPLICATION_PATH, "steamcmd.zip")
|
||||||
|
|
||||||
@ -795,6 +802,61 @@ class T7xWD(ctk.CTk):
|
|||||||
|
|
||||||
self.after(0, main_thread)
|
self.after(0, main_thread)
|
||||||
|
|
||||||
|
def check_if_steamcmd_updating(self, log_file_path):
|
||||||
|
temp_file_path = log_file_path + '.temp'
|
||||||
|
if not os.path.exists(log_file_path):
|
||||||
|
if os.path.isdir(log_file_path):
|
||||||
|
try: os.makedirs(log_file_path)
|
||||||
|
except: return False
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
with open(log_file_path, 'w') as file:
|
||||||
|
file.write('')
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
try: shutil.copy2(log_file_path, temp_file_path)
|
||||||
|
except: return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(temp_file_path, 'r') as log_file:
|
||||||
|
log_file.seek(0, os.SEEK_END)
|
||||||
|
file_size = log_file.tell()
|
||||||
|
|
||||||
|
position = file_size
|
||||||
|
lines_found = 0
|
||||||
|
|
||||||
|
while lines_found < 7 and position > 0:
|
||||||
|
position -= 1
|
||||||
|
log_file.seek(position, os.SEEK_SET)
|
||||||
|
|
||||||
|
char = log_file.read(1)
|
||||||
|
|
||||||
|
if char == '\n':
|
||||||
|
lines_found += 1
|
||||||
|
|
||||||
|
lines = log_file.readlines()[-7:]
|
||||||
|
|
||||||
|
for _line in reversed(lines):
|
||||||
|
line = _line.lower().strip()
|
||||||
|
if "downloading update" in line:
|
||||||
|
print(line)
|
||||||
|
match = re.search(r'(\d{1,3}(?:,\d{3})* of \d{1,3}(?:,\d{3})* [kKMGTP]{0,1}B)', _line)
|
||||||
|
if match:
|
||||||
|
update_size_str = match.group(1)
|
||||||
|
self.steam_updater_size = update_size_str
|
||||||
|
return True
|
||||||
|
elif self.is_steamcmd_updating and "downloading update" not in line:
|
||||||
|
self.steam_updater_size = "Installing"
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
os.remove(temp_file_path)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
try: os.remove(temp_file_path)
|
||||||
|
except: pass
|
||||||
|
|
||||||
def check_steamcmd_stdout(self, log_file_path, target_item_id):
|
def check_steamcmd_stdout(self, log_file_path, target_item_id):
|
||||||
temp_file_path = log_file_path + '.temp'
|
temp_file_path = log_file_path + '.temp'
|
||||||
if not os.path.exists(log_file_path):
|
if not os.path.exists(log_file_path):
|
||||||
@ -846,7 +908,7 @@ class T7xWD(ctk.CTk):
|
|||||||
|
|
||||||
def skip_current_queue_item(self):
|
def skip_current_queue_item(self):
|
||||||
if self.button_download._state == "normal":
|
if self.button_download._state == "normal":
|
||||||
self.skip_boutton.grid_remove()
|
self.skip_button.grid_remove()
|
||||||
self.after(1, self.status_text.configure(text=f"Status: Standby!"))
|
self.after(1, self.status_text.configure(text=f"Status: Standby!"))
|
||||||
return
|
return
|
||||||
self.settings_tab.stopped = True
|
self.settings_tab.stopped = True
|
||||||
@ -858,7 +920,7 @@ class T7xWD(ctk.CTk):
|
|||||||
|
|
||||||
subprocess.run(['taskkill', '/F', '/IM', 'steamcmd.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
subprocess.run(['taskkill', '/F', '/IM', 'steamcmd.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
creationflags=subprocess.CREATE_NO_WINDOW)
|
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||||
self.skip_boutton.grid_remove()
|
self.skip_button.grid_remove()
|
||||||
self.after(2, self.status_text.configure(text=f"Status: Skipping..."))
|
self.after(2, self.status_text.configure(text=f"Status: Skipping..."))
|
||||||
self.label_speed.configure(text="Network Speed: 0 KB/s")
|
self.label_speed.configure(text="Network Speed: 0 KB/s")
|
||||||
self.progress_text.configure(text="0%")
|
self.progress_text.configure(text="0%")
|
||||||
@ -867,6 +929,7 @@ class T7xWD(ctk.CTk):
|
|||||||
# the real deal
|
# the real deal
|
||||||
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()
|
||||||
|
steamcmd_bootstrap_logs = os.path.join(steamcmd_path, "logs", "bootstrap_log.txt")
|
||||||
stdout_path = os.path.join(steamcmd_path, "logs", "workshop_log.txt")
|
stdout_path = os.path.join(steamcmd_path, "logs", "workshop_log.txt")
|
||||||
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
|
||||||
@ -874,9 +937,13 @@ class T7xWD(ctk.CTk):
|
|||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
with open(steamcmd_bootstrap_logs, 'w') as file:
|
||||||
|
file.write('')
|
||||||
with open(stdout_path, 'w') as file:
|
with open(stdout_path, 'w') as file:
|
||||||
file.write('')
|
file.write('')
|
||||||
except:
|
except:
|
||||||
|
try: os.rename(stdout_path, os.path.join(map_folder, os.path.join(steamcmd_bootstrap_logs, f"bootstrap_log_couldntremove_{timestamp}.txt")))
|
||||||
|
except: pass
|
||||||
try: os.rename(stdout_path, os.path.join(map_folder, os.path.join(stdout_path, f"workshop_log_couldntremove_{timestamp}.txt")))
|
try: os.rename(stdout_path, os.path.join(map_folder, os.path.join(stdout_path, f"workshop_log_couldntremove_{timestamp}.txt")))
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
@ -918,14 +985,18 @@ class T7xWD(ctk.CTk):
|
|||||||
if process.poll() is not None:
|
if process.poll() is not None:
|
||||||
break
|
break
|
||||||
if not self.is_downloading:
|
if not self.is_downloading:
|
||||||
|
if self.check_if_steamcmd_updating(steamcmd_bootstrap_logs):
|
||||||
|
self.is_steamcmd_updating = True
|
||||||
if self.check_steamcmd_stdout(stdout_path, wsid):
|
if self.check_steamcmd_stdout(stdout_path, wsid):
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
self.is_downloading = True
|
self.is_downloading = True
|
||||||
|
self.is_steamcmd_updating = False
|
||||||
elapsed_time = time.time() - start_time
|
elapsed_time = time.time() - start_time
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
# print("Broken freeeee!")
|
# print("Broken freeeee!")
|
||||||
self.is_downloading = False
|
self.is_downloading = False
|
||||||
|
self.is_steamcmd_updating = False
|
||||||
try:
|
try:
|
||||||
with open(stdout_path, 'w') as file:
|
with open(stdout_path, 'w') as file:
|
||||||
file.write('')
|
file.write('')
|
||||||
@ -968,6 +1039,8 @@ class T7xWD(ctk.CTk):
|
|||||||
if process.poll() is not None:
|
if process.poll() is not None:
|
||||||
break
|
break
|
||||||
if not self.is_downloading:
|
if not self.is_downloading:
|
||||||
|
if self.check_if_steamcmd_updating(steamcmd_bootstrap_logs):
|
||||||
|
self.is_steamcmd_updating = True
|
||||||
if self.check_steamcmd_stdout(stdout_path, wsid):
|
if self.check_steamcmd_stdout(stdout_path, wsid):
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
self.is_downloading = True
|
self.is_downloading = True
|
||||||
@ -976,6 +1049,7 @@ class T7xWD(ctk.CTk):
|
|||||||
|
|
||||||
# print("Broken freeeee!")
|
# print("Broken freeeee!")
|
||||||
self.is_downloading = False
|
self.is_downloading = False
|
||||||
|
self.is_steamcmd_updating = False
|
||||||
try:
|
try:
|
||||||
with open(stdout_path, 'w') as file:
|
with open(stdout_path, 'w') as file:
|
||||||
file.write('')
|
file.write('')
|
||||||
@ -1011,7 +1085,7 @@ class T7xWD(ctk.CTk):
|
|||||||
msg = CTkMessagebox(title="Downloads Complete", message=message, icon="info", option_1="Launch", option_2="Ok", sound=True)
|
msg = CTkMessagebox(title="Downloads Complete", message=message, icon="info", option_1="Launch", option_2="Ok", sound=True)
|
||||||
response = msg.get()
|
response = msg.get()
|
||||||
if response=="Launch":
|
if response=="Launch":
|
||||||
launch_T7x_func(self.edit_destination_folder.get().strip())
|
launch_game_func(self.settings_tab.edit_destination_folder.get().strip(), self.settings_tab.edit_startup_exe.get(), self.settings_tab.edit_launch_args.get())
|
||||||
if response=="Ok":
|
if response=="Ok":
|
||||||
return
|
return
|
||||||
self.after(0, callback)
|
self.after(0, callback)
|
||||||
@ -1023,8 +1097,8 @@ class T7xWD(ctk.CTk):
|
|||||||
if not self.is_pressed:
|
if not self.is_pressed:
|
||||||
self.after(1, self.label_speed.configure(text=f"Loading..."))
|
self.after(1, self.label_speed.configure(text=f"Loading..."))
|
||||||
self.is_pressed = True
|
self.is_pressed = True
|
||||||
self.library_tab.load_items(self.edit_destination_folder.get(), dont_add=True)
|
self.library_tab.load_items(self.settings_tab.edit_destination_folder.get(), dont_add=True)
|
||||||
if self.queue_enabled:
|
if self.use_queue_download():
|
||||||
self.item_skipped = False
|
self.item_skipped = False
|
||||||
start_down_thread = threading.Thread(target=self.queue_download_thread, args=(update,))
|
start_down_thread = threading.Thread(target=self.queue_download_thread, args=(update,))
|
||||||
start_down_thread.start()
|
start_down_thread.start()
|
||||||
@ -1038,8 +1112,8 @@ class T7xWD(ctk.CTk):
|
|||||||
self.stopped = False
|
self.stopped = False
|
||||||
self.queue_stop_button = False
|
self.queue_stop_button = False
|
||||||
try:
|
try:
|
||||||
save_config("DestinationFolder" ,self.edit_destination_folder.get())
|
save_config("DestinationFolder" ,self.settings_tab.edit_destination_folder.get())
|
||||||
save_config("SteamCMDPath" ,self.edit_steamcmd_path.get())
|
save_config("SteamCMDPath" ,self.settings_tab.edit_steamcmd_path.get())
|
||||||
|
|
||||||
if not check_steamcmd():
|
if not check_steamcmd():
|
||||||
self.show_steam_warning_message()
|
self.show_steam_warning_message()
|
||||||
@ -1065,7 +1139,7 @@ class T7xWD(ctk.CTk):
|
|||||||
self.stop_download()
|
self.stop_download()
|
||||||
return
|
return
|
||||||
|
|
||||||
destination_folder = self.edit_destination_folder.get().strip()
|
destination_folder = self.settings_tab.edit_destination_folder.get().strip()
|
||||||
|
|
||||||
if not destination_folder or not os.path.exists(destination_folder):
|
if not destination_folder or not os.path.exists(destination_folder):
|
||||||
show_message("Error", "Please select a valid destination folder => in the main tab!.")
|
show_message("Error", "Please select a valid destination folder => in the main tab!.")
|
||||||
@ -1102,13 +1176,16 @@ class T7xWD(ctk.CTk):
|
|||||||
|
|
||||||
ws_file_size = get_workshop_file_size(workshop_id)
|
ws_file_size = get_workshop_file_size(workshop_id)
|
||||||
file_size = ws_file_size
|
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:
|
if file_size is None:
|
||||||
show_message("Error", "Failed to retrieve file size.", icon="cancel")
|
ws_file_size = 1
|
||||||
self.stop_download()
|
file_size = 1
|
||||||
return
|
show_message("Error", "Failed to retrieve file size, Continuing anyway", icon="cancel")
|
||||||
|
# self.stop_download()
|
||||||
|
# return
|
||||||
|
|
||||||
|
items_ws_sizes[workshop_id] = ws_file_size
|
||||||
|
self.total_queue_size += ws_file_size
|
||||||
|
|
||||||
if any(workshop_id in item for item in self.library_tab.added_items):
|
if any(workshop_id in item for item in self.library_tab.added_items):
|
||||||
self.already_installed.append(workshop_id)
|
self.already_installed.append(workshop_id)
|
||||||
@ -1160,7 +1237,7 @@ class T7xWD(ctk.CTk):
|
|||||||
self.stop_download()
|
self.stop_download()
|
||||||
return
|
return
|
||||||
ws_file_size = get_workshop_file_size(workshop_id)
|
ws_file_size = get_workshop_file_size(workshop_id)
|
||||||
file_size = ws_file_size
|
file_size = ws_file_size if ws_file_size is not None else 1
|
||||||
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)
|
||||||
@ -1170,7 +1247,7 @@ class T7xWD(ctk.CTk):
|
|||||||
def check_and_update_progress():
|
def check_and_update_progress():
|
||||||
previous_net_speed = 0
|
previous_net_speed = 0
|
||||||
est_downloaded_bytes = 0
|
est_downloaded_bytes = 0
|
||||||
file_size = ws_file_size
|
file_size = ws_file_size if ws_file_size is not None else 1
|
||||||
item_name = get_item_name(workshop_id) if get_item_name(workshop_id) else "Error getting name"
|
item_name = get_item_name(workshop_id) if get_item_name(workshop_id) else "Error getting name"
|
||||||
|
|
||||||
while not self.settings_tab.stopped:
|
while not self.settings_tab.stopped:
|
||||||
@ -1196,6 +1273,9 @@ class T7xWD(ctk.CTk):
|
|||||||
self.item_skipped = False
|
self.item_skipped = False
|
||||||
|
|
||||||
while not self.is_downloading and not self.settings_tab.stopped:
|
while not self.is_downloading and not self.settings_tab.stopped:
|
||||||
|
if self.is_steamcmd_updating:
|
||||||
|
self.after(1, self.label_speed.configure(text=f"Updating steamcmd ({self.steam_updater_size})..."))
|
||||||
|
else:
|
||||||
self.after(1, self.label_speed.configure(text=f"Waiting for steamcmd..."))
|
self.after(1, self.label_speed.configure(text=f"Waiting for steamcmd..."))
|
||||||
time_elapsed = time.time() - start_time
|
time_elapsed = time.time() - start_time
|
||||||
elapsed_hours, elapsed_minutes, elapsed_seconds = convert_seconds(time_elapsed)
|
elapsed_hours, elapsed_minutes, elapsed_seconds = convert_seconds(time_elapsed)
|
||||||
@ -1206,11 +1286,12 @@ class T7xWD(ctk.CTk):
|
|||||||
self.after(1, self.status_text.configure(
|
self.after(1, self.status_text.configure(
|
||||||
text=f"Status: Total size: ~{convert_bytes_to_readable(self.total_queue_size)} | ID: {workshop_id} | {item_name} | Waiting {current_number}/{total_items}"))
|
text=f"Status: Total size: ~{convert_bytes_to_readable(self.total_queue_size)} | ID: {workshop_id} | {item_name} | Waiting {current_number}/{total_items}"))
|
||||||
if len(items) > 1:
|
if len(items) > 1:
|
||||||
self.skip_boutton.grid(row=3, column=1, padx=(10, 20), pady=(0, 25), sticky="ws")
|
self.skip_button.grid(row=1, column=3, padx=(0, 20), pady=(0, 8), sticky="es")
|
||||||
if index == len(items) - 1:
|
if index == len(items) - 1:
|
||||||
self.skip_boutton.grid_remove()
|
self.skip_button.grid_remove()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
if self.is_downloading:
|
if self.is_downloading:
|
||||||
|
self.is_steamcmd_updating = False
|
||||||
break
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1355,7 +1436,7 @@ class T7xWD(ctk.CTk):
|
|||||||
remove_tree(map_folder)
|
remove_tree(map_folder)
|
||||||
remove_tree(download_folder)
|
remove_tree(download_folder)
|
||||||
|
|
||||||
self.library_tab.update_item(self.edit_destination_folder.get(), workshop_id, mod_type, folder_name)
|
self.library_tab.update_item(self.settings_tab.edit_destination_folder.get(), workshop_id, mod_type, folder_name)
|
||||||
|
|
||||||
if index == len(items) - 1:
|
if index == len(items) - 1:
|
||||||
self.after(1, self.status_text.configure(text=f"Status: Done! => Please press stop only if you see no popup window (rare bug)"))
|
self.after(1, self.status_text.configure(text=f"Status: Done! => Please press stop only if you see no popup window (rare bug)"))
|
||||||
@ -1378,7 +1459,7 @@ class T7xWD(ctk.CTk):
|
|||||||
self.button_download.configure(state="normal")
|
self.button_download.configure(state="normal")
|
||||||
self.button_stop.configure(state="disabled")
|
self.button_stop.configure(state="disabled")
|
||||||
self.after(1, self.status_text.configure(text=f"Status: Done!"))
|
self.after(1, self.status_text.configure(text=f"Status: Done!"))
|
||||||
self.skip_boutton.grid_remove()
|
self.skip_button.grid_remove()
|
||||||
self.after(1, self.label_file_size.configure(text=f"File size: 0KB"))
|
self.after(1, self.label_file_size.configure(text=f"File size: 0KB"))
|
||||||
self.settings_tab.stopped = True
|
self.settings_tab.stopped = True
|
||||||
self.stop_download()
|
self.stop_download()
|
||||||
@ -1393,8 +1474,8 @@ class T7xWD(ctk.CTk):
|
|||||||
try:
|
try:
|
||||||
self.settings_tab.stopped = False
|
self.settings_tab.stopped = False
|
||||||
|
|
||||||
save_config("DestinationFolder" ,self.edit_destination_folder.get())
|
save_config("DestinationFolder" ,self.settings_tab.edit_destination_folder.get())
|
||||||
save_config("SteamCMDPath" ,self.edit_steamcmd_path.get())
|
save_config("SteamCMDPath" ,self.settings_tab.edit_steamcmd_path.get())
|
||||||
|
|
||||||
if not check_steamcmd():
|
if not check_steamcmd():
|
||||||
self.show_steam_warning_message()
|
self.show_steam_warning_message()
|
||||||
@ -1408,7 +1489,7 @@ class T7xWD(ctk.CTk):
|
|||||||
|
|
||||||
workshop_id = self.edit_workshop_id.get().strip()
|
workshop_id = self.edit_workshop_id.get().strip()
|
||||||
|
|
||||||
destination_folder = self.edit_destination_folder.get().strip()
|
destination_folder = self.settings_tab.edit_destination_folder.get().strip()
|
||||||
|
|
||||||
if not destination_folder or not os.path.exists(destination_folder):
|
if not destination_folder or not os.path.exists(destination_folder):
|
||||||
show_message("Error", "Please select a valid destination folder.")
|
show_message("Error", "Please select a valid destination folder.")
|
||||||
@ -1437,14 +1518,16 @@ class T7xWD(ctk.CTk):
|
|||||||
file_size = ws_file_size
|
file_size = ws_file_size
|
||||||
|
|
||||||
if not valid_id(workshop_id):
|
if not valid_id(workshop_id):
|
||||||
show_message("Warning", "Please enter a valid Workshop ID/Link.", icon="warning")
|
show_message("Warning", "Invalid Workshop ID/Link.\nYou can attempt to update with 'Skip Invalid Items' disabled.", icon="warning")
|
||||||
self.stop_download()
|
self.stop_download()
|
||||||
return
|
return
|
||||||
|
|
||||||
if file_size is None:
|
if file_size is None:
|
||||||
show_message("Error", "Failed to retrieve file size.", icon="cancel")
|
ws_file_size = 1
|
||||||
self.stop_download()
|
file_size = 1
|
||||||
return
|
show_message("Error", "Failed to retrieve file size, Continuing anyway", icon="cancel")
|
||||||
|
# self.stop_download()
|
||||||
|
# return
|
||||||
|
|
||||||
if not update:
|
if not update:
|
||||||
if any(workshop_id in item for item in self.library_tab.added_items):
|
if any(workshop_id in item for item in self.library_tab.added_items):
|
||||||
@ -1464,7 +1547,7 @@ class T7xWD(ctk.CTk):
|
|||||||
previous_net_speed = 0
|
previous_net_speed = 0
|
||||||
est_downloaded_bytes = 0
|
est_downloaded_bytes = 0
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
file_size = ws_file_size
|
file_size = ws_file_size if ws_file_size is not None else 1
|
||||||
|
|
||||||
while not self.settings_tab.stopped:
|
while not self.settings_tab.stopped:
|
||||||
if self.settings_tab.steamcmd_reset:
|
if self.settings_tab.steamcmd_reset:
|
||||||
@ -1473,6 +1556,9 @@ class T7xWD(ctk.CTk):
|
|||||||
est_downloaded_bytes = 0
|
est_downloaded_bytes = 0
|
||||||
|
|
||||||
while not self.is_downloading and not self.settings_tab.stopped:
|
while not self.is_downloading and not self.settings_tab.stopped:
|
||||||
|
if self.is_steamcmd_updating:
|
||||||
|
self.after(1, self.label_speed.configure(text=f"Updating steamcmd ({self.steam_updater_size})..."))
|
||||||
|
else:
|
||||||
self.after(1, self.label_speed.configure(text=f"Waiting for steamcmd..."))
|
self.after(1, self.label_speed.configure(text=f"Waiting for steamcmd..."))
|
||||||
time_elapsed = time.time() - start_time
|
time_elapsed = time.time() - start_time
|
||||||
elapsed_hours, elapsed_minutes, elapsed_seconds = convert_seconds(time_elapsed)
|
elapsed_hours, elapsed_minutes, elapsed_seconds = convert_seconds(time_elapsed)
|
||||||
@ -1482,6 +1568,7 @@ class T7xWD(ctk.CTk):
|
|||||||
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)
|
||||||
if self.is_downloading:
|
if self.is_downloading:
|
||||||
|
self.is_steamcmd_updating = False
|
||||||
break
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -1626,7 +1713,7 @@ class T7xWD(ctk.CTk):
|
|||||||
remove_tree(download_folder)
|
remove_tree(download_folder)
|
||||||
|
|
||||||
if not invalid_item_folder:
|
if not invalid_item_folder:
|
||||||
self.library_tab.update_item(self.edit_destination_folder.get(), workshop_id, mod_type, folder_name)
|
self.library_tab.update_item(self.settings_tab.edit_destination_folder.get(), workshop_id, mod_type, folder_name)
|
||||||
self.show_complete_message(message=f"{mod_type.capitalize()} files were downloaded\nYou can run the game now!\nPS: You have to restart the game \n(pressing launch will launch/restarts)")
|
self.show_complete_message(message=f"{mod_type.capitalize()} files were downloaded\nYou can run the game now!\nPS: You have to restart the game \n(pressing launch will launch/restarts)")
|
||||||
self.button_download.configure(state="normal")
|
self.button_download.configure(state="normal")
|
||||||
self.button_stop.configure(state="disabled")
|
self.button_stop.configure(state="disabled")
|
||||||
@ -1692,4 +1779,4 @@ class T7xWD(ctk.CTk):
|
|||||||
self.progress_bar.set(0.0)
|
self.progress_bar.set(0.0)
|
||||||
self.after(50, self.status_text.configure(text=f"Status: Standby!"))
|
self.after(50, self.status_text.configure(text=f"Status: Standby!"))
|
||||||
self.after(1, self.label_speed.configure(text=f"Awaiting Download!"))
|
self.after(1, self.label_speed.configure(text=f"Awaiting Download!"))
|
||||||
self.skip_boutton.grid_remove()
|
self.skip_button.grid_remove()
|
||||||
|
@ -28,13 +28,17 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
self.grid_columnconfigure(1, weight=1)
|
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 = ctk.CTkFrame(self)
|
||||||
left_frame.grid(row=0, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew")
|
left_frame.grid(row=0, column=0, columnspan=2, padx=(20, 20), pady=(20, 0), sticky="nsew")
|
||||||
left_frame.grid_columnconfigure(1, weight=1)
|
left_frame.grid_columnconfigure(1, weight=1)
|
||||||
right_frame = ctk.CTkFrame(self)
|
right_frame = ctk.CTkFrame(self)
|
||||||
right_frame.grid(row=0, column=1, padx=(20, 20), pady=(20, 0), sticky="nsew")
|
right_frame.grid(row=0, column=2, padx=(0, 20), pady=(20, 0), sticky="nsew")
|
||||||
right_frame.grid_columnconfigure(1, weight=1)
|
right_frame.grid_columnconfigure(1, weight=1)
|
||||||
self.update_idletasks()
|
self.update_idletasks()
|
||||||
|
|
||||||
|
# Save button
|
||||||
|
self.save_button = ctk.CTkButton(self, text="Save", command=self.save_settings, state='disabled')
|
||||||
|
self.save_button.grid(row=3, column=1, padx=40, pady=(20, 20), sticky="ne")
|
||||||
|
|
||||||
# Check for updates checkbox
|
# Check for updates checkbox
|
||||||
self.check_updates_var = ctk.BooleanVar()
|
self.check_updates_var = ctk.BooleanVar()
|
||||||
self.check_updates_var.trace_add("write", self.enable_save_button)
|
self.check_updates_var.trace_add("write", self.enable_save_button)
|
||||||
@ -45,7 +49,7 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
# Show console checkbox
|
# Show console checkbox
|
||||||
self.console_var = ctk.BooleanVar()
|
self.console_var = ctk.BooleanVar()
|
||||||
self.console_var.trace_add("write", self.enable_save_button)
|
self.console_var.trace_add("write", self.enable_save_button)
|
||||||
self.checkbox_show_console = ctk.CTkSwitch(left_frame, text="Console (On Download)", variable=self.console_var)
|
self.checkbox_show_console = ctk.CTkSwitch(left_frame, text="Display SteamCMD console", variable=self.console_var)
|
||||||
self.checkbox_show_console.grid(row=1, column=1, padx=20, pady=(20, 0), sticky="nw")
|
self.checkbox_show_console.grid(row=1, column=1, padx=20, pady=(20, 0), sticky="nw")
|
||||||
self.checkbox_show_console_tooltip = CTkToolTip(self.checkbox_show_console, message="Toggle SteamCMD console\nPlease don't close the Console If you want to stop press the Stop button")
|
self.checkbox_show_console_tooltip = CTkToolTip(self.checkbox_show_console, message="Toggle SteamCMD console\nPlease don't close the Console If you want to stop press the Stop button")
|
||||||
self.console_var.set(self.load_settings("console"))
|
self.console_var.set(self.load_settings("console"))
|
||||||
@ -53,7 +57,7 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
# Show continuous checkbox
|
# Show continuous checkbox
|
||||||
self.continuous_var = ctk.BooleanVar()
|
self.continuous_var = ctk.BooleanVar()
|
||||||
self.continuous_var.trace_add("write", self.enable_save_button)
|
self.continuous_var.trace_add("write", self.enable_save_button)
|
||||||
self.checkbox_continuous = ctk.CTkSwitch(left_frame, text="Continuous Download", variable=self.continuous_var)
|
self.checkbox_continuous = ctk.CTkSwitch(left_frame, text="Continuous download", variable=self.continuous_var)
|
||||||
self.checkbox_continuous.grid(row=2, column=1, padx=20, pady=(20, 0), sticky="nw")
|
self.checkbox_continuous.grid(row=2, column=1, padx=20, pady=(20, 0), sticky="nw")
|
||||||
self.checkbox_continuous_tooltip = CTkToolTip(self.checkbox_continuous, message="This will make sure that the download restarts and resumes! until it finishes if steamcmd crashes randomly (it will not redownload from the start)")
|
self.checkbox_continuous_tooltip = CTkToolTip(self.checkbox_continuous, message="This will make sure that the download restarts and resumes! until it finishes if steamcmd crashes randomly (it will not redownload from the start)")
|
||||||
self.continuous_var.set(self.load_settings("continuous_download"))
|
self.continuous_var.set(self.load_settings("continuous_download"))
|
||||||
@ -69,16 +73,16 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
# Show estimated_progress checkbox
|
# Show estimated_progress checkbox
|
||||||
self.estimated_progress_var = ctk.BooleanVar()
|
self.estimated_progress_var = ctk.BooleanVar()
|
||||||
self.estimated_progress_var.trace_add("write", self.enable_save_button)
|
self.estimated_progress_var.trace_add("write", self.enable_save_button)
|
||||||
self.estimated_progress_cb = ctk.CTkSwitch(left_frame, text="Estimated Progress Bar", variable=self.estimated_progress_var)
|
self.estimated_progress_cb = ctk.CTkSwitch(left_frame, text="Estimated progress bar", variable=self.estimated_progress_var)
|
||||||
self.estimated_progress_cb.grid(row=4, column=1, padx=20, pady=(20, 0), sticky="nw")
|
self.estimated_progress_cb.grid(row=4, column=1, padx=20, pady=(20, 0), sticky="nw")
|
||||||
self.estimated_progress_var_tooltip = CTkToolTip(self.estimated_progress_cb, message="This will change how to progress bar works by estimating how long the download will take\
|
self.estimated_progress_var_tooltip = CTkToolTip(self.estimated_progress_cb, message="This will change how to progress bar works by estimating how long the download will take\
|
||||||
\nThis is not accurate ,it's better than with it off which is calculating the downloaded folder size which steamcmd dumps the full size rigth mostly")
|
\nThis is not accurate ,it's better than with it off which is calculating the downloaded folder size which steamcmd dumps the full size rigth mostly")
|
||||||
self.estimated_progress_var.set(self.load_settings("estimated_progress", "on"))
|
self.estimated_progress_var.set(self.load_settings("estimated_progress", "on"))
|
||||||
|
|
||||||
# Show show fails checkbox
|
# Show fails checkbox
|
||||||
self.show_fails_var = ctk.BooleanVar()
|
self.show_fails_var = ctk.BooleanVar()
|
||||||
self.show_fails_var.trace_add("write", self.enable_save_button)
|
self.show_fails_var.trace_add("write", self.enable_save_button)
|
||||||
self.show_fails_cb = ctk.CTkSwitch(left_frame, text="Show fails (on top of progress bar)", variable=self.show_fails_var)
|
self.show_fails_cb = ctk.CTkSwitch(left_frame, text="Show fails", variable=self.show_fails_var)
|
||||||
self.show_fails_cb.grid(row=5, column=1, padx=20, pady=(20, 0), sticky="nw")
|
self.show_fails_cb.grid(row=5, column=1, padx=20, pady=(20, 0), sticky="nw")
|
||||||
self.show_fails_tooltip = CTkToolTip(self.show_fails_cb, message="Display how many times steamcmd has failed/crashed\nIf the number is getting high quickly then try pressing Reset SteamCMD and try again, otherwise its fine")
|
self.show_fails_tooltip = CTkToolTip(self.show_fails_cb, message="Display how many times steamcmd has failed/crashed\nIf the number is getting high quickly then try pressing Reset SteamCMD and try again, otherwise its fine")
|
||||||
self.estimated_progress_var.set(self.load_settings("show_fails", "on"))
|
self.estimated_progress_var.set(self.load_settings("show_fails", "on"))
|
||||||
@ -94,75 +98,138 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
# check items for update on launch
|
# check items for update on launch
|
||||||
self.check_items_var = ctk.BooleanVar()
|
self.check_items_var = ctk.BooleanVar()
|
||||||
self.check_items_var.trace_add("write", self.enable_save_button)
|
self.check_items_var.trace_add("write", self.enable_save_button)
|
||||||
self.check_items_ch = ctk.CTkSwitch(left_frame, text="Check Library items on launch", variable=self.check_items_var)
|
self.check_items_ch = ctk.CTkSwitch(left_frame, text="Check library items on launch", variable=self.check_items_var)
|
||||||
self.check_items_ch.grid(row=7, column=1, padx=20, pady=(20, 0), sticky="nw")
|
self.check_items_ch.grid(row=7, column=1, padx=20, pady=(20, 0), sticky="nw")
|
||||||
self.check_items_tooltip = CTkToolTip(self.check_items_ch, message="This will show a window on launch of items that have pending updates -> you can open it manually from library tab")
|
self.check_items_tooltip = CTkToolTip(self.check_items_ch, message="This will show a window on launch of items that have pending updates -> you can open it manually from library tab")
|
||||||
self.check_items_var.set(self.load_settings("check_items", "off"))
|
self.check_items_var.set(self.load_settings("check_items", "off"))
|
||||||
|
|
||||||
# Resetr steam on many fails
|
|
||||||
|
# TODO: get windows size to padx for the following checkboxes
|
||||||
|
|
||||||
|
# update invalid
|
||||||
|
self.invalid_items_var = ctk.BooleanVar()
|
||||||
|
self.invalid_items_var.trace_add("write", self.enable_save_button)
|
||||||
|
self.invalid_items_ch = ctk.CTkSwitch(left_frame, text="Update invalid items", variable=self.invalid_items_var)
|
||||||
|
self.invalid_items_ch.grid(row=0, column=1, padx=(300,0), pady=(20, 0), sticky="nw")
|
||||||
|
self.invalid_items_tooltip = CTkToolTip(self.invalid_items_ch, message="Allow updating invalid items from the details tab")
|
||||||
|
self.invalid_items_var.set(self.load_settings("update_invalid", "off"))
|
||||||
|
|
||||||
|
# skip invalid
|
||||||
|
self.skip_items_var = ctk.BooleanVar()
|
||||||
|
self.skip_items_var.trace_add("write", self.enable_save_button)
|
||||||
|
self.skip_items_ch = ctk.CTkSwitch(left_frame, text="Skip invalid items", variable=self.skip_items_var)
|
||||||
|
self.skip_items_ch.grid(row=1, column=1, padx=(300,0), pady=(20, 0), sticky="nw")
|
||||||
|
self.skip_items_tooltip = CTkToolTip(self.skip_items_ch, message="Skip invalid items")
|
||||||
|
self.skip_items_var.set(self.load_settings("skip_invalid", "off"))
|
||||||
|
|
||||||
|
# text input fields
|
||||||
|
self.label_destination_folder = ctk.CTkLabel(left_frame, text='Enter Game folder:')
|
||||||
|
self.label_destination_folder.grid(row=8, column=1, padx=20, pady=(20, 0), columnspan=1, sticky="ws")
|
||||||
|
|
||||||
|
self.entry_var1 = ctk.StringVar(value="")
|
||||||
|
self.edit_destination_folder = ctk.CTkEntry(left_frame, placeholder_text="game installation folder", textvariable=self.entry_var1)
|
||||||
|
self.edit_destination_folder.grid(row=9, column=1, padx=20, pady=(0, 10), columnspan=1, sticky="ewn")
|
||||||
|
self.entry_var1.trace_add("write", self.enable_save_button)
|
||||||
|
|
||||||
|
self.button_T7x_browse = ctk.CTkButton(left_frame, text="Select", command=self.open_T7x_browser)
|
||||||
|
self.button_T7x_browse.grid(row=9, column=2, padx=(0, 20), pady=(0, 10), sticky="ewn")
|
||||||
|
|
||||||
|
self.label_steamcmd_path = ctk.CTkLabel(left_frame, text="Enter SteamCMD path:")
|
||||||
|
self.label_steamcmd_path.grid(row=10, column=1, padx=20, pady=(0, 0), columnspan=1, sticky="wn")
|
||||||
|
|
||||||
|
self.entry_var2 = ctk.StringVar(value="")
|
||||||
|
self.edit_steamcmd_path = ctk.CTkEntry(left_frame, placeholder_text="Enter SteamCMD path", textvariable=self.entry_var2)
|
||||||
|
self.edit_steamcmd_path.grid(row=11, column=1, padx=20, pady=(0, 10), columnspan=1, sticky="ewn")
|
||||||
|
self.entry_var2.trace_add("write", self.enable_save_button)
|
||||||
|
|
||||||
|
self.button_steamcmd_browse = ctk.CTkButton(left_frame, text="Select", command=self.open_steamcmd_path_browser)
|
||||||
|
self.button_steamcmd_browse.grid(row=11, column=2, padx=(0, 20), pady=(0, 10), sticky="ewn")
|
||||||
|
|
||||||
|
self.label_launch_args = ctk.CTkLabel(left_frame, text='Launch Parameters:')
|
||||||
|
self.label_launch_args.grid(row=12, column=1, padx=20, pady=(0, 0), columnspan=1, sticky="ws")
|
||||||
|
|
||||||
|
self.edit_startup_exe = ctk.CTkEntry(left_frame, placeholder_text="exe")
|
||||||
|
self.edit_startup_exe.grid(row=13, column=1, padx=(20,0), pady=(0, 20), columnspan=1, sticky="we")
|
||||||
|
|
||||||
|
self.edit_launch_args = ctk.CTkEntry(left_frame, placeholder_text="launch arguments")
|
||||||
|
self.edit_launch_args.grid(row=13, column=1, padx=(140,20), pady=(0, 20), columnspan=2, sticky="we")
|
||||||
|
|
||||||
|
# Check for updates button n Launch game
|
||||||
|
self.check_for_updates = ctk.CTkButton(right_frame, text="Check for updates", command=self.settings_check_for_updates)
|
||||||
|
self.check_for_updates.grid(row=1, column=1, padx=20, pady=(20, 0), sticky="n")
|
||||||
|
|
||||||
|
# self.launch_game = ctk.CTkButton(right_frame, text="Launch game", command=self.settings_launch_game)
|
||||||
|
# self.launch_game.grid(row=2, column=1, padx=20, pady=(10, 0), sticky="n")
|
||||||
|
|
||||||
|
self.reset_steamcmd = ctk.CTkButton(right_frame, text="Reset SteamCMD", command=self.settings_reset_steamcmd)
|
||||||
|
self.reset_steamcmd.grid(row=3, column=1, padx=20, pady=(10, 0), sticky="n")
|
||||||
|
self.reset_steamcmd_tooltip = CTkToolTip(self.reset_steamcmd, message="This will remove steamapps folder + all the maps that are potentioaly corrupted\nor not so use at ur own risk (could fix some issues as well)")
|
||||||
|
|
||||||
|
self.workshop_to_gamedir = ctk.CTkButton(right_frame, text="Workshop Transfer", command=self.workshop_to_gamedir_toplevel)
|
||||||
|
self.workshop_to_gamedir.grid(row=4, column=1, padx=20, pady=(10, 0), sticky="n")
|
||||||
|
self.workshop_to_gamedir_tooltip = CTkToolTip(self.workshop_to_gamedir, message="Copy/Move maps and mods from Workshop to the game directory (opens up a window)")
|
||||||
|
|
||||||
|
# appearance
|
||||||
|
self.appearance_mode_label = ctk.CTkLabel(right_frame, text="Appearance:", anchor="w")
|
||||||
|
self.appearance_mode_label.grid(row=5, column=1, padx=20, pady=(150, 0), sticky="nw")
|
||||||
|
self.appearance_mode_optionemenu = ctk.CTkOptionMenu(right_frame, values=["Light", "Dark", "System"],
|
||||||
|
command=master.change_appearance_mode_event)
|
||||||
|
self.appearance_mode_optionemenu.grid(row=6, column=1, padx=20, pady=(0, 0), sticky="nw")
|
||||||
|
self.scaling_label = ctk.CTkLabel(right_frame, text="UI Scaling:", anchor="w")
|
||||||
|
self.scaling_label.grid(row=7, column=1, padx=20, pady=(0, 0), sticky="nw")
|
||||||
|
self.scaling_optionemenu = ctk.CTkOptionMenu(right_frame, values=["60%", "70%", "80%", "90%", "100%", "110%"],
|
||||||
|
command=master.change_scaling_event)
|
||||||
|
self.scaling_optionemenu.grid(row=8, column=1, padx=20, pady=(0, 0), sticky="nw")
|
||||||
|
|
||||||
|
# self.custom_theme = ctk.CTkButton(right_frame, text="Custom theme", command=self.T7xwd_custom_theme)
|
||||||
|
# self.custom_theme.grid(row=9, column=1, padx=20, pady=(20, 0), sticky="n")
|
||||||
|
|
||||||
|
self.theme_options_label = ctk.CTkLabel(right_frame, text="Theme:", anchor="w")
|
||||||
|
self.theme_options_label.grid(row=9, column=1, padx=20, pady=(0, 0), sticky="nw")
|
||||||
|
self.theme_options = ctk.CTkOptionMenu(right_frame, values=["Default", "Blue", "Grey", "Obsidian", "Ghost","NeonBanana", "Custom"],
|
||||||
|
command=self.theme_options_func)
|
||||||
|
self.theme_options.grid(row=10, column=1, padx=20, pady=(0, 0), sticky="nw")
|
||||||
|
self.theme_options.set(value=self.load_settings("theme", "Default"))
|
||||||
|
|
||||||
|
# Reset steam on many fails
|
||||||
self.reset_steamcmd_on_fail_var = ctk.IntVar()
|
self.reset_steamcmd_on_fail_var = ctk.IntVar()
|
||||||
self.reset_steamcmd_on_fail_var.trace_add("write", self.enable_save_button)
|
self.reset_steamcmd_on_fail_var.trace_add("write", self.enable_save_button)
|
||||||
self.reset_steamcmd_on_fail_text = ctk.CTkLabel(left_frame, text=f"Reset steamcmd: (n of fails):", anchor="w")
|
self.reset_steamcmd_on_fail_text = ctk.CTkLabel(right_frame, text=f"Download Attempts:", anchor="w")
|
||||||
self.reset_steamcmd_on_fail_text.grid(row=8, column=1, padx=20, pady=(10, 0), sticky="nw")
|
self.reset_steamcmd_on_fail_text.grid(row=11, column=1, padx=20, pady=(0, 0), sticky="nw")
|
||||||
self.reset_steamcmd_on_fail = ctk.CTkOptionMenu(left_frame, values=["5", "10", "20", "30", "40", "Custom", "Disable"], variable=self.reset_steamcmd_on_fail_var, command=self.reset_steamcmd_on_fail_func)
|
self.reset_steamcmd_on_fail = ctk.CTkOptionMenu(right_frame, values=["5", "10", "15", "20", "Custom", "Disable"], variable=self.reset_steamcmd_on_fail_var, command=self.reset_steamcmd_on_fail_func)
|
||||||
self.reset_steamcmd_on_fail.grid(row=8, column=1, padx=(190, 0), pady=(10, 0), sticky="nw")
|
self.reset_steamcmd_on_fail.grid(row=12, column=1, padx=20, pady=(0, 0), sticky="nw")
|
||||||
self.reset_steamcmd_on_fail_tooltip = CTkToolTip(self.reset_steamcmd_on_fail, message="This actually fixes steamcmd when its crashing way too much")
|
self.reset_steamcmd_on_fail_tooltip = CTkToolTip(self.reset_steamcmd_on_fail, message="Number of failed download attempts before resetting SteamCMD")
|
||||||
self.reset_steamcmd_on_fail.set(value=self.load_settings("reset_on_fail", "10"))
|
self.reset_steamcmd_on_fail.set(value=self.load_settings("reset_on_fail", "10"))
|
||||||
|
|
||||||
# item folder naming
|
# item folder naming
|
||||||
self.folder_options_label_var = ctk.IntVar()
|
self.folder_options_label_var = ctk.IntVar()
|
||||||
self.folder_options_label_var.trace_add("write", self.enable_save_button)
|
self.folder_options_label_var.trace_add("write", self.enable_save_button)
|
||||||
self.folder_options_label = ctk.CTkLabel(left_frame, text="Items Folder Naming:", anchor="nw")
|
self.folder_options_label = ctk.CTkLabel(right_frame, text="Items Folder Naming:", anchor="w")
|
||||||
self.folder_options_label.grid(row=10, column=1, padx=20, pady=(10, 0), sticky="nw")
|
self.folder_options_label.grid(row=13, column=1, padx=(20,0), pady=(0, 0), sticky="nw")
|
||||||
self.folder_options = ctk.CTkOptionMenu(left_frame, values=["PublisherID", "FolderName"], command=self.change_folder_naming,
|
self.folder_options = ctk.CTkOptionMenu(right_frame, values=["PublisherID", "FolderName"], command=self.change_folder_naming,
|
||||||
variable=self.folder_options_label_var)
|
variable=self.folder_options_label_var)
|
||||||
self.folder_options.grid(row=10, column=1, padx=(150, 0), pady=(3, 0), sticky="nw")
|
self.folder_options.grid(row=14, column=1, padx=20, pady=(0, 0), sticky="nw")
|
||||||
self.folder_options.set(value=self.load_settings("folder_naming", "PublisherID"))
|
self.folder_options.set(value=self.load_settings("folder_naming", "PublisherID"))
|
||||||
|
|
||||||
# Check for updates button n Launch T7x
|
|
||||||
self.check_for_updates = ctk.CTkButton(right_frame, text="Check for updates", command=self.settings_check_for_updates)
|
|
||||||
self.check_for_updates.grid(row=1, column=1, padx=20, pady=(20, 0), sticky="n")
|
|
||||||
|
|
||||||
self.launch_T7x = ctk.CTkButton(right_frame, text="Launch T7x", command=self.settings_launch_T7x)
|
|
||||||
self.launch_T7x.grid(row=2, column=1, padx=20, pady=(20, 0), sticky="n")
|
|
||||||
|
|
||||||
self.reset_steamcmd = ctk.CTkButton(right_frame, text="Reset SteamCMD", command=self.settings_reset_steamcmd)
|
|
||||||
self.reset_steamcmd.grid(row=3, column=1, padx=20, pady=(20, 0), sticky="n")
|
|
||||||
self.reset_steamcmd_tooltip = CTkToolTip(self.reset_steamcmd, message="This will remove steamapps folder + all the maps that are potentioaly corrupted\nor not so use at ur own risk (could fix some issues as well)")
|
|
||||||
|
|
||||||
self.steam_to_T7x = ctk.CTkButton(right_frame, text="Steam to T7x", command=self.from_steam_to_T7x_toplevel)
|
|
||||||
self.steam_to_T7x.grid(row=5, column=1, padx=20, pady=(20, 0), sticky="n")
|
|
||||||
self.steam_to_T7x_tooltip = CTkToolTip(self.steam_to_T7x, message="Moves/copies maps and mods from steam to T7x (opens up a window)")
|
|
||||||
|
|
||||||
# appearance
|
|
||||||
self.appearance_mode_label = ctk.CTkLabel(right_frame, text="Appearance Mode:", anchor="n")
|
|
||||||
self.appearance_mode_label.grid(row=6, column=1, padx=20, pady=(20, 0))
|
|
||||||
self.appearance_mode_optionemenu = ctk.CTkOptionMenu(right_frame, values=["Light", "Dark", "System"],
|
|
||||||
command=master.change_appearance_mode_event)
|
|
||||||
self.appearance_mode_optionemenu.grid(row=7, column=1, padx=20, pady=(0, 0))
|
|
||||||
self.scaling_label = ctk.CTkLabel(right_frame, text="UI Scaling:", anchor="n")
|
|
||||||
self.scaling_label.grid(row=8, column=1, padx=20, pady=(10, 0))
|
|
||||||
self.scaling_optionemenu = ctk.CTkOptionMenu(right_frame, values=["80%", "90%", "100%", "110%", "120%"],
|
|
||||||
command=master.change_scaling_event)
|
|
||||||
self.scaling_optionemenu.grid(row=9, column=1, padx=20, pady=(0, 0))
|
|
||||||
|
|
||||||
# self.custom_theme = ctk.CTkButton(right_frame, text="Custom theme", command=self.T7xwd_custom_theme)
|
|
||||||
# self.custom_theme.grid(row=8, column=1, padx=20, pady=(20, 0), sticky="n")
|
|
||||||
|
|
||||||
self.theme_options_label = ctk.CTkLabel(right_frame, text="Themes:", anchor="n")
|
|
||||||
self.theme_options_label.grid(row=10, column=1, padx=20, pady=(10, 0))
|
|
||||||
self.theme_options = ctk.CTkOptionMenu(right_frame, values=["Default", "Blue", "Grey", "Obsidian", "Ghost","NeonBanana", "Custom"],
|
|
||||||
command=self.theme_options_func)
|
|
||||||
self.theme_options.grid(row=11, column=1, padx=20, pady=(0, 0))
|
|
||||||
self.theme_options.set(value=self.load_settings("theme", "Default"))
|
|
||||||
|
|
||||||
# Save button
|
|
||||||
self.save_button = ctk.CTkButton(self, text="Save", command=self.save_settings, state='disabled')
|
|
||||||
self.save_button.grid(row=3, column=0, padx=20, pady=(20, 20), sticky="nw")
|
|
||||||
|
|
||||||
#version
|
#version
|
||||||
self.version_info = ctk.CTkLabel(self, text=f"{VERSION}")
|
self.version_info = ctk.CTkLabel(self, text=f"{VERSION}")
|
||||||
self.version_info.grid(row=3, column=1, padx=20, pady=(20, 20), sticky="e")
|
self.version_info.grid(row=3, column=2, padx=20, pady=(20, 20), sticky="e")
|
||||||
|
|
||||||
|
def open_T7x_browser(self):
|
||||||
|
selected_folder = ctk.filedialog.askdirectory(title="Select Game Folder")
|
||||||
|
if selected_folder:
|
||||||
|
self.edit_destination_folder.delete(0, "end")
|
||||||
|
self.edit_destination_folder.insert(0, selected_folder)
|
||||||
|
save_config("DestinationFolder" ,self.edit_destination_folder.get())
|
||||||
|
save_config("SteamCMDPath" ,self.edit_steamcmd_path.get())
|
||||||
|
|
||||||
|
def open_steamcmd_path_browser(self):
|
||||||
|
selected_folder = ctk.filedialog.askdirectory(title="Select SteamCMD Folder")
|
||||||
|
if selected_folder:
|
||||||
|
self.edit_steamcmd_path.delete(0, "end")
|
||||||
|
self.edit_steamcmd_path.insert(0, selected_folder)
|
||||||
|
save_config("DestinationFolder" ,self.edit_destination_folder.get())
|
||||||
|
save_config("SteamCMDPath" ,self.edit_steamcmd_path.get())
|
||||||
|
|
||||||
def reset_steamcmd_on_fail_func(self, option: str):
|
def reset_steamcmd_on_fail_func(self, option: str):
|
||||||
if option == "Custom":
|
if option == "Custom":
|
||||||
@ -225,6 +292,9 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
def save_settings(self):
|
def save_settings(self):
|
||||||
self.save_button.configure(state='disabled')
|
self.save_button.configure(state='disabled')
|
||||||
|
|
||||||
|
save_config("GameExecutable", str(self.edit_startup_exe.get()) if not isNullOrWhiteSpace(self.edit_startup_exe.get()) else "BlackOps3")
|
||||||
|
save_config("LaunchParameters", str(self.edit_launch_args.get()) if not isNullOrWhiteSpace(self.edit_launch_args.get()) else " ")
|
||||||
|
|
||||||
if self.folder_options.get() == "PublisherID":
|
if self.folder_options.get() == "PublisherID":
|
||||||
save_config("folder_naming", "0")
|
save_config("folder_naming", "0")
|
||||||
else:
|
else:
|
||||||
@ -235,10 +305,20 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
else:
|
else:
|
||||||
save_config("check_items", "off")
|
save_config("check_items", "off")
|
||||||
|
|
||||||
if self.check_updates_checkbox.get():
|
if self.invalid_items_var.get():
|
||||||
save_config("checkforupdtes", "on")
|
save_config("update_invalid", "on")
|
||||||
else:
|
else:
|
||||||
save_config("checkforupdtes", "off")
|
save_config("update_invalid", "off")
|
||||||
|
|
||||||
|
if self.skip_items_var.get():
|
||||||
|
save_config("skip_invalid", "on")
|
||||||
|
else:
|
||||||
|
save_config("skip_invalid", "off")
|
||||||
|
|
||||||
|
if self.check_updates_checkbox.get():
|
||||||
|
save_config("checkforupdates", "on")
|
||||||
|
else:
|
||||||
|
save_config("checkforupdates", "off")
|
||||||
|
|
||||||
if self.checkbox_show_console.get():
|
if self.checkbox_show_console.get():
|
||||||
save_config("console", "on")
|
save_config("console", "on")
|
||||||
@ -380,8 +460,8 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
file_to_rename = os.path.join(APPLICATION_PATH, "T7xwd_theme.json")
|
file_to_rename = os.path.join(APPLICATION_PATH, "T7xwd_theme.json")
|
||||||
if os.path.exists(file_to_rename):
|
if os.path.exists(file_to_rename):
|
||||||
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
new_name = f"T7xwd_theme_{timestamp}.json"
|
name = f"T7xwd_theme_{timestamp}.json"
|
||||||
os.rename(file_to_rename, os.path.join(APPLICATION_PATH, new_name))
|
os.rename(file_to_rename, os.path.join(APPLICATION_PATH, name))
|
||||||
|
|
||||||
if not disable_only:
|
if not disable_only:
|
||||||
show_message("Preset file renamed", "Custom preset disabled, file has been renmaed\n* Restart the app to take effect", icon="info")
|
show_message("Preset file renamed", "Custom preset disabled, file has been renmaed\n* Restart the app to take effect", icon="info")
|
||||||
@ -399,9 +479,9 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
|
|
||||||
# make this rename to {id}_duplicate as a fallback
|
# make this rename to {id}_duplicate as a fallback
|
||||||
def rename_all_folders(self, option):
|
def rename_all_folders(self, option):
|
||||||
T7xFolder = main_app.app.edit_destination_folder.get()
|
gameFolder = self.edit_destination_folder.get()
|
||||||
maps_folder = os.path.join(T7xFolder, "mods")
|
mods_folder = os.path.join(gameFolder, "mods")
|
||||||
mods_folder = os.path.join(T7xFolder, "usermaps")
|
maps_folder = os.path.join(gameFolder, "usermaps")
|
||||||
|
|
||||||
folders_to_process = []
|
folders_to_process = []
|
||||||
|
|
||||||
@ -412,61 +492,105 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
folders_to_process.append(maps_folder)
|
folders_to_process.append(maps_folder)
|
||||||
|
|
||||||
if not os.path.exists(maps_folder) and not os.path.exists(mods_folder):
|
if not os.path.exists(maps_folder) and not os.path.exists(mods_folder):
|
||||||
show_message("Warning -> Check T7x path", f"You don't have any items yet ,from now on item's folders will be named as their {option}")
|
show_message("Warning -> Check game path",
|
||||||
|
f"You don't have any items yet, from now on item's folders will be named as their {option}")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
processed_names = set()
|
processed_names = set()
|
||||||
|
|
||||||
for folder_path in folders_to_process:
|
files = Path(folders_to_process[0]).glob("*/zone/workshop.json")
|
||||||
for folder_name in os.listdir(folder_path):
|
items = dict()
|
||||||
zone_path = os.path.join(folder_path, folder_name, "zone")
|
ignored_folders = []
|
||||||
if not os.path.isdir(zone_path):
|
|
||||||
continue
|
|
||||||
if folder_name in main_app.app.library_tab.item_block_list:
|
|
||||||
continue
|
|
||||||
|
|
||||||
json_path = os.path.join(zone_path, "workshop.json")
|
for idx, file in enumerate(files):
|
||||||
publisher_id = extract_json_data(json_path, 'PublisherID')
|
curr_folder_name = os.path.relpath(file, folders_to_process[0]).split("\\", 1)[0]
|
||||||
new_name = extract_json_data(json_path, option)
|
|
||||||
if folder_name == new_name:
|
|
||||||
continue
|
|
||||||
|
|
||||||
rename_flag = True
|
with open(file, 'r') as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
if os.path.exists(json_path):
|
_item = {
|
||||||
folder_to_rename = os.path.join(folder_path, folder_name)
|
'PublisherID': data.get('PublisherID'),
|
||||||
new_folder_name = new_name
|
'Name': data.get(option),
|
||||||
while new_folder_name in processed_names:
|
'current_folder': curr_folder_name
|
||||||
if new_name == publisher_id:
|
}
|
||||||
new_folder_name += f"_duplicated"
|
if _item.get('PublisherID')!="" and int(_item.get('PublisherID'))>0:
|
||||||
|
items[idx] = _item
|
||||||
else:
|
else:
|
||||||
new_folder_name += f"_{publisher_id}"
|
ignored_folders.append(curr_folder_name)
|
||||||
if folder_name == new_folder_name:
|
|
||||||
rename_flag = False
|
|
||||||
break
|
|
||||||
new_path = os.path.join(folder_path, new_folder_name)
|
|
||||||
|
|
||||||
while os.path.exists(new_path):
|
IDs = [x['PublisherID'] for x in items.values()]
|
||||||
if new_name == publisher_id:
|
Names = [x['Name'] for x in items.values()]
|
||||||
new_folder_name += f"_duplicated"
|
currFolder = [x['current_folder'] for x in items.values()]
|
||||||
|
|
||||||
|
def indices(lst, item):
|
||||||
|
return [i for i, x in enumerate(lst) if item in x]
|
||||||
|
|
||||||
|
def find_duplicate_items_in_list(list, items):
|
||||||
|
return dict((x, indices(list, x)) for x in [y for y in items if items.count(y) > 1])
|
||||||
|
|
||||||
|
def prep_rename(changelist, orig, new):
|
||||||
|
return changelist.append((os.path.join(folders_to_process[0], orig), os.path.join(folders_to_process[0], new)))
|
||||||
|
|
||||||
|
duplicates = find_duplicate_items_in_list(Names, Names)
|
||||||
|
duplicates_IDs = find_duplicate_items_in_list(IDs, IDs)
|
||||||
|
|
||||||
|
duplicate_idx = concatenate_sublists(duplicates.values())
|
||||||
|
|
||||||
|
changelist = []
|
||||||
|
|
||||||
|
for i in range(len(IDs)):
|
||||||
|
if i not in duplicate_idx:
|
||||||
|
prep_rename(changelist, currFolder[i], Names[i])
|
||||||
|
|
||||||
|
for v in duplicates.values():
|
||||||
|
if len(v) == 2:
|
||||||
|
if IDs[v[0]] == IDs[v[1]]:
|
||||||
|
prep_rename(changelist, currFolder[v[0]], Names[v[0]])
|
||||||
|
prep_rename(
|
||||||
|
changelist, currFolder[v[1]], Names[v[1]]+"_duplicate")
|
||||||
else:
|
else:
|
||||||
new_folder_name += f"_{publisher_id}"
|
prep_rename(
|
||||||
if folder_name == new_folder_name:
|
changelist, currFolder[v[0]], Names[v[0]]+f"_{IDs[v[0]]}")
|
||||||
rename_flag = False
|
prep_rename(
|
||||||
break
|
changelist, currFolder[v[1]], Names[v[1]]+f"_{IDs[v[1]]}")
|
||||||
new_path = os.path.join(folder_path, new_folder_name)
|
|
||||||
|
|
||||||
if rename_flag:
|
if len(v) > 2:
|
||||||
os.rename(folder_to_rename, new_path)
|
for j, i in enumerate(v):
|
||||||
processed_names.add(new_folder_name)
|
if i in (duplicates_IDs.get(f'{IDs[i]}') if duplicates_IDs.get(f'{IDs[i]}') is not None else []):
|
||||||
|
if i == v[0]:
|
||||||
|
if Names[i].startswith(IDs[i]):
|
||||||
|
prep_rename(
|
||||||
|
changelist, currFolder[i], Names[i])
|
||||||
|
else:
|
||||||
|
prep_rename(
|
||||||
|
changelist, currFolder[i], Names[i]+f"_{IDs[i]}")
|
||||||
|
else:
|
||||||
|
if Names[i].startswith(IDs[i]):
|
||||||
|
newname = Names[i]+f"_duplicate"
|
||||||
|
else:
|
||||||
|
newname = Names[i]+f"_{IDs[i]}"
|
||||||
|
|
||||||
|
if j > 0:
|
||||||
|
newname += '_' + str(j)
|
||||||
|
|
||||||
|
prep_rename(changelist, currFolder[i], newname)
|
||||||
|
else:
|
||||||
|
prep_rename(
|
||||||
|
changelist, currFolder[i], Names[i]+f"_{IDs[i]}")
|
||||||
|
|
||||||
|
for n in changelist:
|
||||||
|
safe_name = nextnonexistentdir(*tuple(reversed(os.path.split(n[1]))))
|
||||||
|
if safe_name[0] in ignored_folders and safe_name[1] > 0:
|
||||||
|
os.rename(n[0], os.path.join(n[0], '{}_{}'.format(*safe_name)))
|
||||||
|
else:
|
||||||
|
os.rename(n[0], n[1])
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def change_folder_naming(self, option):
|
def change_folder_naming(self, option):
|
||||||
main_app.app.title("T7x Workshop Downloader - Settings ➜ Loading... ⏳")
|
main_app.app.title("T7x Workshop Downloader - Settings ➜ Loading... ⏳")
|
||||||
try:
|
try:
|
||||||
if os.path.exists(main_app.app.edit_destination_folder.get()):
|
if os.path.exists(self.edit_destination_folder.get()):
|
||||||
lib = main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
lib = main_app.app.library_tab.load_items(self.edit_destination_folder.get(), dont_add=True)
|
||||||
if not "No items" in lib:
|
if not "No items" in lib:
|
||||||
if show_message("Renaming", "Would you like to rename all your exisiting item folders now?", _return=True):
|
if show_message("Renaming", "Would you like to rename all your exisiting item folders now?", _return=True):
|
||||||
main_app.app.title("T7x Workshop Downloader - Settings ➜ Renaming... ⏳")
|
main_app.app.title("T7x Workshop Downloader - Settings ➜ Renaming... ⏳")
|
||||||
@ -476,13 +600,13 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
return 0
|
return 0
|
||||||
else:
|
else:
|
||||||
show_message("Done!", "All folders have been renamed", icon="info")
|
show_message("Done!", "All folders have been renamed", icon="info")
|
||||||
main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
main_app.app.library_tab.load_items(self.edit_destination_folder.get(), dont_add=True)
|
||||||
else:
|
else:
|
||||||
show_message("Heads up!", "Only newly downloaded items will be affected", icon="info")
|
show_message("Heads up!", "Only newly downloaded items will be affected", icon="info")
|
||||||
else:
|
else:
|
||||||
show_message("Warning -> Check T7x path", f"You don't have any items yet ,from now on item's folders will be named as their {option}")
|
show_message("Warning -> Check game path", f"You don't have any items yet ,from now on item's folders will be named as their {option}")
|
||||||
else:
|
else:
|
||||||
show_message("Warning -> Check T7x path", f"You don't have any items yet ,from now on item's folders will be named as their {option}")
|
show_message("Warning -> Check game path", f"You don't have any items yet ,from now on item's folders will be named as their {option}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
show_message("Error", f"Error occured \n{e}")
|
show_message("Error", f"Error occured \n{e}")
|
||||||
finally:
|
finally:
|
||||||
@ -490,7 +614,7 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
self.save_settings()
|
self.save_settings()
|
||||||
|
|
||||||
def load_on_switch_screen(self):
|
def load_on_switch_screen(self):
|
||||||
self.check_updates_var.set(self.load_settings("checkforupdtes"))
|
self.check_updates_var.set(self.load_settings("checkforupdates"))
|
||||||
self.console_var.set(self.load_settings("console"))
|
self.console_var.set(self.load_settings("console"))
|
||||||
self.reset_steamcmd_on_fail.set(value=self.load_settings("reset_on_fail", "10"))
|
self.reset_steamcmd_on_fail.set(value=self.load_settings("reset_on_fail", "10"))
|
||||||
self.estimated_progress_var.set(self.load_settings("estimated_progress", "on"))
|
self.estimated_progress_var.set(self.load_settings("estimated_progress", "on"))
|
||||||
@ -502,20 +626,20 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
# keep last cuz of trace_add()
|
# keep last cuz of trace_add()
|
||||||
self.save_button.configure(state='disabled')
|
self.save_button.configure(state='disabled')
|
||||||
|
|
||||||
def settings_launch_T7x(self):
|
def settings_launch_game(self):
|
||||||
launch_T7x_func(check_config("destinationfolder"))
|
launch_game_func(check_config("destinationfolder"), self.edit_startup_exe.get(), self.edit_launch_args.get())
|
||||||
|
|
||||||
def settings_reset_steamcmd(self):
|
def settings_reset_steamcmd(self):
|
||||||
reset_steamcmd()
|
reset_steamcmd()
|
||||||
|
|
||||||
def from_steam_to_T7x_toplevel(self):
|
def workshop_to_gamedir_toplevel(self):
|
||||||
try:
|
try:
|
||||||
# to make sure json file is up to date
|
# 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)
|
main_app.app.library_tab.load_items(self.edit_destination_folder.get(), dont_add=True)
|
||||||
top = ctk.CTkToplevel(self)
|
top = ctk.CTkToplevel(self)
|
||||||
if os.path.exists(os.path.join(RESOURCES_DIR, "ryuk.ico")):
|
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.after(210, lambda: top.iconbitmap(os.path.join(RESOURCES_DIR, "ryuk.ico")))
|
||||||
top.title("Steam to T7x")
|
top.title("Workshop Transfer")
|
||||||
_, _, x, y = get_window_size_from_registry()
|
_, _, x, y = get_window_size_from_registry()
|
||||||
top.geometry(f"+{x}+{y}")
|
top.geometry(f"+{x}+{y}")
|
||||||
# top.attributes('-topmost', 'true')
|
# top.attributes('-topmost', 'true')
|
||||||
@ -527,9 +651,10 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
steam_folder_label = ctk.CTkLabel(center_frame, text="Steam Folder:")
|
steam_folder_label = ctk.CTkLabel(center_frame, text="Steam Folder:")
|
||||||
steam_folder_entry = ctk.CTkEntry(center_frame, width=225)
|
steam_folder_entry = ctk.CTkEntry(center_frame, width=225)
|
||||||
button_steam_browse = ctk.CTkButton(center_frame, text="Select", width=10)
|
button_steam_browse = ctk.CTkButton(center_frame, text="Select", width=10)
|
||||||
T7x_folder_label = ctk.CTkLabel(center_frame, text="T7x Folder:")
|
game_folder_label = ctk.CTkLabel(center_frame, text="Game Folder:")
|
||||||
T7x_folder_entry = ctk.CTkEntry(center_frame, width=225)
|
game_folder_entry = ctk.CTkEntry(center_frame, width=225)
|
||||||
button_T7x_browse = ctk.CTkButton(center_frame, text="Select", width=10)
|
button_T7x_browse = ctk.CTkButton(center_frame, text="Select", width=10)
|
||||||
|
|
||||||
# Create option to choose between cut or copy
|
# Create option to choose between cut or copy
|
||||||
operation_label = ctk.CTkLabel(center_frame, text="Choose operation:")
|
operation_label = ctk.CTkLabel(center_frame, text="Choose operation:")
|
||||||
copy_var = ctk.BooleanVar()
|
copy_var = ctk.BooleanVar()
|
||||||
@ -574,11 +699,11 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
if copy_var.get():
|
if copy_var.get():
|
||||||
copy_button.configure(text=f"Start (Copy)")
|
copy_button.configure(text=f"Start (Copy)")
|
||||||
|
|
||||||
def open_T7x_browser():
|
def open_game_browser():
|
||||||
selected_folder = ctk.filedialog.askdirectory(title="Select T7x Folder")
|
selected_folder = ctk.filedialog.askdirectory(title="Select Game Folder")
|
||||||
if selected_folder:
|
if selected_folder:
|
||||||
T7x_folder_entry.delete(0, "end")
|
game_folder_entry.delete(0, "end")
|
||||||
T7x_folder_entry.insert(0, selected_folder)
|
game_folder_entry.insert(0, selected_folder)
|
||||||
|
|
||||||
def open_steam_browser():
|
def open_steam_browser():
|
||||||
selected_folder = ctk.filedialog.askdirectory(title="Select Steam Folder (ex: C:/Program Files (x86)/Steam)")
|
selected_folder = ctk.filedialog.askdirectory(title="Select Steam Folder (ex: C:/Program Files (x86)/Steam)")
|
||||||
@ -591,20 +716,20 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
def start_thread():
|
def start_thread():
|
||||||
try:
|
try:
|
||||||
if not cut_var.get() and not copy_var.get():
|
if not cut_var.get() and not copy_var.get():
|
||||||
show_message("Choose operation!", "Please choose an operation, Copy or Cut files from steam!")
|
show_message("Choose operation!", "Please choose an operation, Copy or Cut files from Steam!")
|
||||||
return
|
return
|
||||||
|
|
||||||
copy_button.configure(state="disabled")
|
copy_button.configure(state="disabled")
|
||||||
steam_folder = steam_folder_entry.get()
|
steam_folder = steam_folder_entry.get()
|
||||||
ws_folder = os.path.join(steam_folder, "steamapps/workshop/content/311210")
|
ws_folder = os.path.join(steam_folder, "steamapps/workshop/content/311210")
|
||||||
T7x_folder = T7x_folder_entry.get()
|
game_folder = game_folder_entry.get()
|
||||||
|
|
||||||
if not os.path.exists(steam_folder) and not os.path.exists(ws_folder):
|
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)")
|
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
|
return
|
||||||
|
|
||||||
if not os.path.exists(T7x_folder):
|
if not os.path.exists(game_folder):
|
||||||
show_message("Not found", "T7x folder not found, please recheck path")
|
show_message("Not found", "game folder not found, please recheck path")
|
||||||
return
|
return
|
||||||
|
|
||||||
top.after(0, progress_text.configure(text="Loading..."))
|
top.after(0, progress_text.configure(text="Loading..."))
|
||||||
@ -644,10 +769,10 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
folder_name = extract_json_data(json_file_path, "publisherID")
|
folder_name = extract_json_data(json_file_path, "publisherID")
|
||||||
|
|
||||||
if mod_type == "mod":
|
if mod_type == "mod":
|
||||||
path_folder = os.path.join(T7x_folder, "mods")
|
path_folder = os.path.join(game_folder, "mods")
|
||||||
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
||||||
elif mod_type == "map":
|
elif mod_type == "map":
|
||||||
path_folder = os.path.join(T7x_folder, "usermaps")
|
path_folder = os.path.join(game_folder, "usermaps")
|
||||||
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
folder_name_path = os.path.join(path_folder, folder_name, "zone")
|
||||||
else:
|
else:
|
||||||
show_message("Error", "Invalid workshop type in workshop.json, are you sure this is a map or a mod?.", icon="cancel")
|
show_message("Error", "Invalid workshop type in workshop.json, are you sure this is a map or a mod?.", icon="cancel")
|
||||||
@ -669,17 +794,17 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
if cut_var.get():
|
if cut_var.get():
|
||||||
remove_tree(os.path.join(map_folder, dir_name))
|
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)
|
main_app.app.library_tab.update_item(self.edit_destination_folder.get(), workshop_id, mod_type, folder_name)
|
||||||
else:
|
else:
|
||||||
# if its last folder to check
|
# if its last folder to check
|
||||||
if i == total_folders:
|
if i == total_folders:
|
||||||
show_message("Error", f"workshop.json not found in {dir_name}", icon="cancel")
|
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)
|
main_app.app.library_tab.load_items(self.edit_destination_folder.get(), dont_add=True)
|
||||||
return
|
return
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if subfolders:
|
if subfolders:
|
||||||
main_app.app.library_tab.load_items(main_app.app.edit_destination_folder.get(), dont_add=True)
|
main_app.app.library_tab.load_items(self.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)")
|
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:
|
finally:
|
||||||
@ -699,8 +824,8 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
button_steam_browse.grid(row=1, column=2, padx=(0, 20), pady=(10, 10), sticky="wnes")
|
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_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')
|
steam_folder_entry.grid(row=1, column=0, columnspan=2, padx=(0, 20), pady=(10, 10), sticky='nes')
|
||||||
T7x_folder_label.grid(row=2, column=0, padx=(20, 20), pady=(10, 0), sticky='w')
|
game_folder_label.grid(row=2, column=0, padx=(20, 20), pady=(10, 0), sticky='w')
|
||||||
T7x_folder_entry.grid(row=3, column=0, columnspan=2, padx=(0, 20), pady=(10, 10), sticky='nes')
|
game_folder_entry.grid(row=3, column=0, columnspan=2, padx=(0, 20), pady=(10, 10), sticky='nes')
|
||||||
button_T7x_browse.grid(row=3, column=2, padx=(0, 20), pady=(10, 10), sticky="wnes")
|
button_T7x_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')
|
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')
|
copy_check.grid(row=4, column=1, padx=(0, 10), pady=(10, 10), sticky='wnes')
|
||||||
@ -711,14 +836,14 @@ class SettingsTab(ctk.CTkFrame):
|
|||||||
progress_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")), "progress_bar_fill_color")
|
progress_color = get_button_state_colors(check_custom_theme(check_config("theme", fallback="T7xwd_theme.json")), "progress_bar_fill_color")
|
||||||
progress_bar.configure(progress_color=progress_color)
|
progress_bar.configure(progress_color=progress_color)
|
||||||
steam_folder_entry.insert(1, check_config("steam_folder", ""))
|
steam_folder_entry.insert(1, check_config("steam_folder", ""))
|
||||||
T7x_folder_entry.insert(1, main_app.app.edit_destination_folder.get())
|
game_folder_entry.insert(1, self.edit_destination_folder.get())
|
||||||
button_T7x_browse.configure(command=open_T7x_browser)
|
button_T7x_browse.configure(command=open_game_browser)
|
||||||
button_steam_browse.configure(command=open_steam_browser)
|
button_steam_browse.configure(command=open_steam_browser)
|
||||||
copy_button.configure(command=start_copy_operation)
|
copy_button.configure(command=start_copy_operation)
|
||||||
cut_check.configure(command = lambda: check_status(cut_var, copy_var))
|
cut_check.configure(command = lambda: check_status(cut_var, copy_var))
|
||||||
copy_check.configure(command = lambda: check_status(copy_var, cut_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(steam_folder_entry)
|
||||||
main_app.app.create_context_menu(T7x_folder_entry)
|
main_app.app.create_context_menu(game_folder_entry)
|
||||||
copy_var.set(True)
|
copy_var.set(True)
|
||||||
progress_bar.set(0)
|
progress_bar.set(0)
|
||||||
top.after(150, top.focus_force)
|
top.after(150, top.focus_force)
|
||||||
|
Loading…
Reference in New Issue
Block a user