-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathautoblog_launcher.py
More file actions
executable file
·341 lines (288 loc) · 11.1 KB
/
autoblog_launcher.py
File metadata and controls
executable file
·341 lines (288 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
#!/usr/bin/env python3
"""
AUTO-blogger Launcher with Auto-Update
Copyright © 2025 AryanVBW
GitHub: https://github.com/AryanVBW/AUTO-blogger
This launcher checks for updates before starting the application.
"""
import sys
import subprocess
import json
import urllib.request
import urllib.error
from pathlib import Path
import time
import tkinter as tk
from tkinter import messagebox, ttk
import threading
# Configuration
REPO_URL = "https://github.com/AryanVBW/AUTO-blogger.git"
API_URL = "https://api.github.com/repos/AryanVBW/AUTO-blogger"
APP_DIR = Path(__file__).parent.absolute()
# Virtual environment detection
def find_virtual_environment():
"""Find the virtual environment directory"""
project_root = Path(__file__).parent
# Look for virtual environment patterns
venv_patterns = [
'auto_blogger_venv_*',
'venv',
'.venv',
'env',
'.env'
]
for pattern in venv_patterns:
venv_dirs = list(project_root.glob(pattern))
for venv_dir in venv_dirs:
if venv_dir.is_dir():
# Check for activation script to confirm it's a valid venv
activate_script = venv_dir / 'bin' / 'activate'
if not activate_script.exists():
activate_script = venv_dir / 'Scripts' / 'activate.bat' # Windows
if activate_script.exists():
return venv_dir
return None
VENV_DIR = find_virtual_environment()
# If no virtual environment found, try to use system Python
if not VENV_DIR:
print("⚠️ Virtual environment not found, using system Python")
print("💡 For best results, run the installer to create a virtual environment")
class UpdateChecker:
def __init__(self):
self.root = None
self.progress_var = None
self.status_var = None
def show_update_dialog(self):
"""Show update progress dialog"""
self.root = tk.Tk()
self.root.title("AUTO-blogger Update")
self.root.geometry("400x200")
self.root.resizable(False, False)
# Center the window
self.root.eval('tk::PlaceWindow . center')
# Main frame
main_frame = ttk.Frame(self.root, padding="20")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Title
title_label = ttk.Label(
main_frame, text="AUTO-blogger", font=('Arial', 16, 'bold')
)
title_label.grid(row=0, column=0, columnspan=2, pady=(0, 10))
# Status
self.status_var = tk.StringVar(value="Checking for updates...")
status_label = ttk.Label(main_frame, textvariable=self.status_var)
status_label.grid(row=1, column=0, columnspan=2, pady=(0, 10))
# Progress bar
self.progress_var = tk.DoubleVar()
progress_bar = ttk.Progressbar(
main_frame, variable=self.progress_var, maximum=100
)
progress_bar.grid(
row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10)
)
# Configure grid weights
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(0, weight=1)
return self.root
def update_status(self, message, progress=None):
"""Update status message and progress"""
if self.status_var:
self.status_var.set(message)
if progress is not None and self.progress_var:
self.progress_var.set(progress)
if self.root:
self.root.update()
def close_dialog(self):
"""Close the update dialog"""
if self.root:
self.root.destroy()
def check_git_available(self):
"""Check if git is available"""
try:
subprocess.run(
['git', '--version'], capture_output=True, check=True
)
return True
except (subprocess.CalledProcessError, FileNotFoundError):
return False
def is_git_repo(self):
"""Check if current directory is a git repository"""
return (APP_DIR / '.git').exists()
def get_local_commit(self):
"""Get local commit hash"""
try:
result = subprocess.run(
['git', 'rev-parse', 'HEAD'],
cwd=APP_DIR,
capture_output=True,
text=True,
check=True
)
return result.stdout.strip()
except subprocess.CalledProcessError:
return None
def get_remote_commit(self):
"""Get remote commit hash from GitHub API"""
try:
with urllib.request.urlopen(
f"{API_URL}/commits/main"
) as response:
data = json.loads(response.read().decode())
return data['sha']
except (urllib.error.URLError, json.JSONDecodeError, KeyError):
try:
# Fallback to master branch
with urllib.request.urlopen(
f"{API_URL}/commits/master"
) as response:
data = json.loads(response.read().decode())
return data['sha']
except (urllib.error.URLError, json.JSONDecodeError, KeyError):
return None
def update_repository(self):
"""Update the repository"""
try:
self.update_status("Checking repository status...", 20)
# Check for uncommitted changes
result = subprocess.run(
['git', 'status', '--porcelain'],
cwd=APP_DIR, capture_output=True, text=True
)
if result.stdout.strip():
self.update_status("Stashing local changes...", 25)
subprocess.run(['git', 'stash'], cwd=APP_DIR, check=True)
self.update_status("Fetching updates...", 40)
subprocess.run(['git', 'fetch', 'origin'], cwd=APP_DIR, check=True)
self.update_status("Applying updates...", 70)
# Try main branch first, then master
try:
subprocess.run(
['git', 'pull', 'origin', 'main'], cwd=APP_DIR, check=True
)
except subprocess.CalledProcessError:
try:
subprocess.run(
['git', 'pull', 'origin', 'master'],
cwd=APP_DIR, check=True
)
except subprocess.CalledProcessError:
# Fallback to reset if pull fails
subprocess.run(
['git', 'reset', '--hard', 'origin/main'],
cwd=APP_DIR, check=True
)
self.update_status("Update completed!", 100)
return True
except subprocess.CalledProcessError as e:
self.update_status(f"Update failed: {str(e)}", 0)
return False
def check_for_updates(self):
"""Check for updates and update if necessary"""
# Show update dialog
dialog = self.show_update_dialog()
def update_thread():
try:
self.update_status("Initializing...", 10)
time.sleep(0.5)
# Check if git is available
if not self.check_git_available():
self.update_status(
"Git not available, skipping update check", 100
)
time.sleep(2)
self.close_dialog()
return
# Check if this is a git repository
if not self.is_git_repo():
self.update_status(
"Not a git repository, skipping update check", 100
)
time.sleep(2)
self.close_dialog()
return
self.update_status("Checking for updates...", 20)
# Get local and remote commits
local_commit = self.get_local_commit()
remote_commit = self.get_remote_commit()
if not local_commit or not remote_commit:
self.update_status("Could not check for updates", 100)
time.sleep(2)
self.close_dialog()
return
# Compare commits
if local_commit == remote_commit:
self.update_status("Application is up to date!", 100)
time.sleep(1.5)
self.close_dialog()
return
# Updates available
self.update_status("Updates available! Downloading...", 25)
if self.update_repository():
time.sleep(1)
self.close_dialog()
# Show success message
root = tk.Tk()
root.withdraw()
messagebox.showinfo(
"Update Complete",
"AUTO-blogger has been updated successfully!\n"
"The application will now start."
)
root.destroy()
else:
time.sleep(2)
self.close_dialog()
except Exception as e:
self.update_status(f"Error: {str(e)}", 0)
time.sleep(3)
self.close_dialog()
# Start update check in thread
thread = threading.Thread(target=update_thread)
thread.daemon = True
thread.start()
# Run dialog
dialog.mainloop()
def launch_app(self):
"""Launch the main application"""
try:
# Determine Python executable
if VENV_DIR:
if sys.platform == "win32":
python_exe = VENV_DIR / "Scripts" / "python.exe"
else:
python_exe = VENV_DIR / "bin" / "python"
# Check if virtual environment exists
if not python_exe.exists():
python_exe = sys.executable
else:
# Use system Python if no virtual environment
python_exe = sys.executable
# Launch the GUI
gui_script = APP_DIR / "gui_blogger.py"
if gui_script.exists():
subprocess.run([str(python_exe), str(gui_script)])
else:
# Fallback to launch_blogger.py
launch_script = APP_DIR / "launch_blogger.py"
if launch_script.exists():
subprocess.run([str(python_exe), str(launch_script)])
else:
raise FileNotFoundError("No launcher script found")
except Exception as e:
root = tk.Tk()
root.withdraw()
messagebox.showerror(
"Launch Error",
f"Failed to launch AUTO-blogger:\n{str(e)}"
)
root.destroy()
def main():
"""Main function"""
checker = UpdateChecker()
# Check for updates first
checker.check_for_updates()
# Launch the application
checker.launch_app()
if __name__ == "__main__":
main()