Skip to content

Commit a951181

Browse files
committed
[v0.3.0] Added various bug fixes and improved downloading
1 parent c5111b8 commit a951181

File tree

3 files changed

+223
-121
lines changed

3 files changed

+223
-121
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "factorio-mod-downloader"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
description = "One Downloader for all your factorio mods."
55
authors = ["Vaibhav Vikas <vbhvvikas@gmail.com>"]
66
license = "MIT"

src/factorio_mod_downloader/__main__.py

Lines changed: 138 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,105 @@
77

88
import customtkinter
99
from CTkMessagebox import CTkMessagebox
10-
1110
from factorio_mod_downloader.mod_downloader.mod_downloader import ModDownloader
1211

13-
1412
customtkinter.set_appearance_mode("dark")
1513
customtkinter.set_default_color_theme("blue")
1614

17-
1815
def resource_path(relative_path):
1916
if hasattr(sys, "_MEIPASS"):
2017
return os.path.join(sys._MEIPASS, relative_path)
2118
return relative_path
2219

2320

21+
class DownloadEntry:
22+
def __init__(self, frame, label_widget, progress_bar):
23+
self.frame = frame
24+
self.label = label_widget
25+
self.progress_bar = progress_bar
26+
2427
class App(customtkinter.CTk):
2528
def __init__(self):
2629
super().__init__()
2730
self.resizable(0, 0)
28-
self.title("Factorio Mod Downloader v0.2.2")
29-
self.geometry(f"{740}x{560}")
31+
self.title("Factorio Mod Downloader v0.3.0")
32+
self.geometry(f"{1080}x{560}")
3033
self.iconbitmap(resource_path("factorio_downloader.ico"))
3134

32-
self.frame_0 = customtkinter.CTkFrame(master=self)
33-
self.frame_0.pack(expand=True, pady=10, padx=10)
34-
self.frame_0.grid_rowconfigure(0, weight=1)
35-
self.frame_0.rowconfigure(4, weight=1)
35+
self.grid_columnconfigure((0, 1), weight=1)
36+
self.grid_rowconfigure(0, weight=1)
37+
38+
self.DownloaderFrame = DownloaderFrame(self, "downloads")
39+
self.DownloaderFrame.grid(row=0, column=1, padx=(0, 10), pady=10, sticky="nsew")
40+
41+
self.BodyFrame = BodyFrame(self, self.DownloaderFrame)
42+
self.BodyFrame.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
43+
44+
45+
46+
class DownloaderFrame(customtkinter.CTkScrollableFrame):
47+
def __init__(self, master, title):
48+
super().__init__(master, label_text=title, height=100, width=300)
49+
self.grid_columnconfigure(0, weight=1)
50+
self.grid_rowconfigure(0, weight=1)
51+
self.frames = []
52+
# Main container frame for added frames
53+
self.container = customtkinter.CTkFrame(self)
54+
self.container.pack(padx=10, pady=10)
55+
56+
def _setup_downloads_frame(self, label):
57+
"""Setup progress tracking section"""
58+
downloads_frame = customtkinter.CTkFrame(master=self.container)
59+
# downloads_frame.grid(row=2, column=0, padx=10, pady=(0, 10), sticky="nsew")
60+
61+
progress_file = customtkinter.CTkLabel(
62+
master=downloads_frame,
63+
text=f"{label}",
64+
font=customtkinter.CTkFont(family="Tahoma"),
65+
text_color=("grey74", "grey60"),
66+
wraplength=250,
67+
)
68+
progress_file.pack(side="top", anchor="w", padx=12, pady=(2,0))
69+
70+
progress_bar = customtkinter.CTkProgressBar(
71+
downloads_frame,
72+
orientation="horizontal",
73+
width=660,
74+
mode="determinate",
75+
)
76+
progress_bar.pack(side="top", fill="x", padx=12, pady=(6,10), anchor="w")
3677

37-
def select_path():
38-
output_path = customtkinter.filedialog.askdirectory()
39-
if output_path is not None and output_path != "":
40-
self.download_path.delete(0, END)
41-
self.download_path.insert(0, output_path)
78+
return downloads_frame, progress_file, progress_bar
4279

43-
def callback(url):
44-
webbrowser.open_new(url)
80+
def add_download(self, label):
81+
# Create a new frame with a label and a button (for demonstration)
82+
frame, label_widget, progress_bar = self._setup_downloads_frame(label)
83+
frame.pack(fill="x", pady=5)
84+
# Store reference for further logic if needed
85+
entry = DownloadEntry(frame, label_widget, progress_bar)
86+
self.frames.append(entry)
87+
return entry
4588

