44import threading
55import os
66import sys
7+ import locale
8+
9+ COMMAND_TIMEOUT = 300
710
811
912class BatRunnerApp :
@@ -16,15 +19,35 @@ def __init__(self, root):
1619 self .lines = []
1720 self .running = False
1821 self .current_row = - 1
22+ self .has_failure = False
23+ self .encoding = locale .getpreferredencoding (False ) or "utf-8"
1924 if getattr (sys , 'frozen' , False ):
2025 self .script_dir = os .path .dirname (sys .executable )
2126 else :
2227 self .script_dir = os .path .dirname (os .path .abspath (sys .argv [0 ]))
2328 self .inject_path = os .path .join (self .script_dir , "inject.txt" )
2429
2530 self ._build_ui ()
31+ self .root .protocol ("WM_DELETE_WINDOW" , self ._on_close )
2632 self .root .after (100 , self ._auto_load_and_run )
2733
34+ def _on_close (self ):
35+ self .running = False
36+ self ._safe_destroy ()
37+
38+ def _safe_after (self , delay , func , * args ):
39+ try :
40+ if self .root .winfo_exists ():
41+ self .root .after (delay , func , * args )
42+ except tk .TclError :
43+ pass
44+
45+ def _safe_destroy (self ):
46+ try :
47+ self .root .destroy ()
48+ except tk .TclError :
49+ pass
50+
2851 def _build_ui (self ):
2952 container = ttk .Frame (self .root )
3053 container .pack (fill = tk .BOTH , expand = True , padx = 5 , pady = 5 )
@@ -61,16 +84,26 @@ def _load_inject(self):
6184 self .status_var .set (f"未找到 inject.txt: { self .inject_path } " )
6285 return False
6386
64- with open (self .inject_path , "r" , encoding = "gbk" , errors = "replace" ) as f :
65- self .lines = f .readlines ()
87+ try :
88+ with open (self .inject_path , "r" , encoding = self .encoding , errors = "replace" ) as f :
89+ self .lines = f .readlines ()
90+ except OSError as e :
91+ self .status_var .set (f"读取失败: { e } " )
92+ return False
6693
6794 for item in self .tree .get_children ():
6895 self .tree .delete (item )
6996
7097 for i , line in enumerate (self .lines , 1 ):
7198 stripped = line .strip ()
72- if stripped and not stripped .startswith ("@" ) and not stripped .lower ().startswith ("rem" ):
73- self .tree .insert ("" , tk .END , iid = str (i ), values = ("⏳" , stripped ))
99+ if not stripped :
100+ continue
101+ if stripped .startswith ("@" ) or stripped .startswith ("::" ):
102+ continue
103+ first_word = stripped .split (None , 1 )[0 ].lower ()
104+ if first_word == "rem" :
105+ continue
106+ self .tree .insert ("" , tk .END , iid = str (i ), values = ("⏳" , stripped ))
74107
75108 self .progress ["value" ] = 0
76109 self .status_var .set (f"已加载 inject.txt,共 { len (self .lines )} 行" )
@@ -87,71 +120,91 @@ def _run(self):
87120 self .status_var .set ("inject.txt 为空或未加载" )
88121 return
89122
123+ items = self .tree .get_children ()
124+ if not items :
125+ self .status_var .set ("没有可执行的命令" )
126+ return
127+
128+ tasks = []
129+ for item_id in items :
130+ values = self .tree .item (item_id , "values" )
131+ tasks .append ((item_id , values [1 ]))
132+ self .tree .item (item_id , values = ("⏳" , * values [1 :]))
133+
90134 self .running = True
135+ self .has_failure = False
91136 self .current_row = - 1
92137 self ._set_output ("" )
93138
94- for item in self .tree .get_children ():
95- self .tree .item (item , values = (self .tree .item (item , "values" )[0 ].replace ("✅" , "⏳" ).replace ("❌" , "⏳" ), * self .tree .item (item , "values" )[1 :]))
96-
97- total = len (self .tree .get_children ())
139+ total = len (tasks )
98140 self .progress ["maximum" ] = total
99141 self .progress ["value" ] = 0
100142
101- threading .Thread (target = self ._execute , daemon = True ).start ()
143+ threading .Thread (target = self ._execute , args = ( tasks ,), daemon = True ).start ()
102144
103- def _execute (self ):
104- items = self .tree .get_children ()
105- total = len (items )
145+ def _execute (self , tasks ):
146+ total = len (tasks )
106147
107- for idx , item_id in enumerate (items ):
148+ for idx , ( item_id , command ) in enumerate (tasks ):
108149 if not self .running :
109150 break
110151
111- values = self .tree .item (item_id , "values" )
112- command = values [1 ]
113- self .root .after (0 , self ._highlight_row , item_id )
152+ self ._safe_after (0 , self ._highlight_row , item_id , command )
114153
115154 try :
116155 result = subprocess .run (
117156 command ,
118157 shell = True ,
119158 capture_output = True ,
120159 text = True ,
121- encoding = "gbk" ,
160+ encoding = self . encoding ,
122161 errors = "replace" ,
123- timeout = 60 ,
162+ timeout = COMMAND_TIMEOUT ,
124163 cwd = self .script_dir ,
125164 )
126165 success = result .returncode == 0
127- output = result .stdout + result .stderr
166+ output = ( result .stdout or "" ) + ( result .stderr or "" )
128167 except subprocess .TimeoutExpired :
129168 success = False
130- output = "执行超时(60秒 )"
169+ output = f "执行超时({ COMMAND_TIMEOUT } 秒 )"
131170 except Exception as e :
132171 success = False
133172 output = str (e )
134173
174+ if not success :
175+ self .has_failure = True
176+
135177 status_icon = "✅" if success else "❌"
136- self .root . after (0 , self ._update_row , item_id , status_icon , output )
137- self .root . after (0 , self ._update_progress , idx + 1 , total )
178+ self ._safe_after (0 , self ._update_row , item_id , command , status_icon , output )
179+ self ._safe_after (0 , self ._update_progress , idx + 1 , total )
138180
139181 self .running = False
140- self .root .after (0 , lambda : self .status_var .set ("执行完成,即将退出..." ))
141- self .root .after (1500 , self .root .destroy )
182+ self ._safe_after (0 , self ._finalize )
183+
184+ def _finalize (self ):
185+ if self .has_failure :
186+ self .status_var .set ("执行完成(含失败项),10 秒后退出" )
187+ self ._safe_after (10000 , self ._safe_destroy )
188+ else :
189+ self .status_var .set ("执行完成,即将退出..." )
190+ self ._safe_after (1500 , self ._safe_destroy )
142191
143- def _highlight_row (self , item_id ):
192+ def _highlight_row (self , item_id , command ):
193+ if not self .tree .exists (item_id ):
194+ return
144195 self .tree .selection_set (item_id )
145196 self .tree .see (item_id )
146197 values = self .tree .item (item_id , "values" )
147198 self .tree .item (item_id , values = ("▶" , * values [1 :]))
148- self .status_var .set (f"正在执行: { values [ 1 ] } " )
199+ self .status_var .set (f"正在执行: { command } " )
149200
150- def _update_row (self , item_id , status_icon , output ):
201+ def _update_row (self , item_id , command , status_icon , output ):
202+ if not self .tree .exists (item_id ):
203+ return
151204 values = self .tree .item (item_id , "values" )
152205 self .tree .item (item_id , values = (status_icon , * values [1 :]))
153206 if output .strip ():
154- self ._append_output (f"{ values [ 1 ] } \n { output .strip ()} \n { '─' * 40 } \n " )
207+ self ._append_output (f"{ command } \n { output .strip ()} \n { '─' * 40 } \n " )
155208
156209 def _update_progress (self , current , total ):
157210 self .progress ["value" ] = current
0 commit comments