htm-engine 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- htm_engine-1.0.0/PKG-INFO +11 -0
- htm_engine-1.0.0/README.md +0 -0
- htm_engine-1.0.0/htm_engine.egg-info/PKG-INFO +11 -0
- htm_engine-1.0.0/htm_engine.egg-info/SOURCES.txt +12 -0
- htm_engine-1.0.0/htm_engine.egg-info/dependency_links.txt +1 -0
- htm_engine-1.0.0/htm_engine.egg-info/entry_points.txt +2 -0
- htm_engine-1.0.0/htm_engine.egg-info/requires.txt +3 -0
- htm_engine-1.0.0/htm_engine.egg-info/top_level.txt +1 -0
- htm_engine-1.0.0/htmengine/__init__.py +1 -0
- htm_engine-1.0.0/htmengine/__main__.py +4 -0
- htm_engine-1.0.0/htmengine/mainapp.py +375 -0
- htm_engine-1.0.0/pyproject.toml +18 -0
- htm_engine-1.0.0/setup.cfg +4 -0
- htm_engine-1.0.0/setup.py +18 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: htm-engine
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Advanced HTML to EXE packaging suite
|
|
5
|
+
Author: YAVUX STUDIOS
|
|
6
|
+
Requires-Python: >=3.7
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: pywebview
|
|
9
|
+
Requires-Dist: requests
|
|
10
|
+
Requires-Dist: pyinstaller
|
|
11
|
+
Dynamic: author
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: htm-engine
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Advanced HTML to EXE packaging suite
|
|
5
|
+
Author: YAVUX STUDIOS
|
|
6
|
+
Requires-Python: >=3.7
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: pywebview
|
|
9
|
+
Requires-Dist: requests
|
|
10
|
+
Requires-Dist: pyinstaller
|
|
11
|
+
Dynamic: author
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.py
|
|
4
|
+
htm_engine.egg-info/PKG-INFO
|
|
5
|
+
htm_engine.egg-info/SOURCES.txt
|
|
6
|
+
htm_engine.egg-info/dependency_links.txt
|
|
7
|
+
htm_engine.egg-info/entry_points.txt
|
|
8
|
+
htm_engine.egg-info/requires.txt
|
|
9
|
+
htm_engine.egg-info/top_level.txt
|
|
10
|
+
htmengine/__init__.py
|
|
11
|
+
htmengine/__main__.py
|
|
12
|
+
htmengine/mainapp.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
htmengine
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import subprocess
|
|
4
|
+
import threading
|
|
5
|
+
import json
|
|
6
|
+
import tkinter as tk
|
|
7
|
+
from tkinter import filedialog, messagebox, ttk
|
|
8
|
+
import re
|
|
9
|
+
import requests
|
|
10
|
+
import time
|
|
11
|
+
from urllib.parse import urljoin, urlparse
|
|
12
|
+
|
|
13
|
+
def get_path(rel):
|
|
14
|
+
if hasattr(sys, '_MEIPASS'):
|
|
15
|
+
return os.path.join(sys._MEIPASS, rel)
|
|
16
|
+
return os.path.join(os.path.abspath("."), rel)
|
|
17
|
+
|
|
18
|
+
class PackerGUI:
|
|
19
|
+
def __init__(self, root):
|
|
20
|
+
self.root = root
|
|
21
|
+
self.root.title("Htm Engine - Advanced Packaging Center")
|
|
22
|
+
self.root.geometry("700x950")
|
|
23
|
+
self.root.configure(bg="#0f0f0f")
|
|
24
|
+
|
|
25
|
+
# --- Variables ---
|
|
26
|
+
self.exe_name = tk.StringVar(value="HtmApp")
|
|
27
|
+
self.app_title = tk.StringVar(value="New Htm Engine Project")
|
|
28
|
+
self.src_dir = tk.StringVar(value="src")
|
|
29
|
+
self.icon_path = tk.StringVar()
|
|
30
|
+
|
|
31
|
+
self.version = tk.StringVar(value="1.0.0.0")
|
|
32
|
+
self.company_name = tk.StringVar(value="Htm Engine")
|
|
33
|
+
self.copyright = tk.StringVar(value="© 2024 Htm Engine")
|
|
34
|
+
|
|
35
|
+
self.screen_mode = tk.StringVar(value="resizable")
|
|
36
|
+
self.width = tk.StringVar(value="1280")
|
|
37
|
+
self.height = tk.StringVar(value="720")
|
|
38
|
+
self.topmost = tk.BooleanVar(value=False)
|
|
39
|
+
self.disable_right_click = tk.BooleanVar(value=True)
|
|
40
|
+
|
|
41
|
+
# --- Splash Screen Variables ---
|
|
42
|
+
self.use_splash = tk.BooleanVar(value=False)
|
|
43
|
+
self.splash_path = tk.StringVar()
|
|
44
|
+
self.splash_time = tk.StringVar(value="3") # Seconds
|
|
45
|
+
|
|
46
|
+
self.open_folder = tk.BooleanVar(value=True)
|
|
47
|
+
self.test_after_build = tk.BooleanVar(value=False)
|
|
48
|
+
|
|
49
|
+
self.create_widgets()
|
|
50
|
+
|
|
51
|
+
def create_widgets(self):
|
|
52
|
+
tk.Label(self.root, text="🛠️ HTM ENGINE PACKER", font=("Impact", 26), fg="#00ffcc", bg="#0f0f0f").pack(pady=10)
|
|
53
|
+
|
|
54
|
+
main_canvas = tk.Canvas(self.root, bg="#0f0f0f", highlightthickness=0)
|
|
55
|
+
scrollbar = ttk.Scrollbar(self.root, orient="vertical", command=main_canvas.yview)
|
|
56
|
+
self.scrollable_frame = tk.Frame(main_canvas, bg="#0f0f0f")
|
|
57
|
+
|
|
58
|
+
self.scrollable_frame.bind(
|
|
59
|
+
"<Configure>",
|
|
60
|
+
lambda e: main_canvas.configure(scrollregion=main_canvas.bbox("all"))
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
main_canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
|
|
64
|
+
main_canvas.configure(yscrollcommand=scrollbar.set)
|
|
65
|
+
|
|
66
|
+
main_canvas.pack(side="left", fill="both", expand=True, padx=20)
|
|
67
|
+
scrollbar.pack(side="right", fill="y")
|
|
68
|
+
|
|
69
|
+
# --- Section 1: Project Essentials ---
|
|
70
|
+
section1 = tk.LabelFrame(self.scrollable_frame, text=" Project Essentials ", fg="#00ffcc", bg="#0f0f0f", padx=10, pady=10)
|
|
71
|
+
section1.pack(fill="x", pady=5)
|
|
72
|
+
|
|
73
|
+
tk.Label(section1, text="Source Folder:", fg="#aaa", bg="#0f0f0f").grid(row=0, column=0, sticky="w")
|
|
74
|
+
tk.Entry(section1, textvariable=self.src_dir, bg="#1a1a1a", fg="white", width=35).grid(row=0, column=1, pady=5)
|
|
75
|
+
tk.Button(section1, text="Browse", command=self.select_src, bg="#333", fg="white").grid(row=0, column=2, padx=5)
|
|
76
|
+
|
|
77
|
+
tk.Label(section1, text="EXE Name:", fg="#aaa", bg="#0f0f0f").grid(row=1, column=0, sticky="w")
|
|
78
|
+
tk.Entry(section1, textvariable=self.exe_name, bg="#1a1a1a", fg="white", width=35).grid(row=1, column=1, pady=5)
|
|
79
|
+
|
|
80
|
+
tk.Label(section1, text="Game Title:", fg="#aaa", bg="#0f0f0f").grid(row=2, column=0, sticky="w")
|
|
81
|
+
tk.Entry(section1, textvariable=self.app_title, bg="#1a1a1a", fg="#00ff00", width=35).grid(row=2, column=1, pady=5)
|
|
82
|
+
|
|
83
|
+
# --- Section: Metadata ---
|
|
84
|
+
section_meta = tk.LabelFrame(self.scrollable_frame, text=" Metadata (EXE Details) ", fg="#00ffcc", bg="#0f0f0f", padx=10, pady=10)
|
|
85
|
+
section_meta.pack(fill="x", pady=5)
|
|
86
|
+
|
|
87
|
+
tk.Label(section_meta, text="Version (Ex: 1.0.0.0):", fg="#aaa", bg="#0f0f0f").grid(row=0, column=0, sticky="w")
|
|
88
|
+
tk.Entry(section_meta, textvariable=self.version, bg="#1a1a1a", fg="white").grid(row=0, column=1, sticky="w", pady=2)
|
|
89
|
+
|
|
90
|
+
tk.Label(section_meta, text="Company:", fg="#aaa", bg="#0f0f0f").grid(row=1, column=0, sticky="w")
|
|
91
|
+
tk.Entry(section_meta, textvariable=self.company_name, bg="#1a1a1a", fg="white").grid(row=1, column=1, sticky="w", pady=2)
|
|
92
|
+
|
|
93
|
+
tk.Label(section_meta, text="Copyright:", fg="#aaa", bg="#0f0f0f").grid(row=2, column=0, sticky="w")
|
|
94
|
+
tk.Entry(section_meta, textvariable=self.copyright, bg="#1a1a1a", fg="white").grid(row=2, column=1, sticky="w", pady=2)
|
|
95
|
+
|
|
96
|
+
# --- Section 2: Screen & Interface ---
|
|
97
|
+
section2 = tk.LabelFrame(self.scrollable_frame, text=" Display & Interface ", fg="#00ffcc", bg="#0f0f0f", padx=10, pady=10)
|
|
98
|
+
section2.pack(fill="x", pady=5)
|
|
99
|
+
|
|
100
|
+
modes = [("Fullscreen", "full"), ("Resizable", "resizable"), ("Fixed", "fixed")]
|
|
101
|
+
for i, (text, mode) in enumerate(modes):
|
|
102
|
+
tk.Radiobutton(section2, text=text, variable=self.screen_mode, value=mode, bg="#0f0f0f", fg="white", selectcolor="#444").grid(row=0, column=i, padx=5)
|
|
103
|
+
|
|
104
|
+
size_frame = tk.Frame(section2, bg="#0f0f0f")
|
|
105
|
+
size_frame.grid(row=1, column=0, columnspan=3, pady=10)
|
|
106
|
+
tk.Label(size_frame, text="Width:", fg="#888", bg="#0f0f0f").pack(side="left")
|
|
107
|
+
tk.Entry(size_frame, textvariable=self.width, width=6, bg="#1a1a1a", fg="white").pack(side="left", padx=5)
|
|
108
|
+
tk.Label(size_frame, text="Height:", fg="#888", bg="#0f0f0f").pack(side="left", padx=(10,0))
|
|
109
|
+
tk.Entry(size_frame, textvariable=self.height, width=6, bg="#1a1a1a", fg="white").pack(side="left", padx=5)
|
|
110
|
+
|
|
111
|
+
tk.Checkbutton(section2, text="Always on Top", variable=self.topmost, bg="#0f0f0f", fg="#aaa", selectcolor="#222").grid(row=2, column=0)
|
|
112
|
+
tk.Checkbutton(section2, text="Disable Right Click", variable=self.disable_right_click, bg="#0f0f0f", fg="#aaa", selectcolor="#222").grid(row=2, column=1)
|
|
113
|
+
|
|
114
|
+
# Splash Screen Settings
|
|
115
|
+
splash_frame = tk.LabelFrame(section2, text=" Splash Screen (Loading) ", fg="#ffa500", bg="#0f0f0f", padx=5, pady=5)
|
|
116
|
+
splash_frame.grid(row=3, column=0, columnspan=3, pady=10, sticky="ew")
|
|
117
|
+
|
|
118
|
+
tk.Checkbutton(splash_frame, text="Enable Splash", variable=self.use_splash, bg="#0f0f0f", fg="white", selectcolor="#222").grid(row=0, column=0, sticky="w")
|
|
119
|
+
tk.Button(splash_frame, text="Select Image", command=self.select_splash, bg="#333", fg="white", font=("Arial", 8)).grid(row=0, column=1, padx=5)
|
|
120
|
+
tk.Label(splash_frame, text="Duration(s):", fg="#aaa", bg="#0f0f0f").grid(row=0, column=2)
|
|
121
|
+
tk.Entry(splash_frame, textvariable=self.splash_time, width=3, bg="#1a1a1a", fg="white").grid(row=0, column=3, padx=5)
|
|
122
|
+
|
|
123
|
+
# --- Section 3: Build & Actions ---
|
|
124
|
+
section3 = tk.LabelFrame(self.scrollable_frame, text=" Build & Operations ", fg="#00ffcc", bg="#0f0f0f", padx=10, pady=10)
|
|
125
|
+
section3.pack(fill="x", pady=5)
|
|
126
|
+
|
|
127
|
+
tk.Checkbutton(section3, text="Open folder when finished", variable=self.open_folder, bg="#0f0f0f", fg="#aaa", selectcolor="#222").pack(anchor="w")
|
|
128
|
+
tk.Checkbutton(section3, text="Start test when finished", variable=self.test_after_build, bg="#0f0f0f", fg="#aaa", selectcolor="#222").pack(anchor="w")
|
|
129
|
+
|
|
130
|
+
btn_frame = tk.Frame(section3, bg="#0f0f0f")
|
|
131
|
+
btn_frame.pack(fill="x", pady=10)
|
|
132
|
+
tk.Button(btn_frame, text="Select Icon (.ico)", command=self.select_icon, bg="#333", fg="white").pack(side="left", fill="x", expand=True)
|
|
133
|
+
self.btn_build = tk.Button(btn_frame, text="🔥 COMPILE PROJECT (OFFLINE) 🔥", bg="#00ffcc", fg="black", font=("Arial", 12, "bold"), command=self.run_thread)
|
|
134
|
+
self.btn_build.pack(side="left", fill="x", expand=True, padx=5)
|
|
135
|
+
|
|
136
|
+
self.log_area = tk.Text(self.scrollable_frame, height=8, bg="black", fg="#00ff00", font=("Consolas", 9))
|
|
137
|
+
self.log_area.pack(fill="x", pady=5)
|
|
138
|
+
|
|
139
|
+
def select_src(self):
|
|
140
|
+
path = filedialog.askdirectory()
|
|
141
|
+
if path: self.src_dir.set(path)
|
|
142
|
+
|
|
143
|
+
def select_icon(self):
|
|
144
|
+
path = filedialog.askopenfilename(filetypes=[("Icon", "*.ico")])
|
|
145
|
+
if path: self.icon_path.set(path)
|
|
146
|
+
|
|
147
|
+
def select_splash(self):
|
|
148
|
+
path = filedialog.askopenfilename(filetypes=[("Image", "*.png *.jpg *.jpeg *.gif")])
|
|
149
|
+
if path: self.splash_path.set(path)
|
|
150
|
+
|
|
151
|
+
def log(self, msg):
|
|
152
|
+
self.log_area.insert("end", f">>> {msg}\n")
|
|
153
|
+
self.log_area.see("end")
|
|
154
|
+
|
|
155
|
+
def run_thread(self):
|
|
156
|
+
self.btn_build.config(state="disabled")
|
|
157
|
+
threading.Thread(target=self.start_build, daemon=True).start()
|
|
158
|
+
|
|
159
|
+
def make_assets_offline(self, src_dir):
|
|
160
|
+
index_path = os.path.join(src_dir, "index.html")
|
|
161
|
+
if not os.path.exists(index_path): return
|
|
162
|
+
libs_dir = os.path.join(src_dir, "offline_libs")
|
|
163
|
+
if not os.path.exists(libs_dir): os.makedirs(libs_dir)
|
|
164
|
+
with open(index_path, "r", encoding="utf-8") as f:
|
|
165
|
+
content = f.read()
|
|
166
|
+
urls = re.findall(r'src=["\'](http[s]?://.*?)["\']|href=["\'](http[s]?://.*?)["\']', content)
|
|
167
|
+
for src_url, href_url in urls:
|
|
168
|
+
url = src_url if src_url else href_url
|
|
169
|
+
if not url: continue
|
|
170
|
+
try:
|
|
171
|
+
filename = os.path.basename(urlparse(url).path)
|
|
172
|
+
if not filename: filename = "lib_" + str(hash(url))
|
|
173
|
+
local_path = os.path.join(libs_dir, filename)
|
|
174
|
+
self.log(f"Downloading: {filename}")
|
|
175
|
+
response = requests.get(url, timeout=10)
|
|
176
|
+
if response.status_code == 200:
|
|
177
|
+
with open(local_path, "wb") as f:
|
|
178
|
+
f.write(response.content)
|
|
179
|
+
rel_path = "offline_libs/" + filename
|
|
180
|
+
content = content.replace(url, rel_path)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
self.log(f"Error (Download): {url} -> {e}")
|
|
183
|
+
with open(index_path, "w", encoding="utf-8") as f:
|
|
184
|
+
f.write(content)
|
|
185
|
+
self.log("All dependencies localized (Offline Mode).")
|
|
186
|
+
|
|
187
|
+
def create_version_file(self):
|
|
188
|
+
raw_version = self.version.get()
|
|
189
|
+
numbers = re.findall(r'\d+', raw_version)
|
|
190
|
+
while len(numbers) < 4: numbers.append('0')
|
|
191
|
+
ver_tuple = f"({','.join(numbers[:4])})"
|
|
192
|
+
content = f"""
|
|
193
|
+
VSVersionInfo(
|
|
194
|
+
ffi=FixedFileInfo(filevers={ver_tuple}, prodvers={ver_tuple}, mask=0x3f, flags=0x0, OS=0x40004, fileType=0x1, subtype=0x0, date=(0, 0)),
|
|
195
|
+
kids=[
|
|
196
|
+
StringFileInfo([
|
|
197
|
+
StringTable(u'040904B0',
|
|
198
|
+
[StringStruct(u'CompanyName', u'{self.company_name.get()}'),
|
|
199
|
+
StringStruct(u'FileDescription', u'{self.app_title.get()}'),
|
|
200
|
+
StringStruct(u'FileVersion', u'{raw_version}'),
|
|
201
|
+
StringStruct(u'InternalName', u'HtmEngine'),
|
|
202
|
+
StringStruct(u'LegalCopyright', u'{self.copyright.get()}'),
|
|
203
|
+
StringStruct(u'OriginalFilename', u'{self.exe_name.get()}.exe'),
|
|
204
|
+
StringStruct(u'ProductName', u'{self.app_title.get()}'),
|
|
205
|
+
StringStruct(u'ProductVersion', u'{raw_version}')])
|
|
206
|
+
]), VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
|
|
207
|
+
]
|
|
208
|
+
)"""
|
|
209
|
+
with open("version_info.txt", "w", encoding="utf-8") as f:
|
|
210
|
+
f.write(content)
|
|
211
|
+
|
|
212
|
+
def start_build(self):
|
|
213
|
+
try:
|
|
214
|
+
src = self.src_dir.get()
|
|
215
|
+
if not os.path.exists(os.path.join(src, "index.html")):
|
|
216
|
+
messagebox.showwarning("Warning", "index.html not found!")
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
self.log("Preparing offline assets...")
|
|
220
|
+
self.make_assets_offline(src)
|
|
221
|
+
|
|
222
|
+
splash_filename = ""
|
|
223
|
+
if self.use_splash.get() and self.splash_path.get():
|
|
224
|
+
import shutil
|
|
225
|
+
ext = os.path.splitext(self.splash_path.get())[1]
|
|
226
|
+
splash_filename = "splash" + ext
|
|
227
|
+
shutil.copy2(self.splash_path.get(), os.path.join(src, splash_filename))
|
|
228
|
+
|
|
229
|
+
config = {
|
|
230
|
+
"title": self.app_title.get(),
|
|
231
|
+
"mode": self.screen_mode.get(),
|
|
232
|
+
"width": int(self.width.get()),
|
|
233
|
+
"height": int(self.height.get()),
|
|
234
|
+
"topmost": self.topmost.get(),
|
|
235
|
+
"no_right_click": self.disable_right_click.get(),
|
|
236
|
+
"use_splash": self.use_splash.get(),
|
|
237
|
+
"splash_img": splash_filename,
|
|
238
|
+
"splash_time": int(self.splash_time.get())
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
with open(os.path.join(src, "config.json"), "w", encoding="utf-8") as f:
|
|
242
|
+
json.dump(config, f)
|
|
243
|
+
|
|
244
|
+
self.create_version_file()
|
|
245
|
+
self.log("Build process started...")
|
|
246
|
+
|
|
247
|
+
sep = ';' if os.name == 'nt' else ':'
|
|
248
|
+
cmd = ["pyinstaller", "--noconsole", "--onefile", "--clean",
|
|
249
|
+
f"--add-data={src}{sep}.",
|
|
250
|
+
"--name", self.exe_name.get(),
|
|
251
|
+
"--version-file", "version_info.txt"]
|
|
252
|
+
|
|
253
|
+
if self.icon_path.get(): cmd.extend(["--icon", self.icon_path.get()])
|
|
254
|
+
cmd.append(sys.argv[0])
|
|
255
|
+
|
|
256
|
+
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
|
257
|
+
for line in proc.stdout:
|
|
258
|
+
self.log(line.strip())
|
|
259
|
+
self.root.update_idletasks()
|
|
260
|
+
|
|
261
|
+
proc.wait()
|
|
262
|
+
|
|
263
|
+
if proc.returncode == 0:
|
|
264
|
+
self.log("✅ Build completed successfully!")
|
|
265
|
+
if self.open_folder.get(): os.startfile("dist")
|
|
266
|
+
if self.test_after_build.get():
|
|
267
|
+
subprocess.Popen([os.path.join("dist", f"{self.exe_name.get()}.exe")])
|
|
268
|
+
messagebox.showinfo("Htm Engine", "Packaging Successful!")
|
|
269
|
+
else:
|
|
270
|
+
self.log("❌ Compilation error!")
|
|
271
|
+
|
|
272
|
+
except Exception as e:
|
|
273
|
+
self.log(f"ERROR: {str(e)}")
|
|
274
|
+
finally:
|
|
275
|
+
self.btn_build.config(state="normal")
|
|
276
|
+
|
|
277
|
+
if __name__ == "__main__":
|
|
278
|
+
if hasattr(sys, '_MEIPASS'):
|
|
279
|
+
import webview
|
|
280
|
+
# --- TÜM SİSTEMİ KAPATAN FONKSİYON ---
|
|
281
|
+
def kill_everything():
|
|
282
|
+
print("System shutting down...")
|
|
283
|
+
os._exit(0) # Bu komut tüm threadleri ve ana süreci anında öldürür.
|
|
284
|
+
|
|
285
|
+
try:
|
|
286
|
+
conf_path = get_path("config.json")
|
|
287
|
+
index_path = get_path("index.html")
|
|
288
|
+
|
|
289
|
+
if not os.path.exists(conf_path) or not os.path.exists(index_path):
|
|
290
|
+
conf_path = get_path(os.path.join("src", "config.json"))
|
|
291
|
+
index_path = get_path(os.path.join("src", "index.html"))
|
|
292
|
+
|
|
293
|
+
with open(conf_path, "r", encoding="utf-8") as f:
|
|
294
|
+
c = json.load(f)
|
|
295
|
+
|
|
296
|
+
index_url = "file:///" + os.path.abspath(index_path).replace("\\", "/")
|
|
297
|
+
|
|
298
|
+
if c.get("use_splash") and c.get("splash_img"):
|
|
299
|
+
splash_img_path = get_path(c["splash_img"])
|
|
300
|
+
if os.path.exists(splash_img_path):
|
|
301
|
+
splash_html = f"""
|
|
302
|
+
<html>
|
|
303
|
+
<body style="margin:0; padding:0; overflow:hidden; background-color:black; display:flex; align-items:center; justify-content:center; height:100vh;">
|
|
304
|
+
<img src="file:///{os.path.abspath(splash_img_path).replace('\\', '/')}" style="max-width:100%; max-height:100%; object-fit:contain;">
|
|
305
|
+
</body>
|
|
306
|
+
</html>
|
|
307
|
+
"""
|
|
308
|
+
splash_window = webview.create_window(
|
|
309
|
+
"Loading...",
|
|
310
|
+
html=splash_html,
|
|
311
|
+
width=c.get("width", 1280),
|
|
312
|
+
height=c.get("height", 720),
|
|
313
|
+
frameless=True,
|
|
314
|
+
on_top=True
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
def close_splash(sw, main_conf, main_url):
|
|
318
|
+
time.sleep(main_conf.get("splash_time", 3))
|
|
319
|
+
main_window = webview.create_window(
|
|
320
|
+
main_conf["title"],
|
|
321
|
+
url=main_url,
|
|
322
|
+
width=main_conf.get("width", 1280),
|
|
323
|
+
height=main_conf.get("height", 720),
|
|
324
|
+
fullscreen=(main_conf.get("mode") == "full"),
|
|
325
|
+
resizable=(main_conf.get("mode") == "resizable"),
|
|
326
|
+
on_top=main_conf.get("topmost", False)
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
# Pencere kapandığında kill_everything'i çağır
|
|
330
|
+
main_window.events.closed += kill_everything
|
|
331
|
+
|
|
332
|
+
if main_conf.get("no_right_click", False):
|
|
333
|
+
main_window.evaluate_js("document.addEventListener('contextmenu', e => e.preventDefault());")
|
|
334
|
+
|
|
335
|
+
sw.destroy()
|
|
336
|
+
|
|
337
|
+
threading.Thread(target=close_splash, args=(splash_window, c, index_url), daemon=True).start()
|
|
338
|
+
webview.start()
|
|
339
|
+
kill_everything() # webview döngüsü kırılırsa (pencere kapanırsa)
|
|
340
|
+
sys.exit()
|
|
341
|
+
|
|
342
|
+
# Splash yoksa normal başla
|
|
343
|
+
window = webview.create_window(
|
|
344
|
+
c["title"],
|
|
345
|
+
url=index_url,
|
|
346
|
+
width=c.get("width", 1280),
|
|
347
|
+
height=c.get("height", 720),
|
|
348
|
+
fullscreen=(c.get("mode") == "full"),
|
|
349
|
+
resizable=(c.get("mode") == "resizable"),
|
|
350
|
+
on_top=c.get("topmost", False)
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
window.events.closed += kill_everything
|
|
354
|
+
|
|
355
|
+
def disable_click(w):
|
|
356
|
+
if c.get("no_right_click", False):
|
|
357
|
+
w.evaluate_js("document.addEventListener('contextmenu', e => e.preventDefault());")
|
|
358
|
+
|
|
359
|
+
webview.start(disable_click, window)
|
|
360
|
+
kill_everything()
|
|
361
|
+
|
|
362
|
+
except Exception as e:
|
|
363
|
+
root = tk.Tk(); root.withdraw()
|
|
364
|
+
messagebox.showerror("Error", f"An error occurred:\n{str(e)}")
|
|
365
|
+
root.destroy()
|
|
366
|
+
kill_everything()
|
|
367
|
+
else:
|
|
368
|
+
root = tk.Tk()
|
|
369
|
+
app = PackerGUI(root)
|
|
370
|
+
root.mainloop()
|
|
371
|
+
|
|
372
|
+
def launch():
|
|
373
|
+
root = tk.Tk()
|
|
374
|
+
app = PackerGUI(root)
|
|
375
|
+
root.mainloop()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "htm-engine"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Advanced HTML to EXE packaging suite"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.7"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"pywebview",
|
|
13
|
+
"requests",
|
|
14
|
+
"pyinstaller"
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
htm-engine = "htm_engine.main:main_func" # Terminalden 'htm-engine' yazınca çalışması için
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="htmengine",
|
|
5
|
+
version="1.0.1",
|
|
6
|
+
author="YAVUX STUDIOS",
|
|
7
|
+
packages=find_packages(),
|
|
8
|
+
install_requires=[
|
|
9
|
+
"pyinstaller",
|
|
10
|
+
"pywebview",
|
|
11
|
+
"requests",
|
|
12
|
+
],
|
|
13
|
+
entry_points={
|
|
14
|
+
'console_scripts': [
|
|
15
|
+
'htmengine=htmengine.mainapp:launch', # htmengine yazınca launch() çalışır
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
)
|