46-
# Title Frame
89+
90+
class BodyFrame(customtkinter.CTkFrame):
91+
def __init__(self, master, downloader_frame):
92+
super().__init__(master)
93+
self.frame_0 = customtkinter.CTkFrame(master=self)
94+
self.frame_0.pack(expand=True, pady=10, padx=10)
95+
self.frame_0.grid_rowconfigure(0, weight=1)
96+
self.frame_0.rowconfigure(5, weight=1)
97+
self.downloader_frame = downloader_frame
98+
self._setup_ui()
99+
100+
def _setup_ui(self):
101+
"""Initialize UI components"""
102+
self._setup_title_frame()
103+
self._setup_body_frame()
104+
self._setup_downloads_frame()
105+
self._setup_textbox()
106+
107+
def _setup_title_frame(self):
108+
"""Setup title section"""
47109
self.title_frame = customtkinter.CTkFrame(master=self.frame_0)
48110
self.title_frame.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
49111
self.title_frame.grid_rowconfigure(0, weight=1)
@@ -63,8 +125,10 @@ def callback(url):
63125
text_color=("grey74", "grey60"),
64126
)
65127
self.title_sub_label.grid(row=1, padx=12, sticky="nsw")
128+
66129
github_repo = "https://github.com/vaibhavvikas/factorio-mod-downloader"
67130
github_url = f"Made with ♥ by Vaibhav Vikas, {github_repo}"
131+
68132
self.developer_label = customtkinter.CTkLabel(
69133
master=self.title_frame,
70134
text=github_url,
@@ -75,19 +139,13 @@ def callback(url):
75139
self.developer_label.grid(row=2, padx=12, sticky="nsw")
76140
self.developer_label.bind(
77141
"<Button-1>",
78-
lambda e: callback(
79-
"https://github.com/vaibhavvikas/factorio-mod-downloader"
80-
),
81-
)
82-
self.developer_link = Label(self, text="Hyperlink", fg="blue", cursor="hand2")
83-
self.developer_link.bind(
84-
"<Button-1>",
85-
lambda e: callback(
142+
lambda e: self._callback(
86143
"https://github.com/vaibhavvikas/factorio-mod-downloader"
87144
),
88145
)
89146

90-
# Body Frame
147+
def _setup_body_frame(self):
148+
"""Setup input controls section"""
91149
self.body_frame = customtkinter.CTkFrame(master=self.frame_0)
92150
self.body_frame.grid(row=1, column=0, padx=10, pady=(0, 10), sticky="nsew")
93151
self.body_frame.grid_rowconfigure(0, weight=1)
@@ -97,37 +155,33 @@ def callback(url):
97155
self.mod_url = customtkinter.CTkEntry(
98156
self.body_frame, placeholder_text="Mod Url", width=500
99157
)
100-
self.mod_url.grid(
101-
row=0, column=0, columnspan=4, padx=10, pady=10, sticky="nsew"
102-
)
158+
self.mod_url.grid(row=0, column=0, columnspan=4, padx=10, pady=10, sticky="nsew")
103159

104160
self.download_path = customtkinter.CTkEntry(
105161
self.body_frame, placeholder_text="Download Path", width=500
106162
)
107-
self.download_path.grid(
108-
row=1, column=0, columnspan=3, padx=10, pady=10, sticky="nsew"
109-
)
163+
self.download_path.grid(row=1, column=0, columnspan=3, padx=10, pady=10, sticky="nsew")
110164

111165
self.path_button = customtkinter.CTkButton(
112166
master=self.body_frame,
113167
border_width=2,
114168
fg_color="transparent",
115169
text_color=("gray10", "#DCE4EE"),
116170
text="Select Path",
117-
command=select_path,
171+
command=self._select_path,
118172
)
119173
self.path_button.grid(row=1, column=3, padx=10, pady=10, sticky="nsew")
120174

175+
121176
self.download_button = customtkinter.CTkButton(
122177
master=self.body_frame,
123178
text="Start Download",
124-
command=self.download_button_action,
125-
)
126-
self.download_button.grid(
127-
row=2, column=0, columnspan=4, padx=10, pady=10, sticky="nsew"
179+
command=self._download_button_action,
128180
)
181+
self.download_button.grid(row=2, column=0, columnspan=4, padx=10, pady=10, sticky="nsew")
129182

130-
# Download Status and Progress Frame
183+
def _setup_downloads_frame(self):
184+
"""Setup progress tracking section"""
131185
self.downloads_frame = customtkinter.CTkFrame(master=self.frame_0)
132186
self.downloads_frame.grid(row=2, column=0, padx=10, pady=(0, 10), sticky="nsew")
133187

@@ -146,43 +200,52 @@ def callback(url):
146200
mode="indeterminate",
147201
indeterminate_speed=1,
148202
)
149-
self.progressbar.grid(
150-
row=1, column=0, padx=(10, 10), pady=(10, 10), sticky="ns"
151-
)
203+
self.progressbar.grid(row=1, column=0, padx=(10, 10), pady=(10, 10), sticky="ns")
152204
self.progressbar.start()
153205

154-
# Logs Frame
206+
def _setup_textbox(self):
207+
"""Setup logs section"""
155208
self.textbox = customtkinter.CTkTextbox(
156209
master=self.frame_0,
157210
border_width=0,
158211
width=680,
159212
font=customtkinter.CTkFont(family="Tahoma"),
160213
)
161214
self.textbox.grid(row=3, column=0, padx=10, pady=(0, 10), sticky="nsew")
162-
self.textbox.insert("0.0", "Factorio Mod Downloader v0.2.2:\n")
215+
self.textbox.insert("0.0", "Factorio Mod Downloader v0.3.0:\n")
163216
self.textbox.yview(END)
164217
self.textbox.configure(state="disabled")
165218

166-
def download_button_action(self):
167-
mod_url = self.mod_url.get()
168-
mod_url = mod_url.strip()
219+
def _select_path(self):
220+
"""Handle path selection"""
221+
output_path = customtkinter.filedialog.askdirectory()
222+
if output_path and output_path != "":
223+
self.download_path.delete(0, END)
224+
self.download_path.insert(0, output_path)
225+
226+
227+
def _open_path(self):
228+
"""Handle path open in explorer"""
229+
output_path = customtkinter.filedialog.opendirectory()
169230

170-
download_path = self.download_path.get()
171-
download_path = download_path.strip()
231+
def _callback(self, url):
232+
"""Open URL in browser"""
233+
webbrowser.open_new(url)
172234

173-
if not mod_url or (
174-
mod_url
175-
and re.match(r"^https://mods\.factorio\.com/mod/.*", mod_url.strip())
176-
is None
177-
):
235+
def _validate_inputs(self) -> bool:
236+
"""Validate user inputs"""
237+
mod_url = self.mod_url.get().strip()
238+
download_path = self.download_path.get().strip()
239+
240+
if not mod_url or not re.match(r"^https://mods\.factorio\.com/mod/.*", mod_url):
178241
CTkMessagebox(
179242
title="Error",
180243
width=500,
181244
wraplength=500,
182245
message="Please provide a valid mod_url!!!",
183246
icon="cancel",
184247
)
185-
return
248+
return False
186249

187250
if not download_path:
188251
CTkMessagebox(
@@ -191,40 +254,46 @@ def download_button_action(self):
191254
message="Please provide a valid download_path!!!",
192255
icon="cancel",
193256
)
194-
return
257+
return False
195258

196-
self.download_button.configure(state="disabled", text="Download Started")
197-
download_path = f"{download_path}/mods"
198259
output = Path(download_path).expanduser().resolve()
199260

200261
if output.exists() and not output.is_dir():
201262
CTkMessagebox(
202263
title="Error",
203264
width=500,
204265
wraplength=500,
205-
message=f"{output} already exists and is not a directory.\n"
206-
"Enter a valid output directory.",
266+
message=f"{output} already exists and is not a directory.\nEnter a valid output directory.",
267+
icon="cancel",
207268
)
208-
self.download_button.configure(state="normal", text="Start Download")
209-
return
269+
return False
210270

211271
if output.exists() and output.is_dir() and tuple(output.glob("*")):
212272
response = CTkMessagebox(
213273
title="Continue?",
214274
width=500,
215275
wraplength=500,
216-
message=f"Directory {output} is not empty.\n"
217-
"Do you want to continue and overwrite?",
276+
message=f"Directory {output} is not empty.\nDo you want to continue and overwrite?",
218277
icon="warning",
219278
option_1="Cancel",
220279
option_2="Yes",
221280
)
281+
if not response or response.get() != "Yes":
282+
return False
222283

223-
if not response or (response and response.get() != "Yes"):
224-
self.download_button.configure(state="normal", text="Start Download")
225-
return
284+
return True
285+
286+
def _download_button_action(self):
287+
"""Handle download button click"""
288+
if not self._validate_inputs():
289+
return
290+
291+
self.download_button.configure(state="disabled", text="Download Started")
292+
download_path = self.download_path.get().strip()
293+
mod_url = self.mod_url.get().strip()
226294

227295
os.makedirs(download_path, exist_ok=True)
296+
228297
try:
229298
mod_downloader = ModDownloader(mod_url, download_path, self)
230299
mod_downloader.start()
@@ -233,15 +302,14 @@ def download_button_action(self):
233302
title="Error",
234303
width=500,
235304
wraplength=500,
236-
message=f"Unknown error occured.\n{str(e).split("\n")[0]}",
305+
message=f"Unknown error occurred.\n{str(e).split(chr(10))[0]}",
306+
icon="cancel",
237307
)
238-
return
239-
308+
self.download_button.configure(state="normal", text="Start Download")
240309

241310
def main():
242311
app = App()
243312
app.mainloop()
244313

245-
246314
if __name__ == "__main__":
247315
main()

0 commit comments

Comments
 (0)