99import sys
1010import tkinter as tk
1111from datetime import datetime
12- from tkinter import messagebox
12+ from tkinter import ttk , filedialog , messagebox
1313
1414import pyperclip
1515from tqdm import tqdm
@@ -26,7 +26,7 @@ def get_latest_modification_time(path):
2626 # print(rst_path, end="")
2727 rst = rst_path
2828
29- time_path_dict = {}
29+ time_path_list = []
3030 # 遍历目标文件夹下的所有直接的文件和文件夹
3131 for entry in os .scandir (path ):
3232 modtime = get_timestamp (entry )
@@ -42,18 +42,19 @@ def get_latest_modification_time(path):
4242 # 比较子文件夹中最新的一个条目的修改时间和子文件夹的修改时间
4343 if top_latest_modtime_in_subdir > modtime :
4444 modtime = top_latest_modtime_in_subdir
45- time_path_dict [ modtime ] = entry_name
45+ time_path_list . append (( modtime , entry_name ))
4646
4747 # 递归结束后,获取到目标文件夹下直接的文件和文件夹的修改时间
48- if time_path_dict :
49- # 将字典按修改时间排序,得到最终所需结果
50- time_path_dict = dict (sorted (time_path_dict .items (), reverse = True ))
51- for modtime , entry_name in time_path_dict .items ():
48+ if time_path_list :
49+ # 将列表按修改时间(列表每一项元组中的第一个元素)排序,得到最终所需结果
50+ time_path_list .sort (key = lambda x : x [0 ], reverse = True )
51+ # print(time_path_list)
52+ for modtime , entry_name in time_path_list :
5253 rst_entry = f"{ modtime } - { entry_name } { os .linesep } "
5354 # print(rst_entry, end="")
5455 rst += rst_entry
5556 # 获取子文件夹中最新修改的一个条目的修改时间,用于返回给上一级文件夹
56- top_latest_modtime = list ( time_path_dict . keys ()) [0 ]
57+ top_latest_modtime = time_path_list [ 0 ] [0 ]
5758 # print(f"{top_latest_modtime}")
5859 else :
5960 # 空文件夹,返回空字符串
@@ -79,7 +80,10 @@ def multi_check(path_list):
7980 for target_path in pbar :
8081 if not isinstance (pbar , list ):
8182 desc = f"Checking the latest modification time in { target_path } "
82- pbar .set_description (desc )
83+ try :
84+ pbar .set_description (desc )
85+ except AttributeError :
86+ pass
8387 rsts += get_latest_modification_time (target_path )[0 ]
8488 rsts += os .linesep
8589 return rsts
@@ -115,11 +119,11 @@ def save2json(rst):
115119 json_dict = {}
116120 for paragraph in paragraphs :
117121 lines = paragraph .split (os .linesep )
118- target_path = lines [0 ][3 :- 1 ]
119- json_dict [target_path ] = {}
122+ target_path = lines [0 ][3 :- 2 ]
123+ json_dict [target_path ] = []
120124 for line in lines [1 :]:
121125 mtime , entry_name = line .split (' - ' )
122- json_dict [target_path ][ mtime ] = entry_name
126+ json_dict [target_path ]. append ({ mtime : entry_name })
123127 # 保存为json文件
124128 with open (filename , 'w' , encoding = 'utf-8' ) as f :
125129 json .dump (json_dict , f , ensure_ascii = False , indent = 4 )
@@ -129,10 +133,156 @@ def save2json(rst):
129133 return msg
130134
131135def gui ():
136+ def browse_folder ():
137+ folder_path = filedialog .askdirectory ()
138+ if folder_path :
139+ path_entry .delete (0 , tk .END )
140+ path_entry .insert (0 , folder_path )
141+
142+ def check_modification_time ():
143+ target_path = path_entry .get ()
144+ if not target_path :
145+ messagebox .showerror ("Error" , "Please select a folder." )
146+ return
147+
148+ try :
149+ rst = get_latest_modification_time (target_path )[0 ]
150+ result_text .delete ("1.0" , tk .END )
151+ result_text .insert (tk .END , rst )
152+ status_label .config (text = "Status: Check completed." )
153+ except Exception as e :
154+ messagebox .showerror ("Error" , str (e ))
155+ status_label .config (text = "Status: Error occurred." )
156+
157+ def check_script_folder_time ():
158+ script_path = os .path .dirname (os .path .realpath (sys .executable ))
159+ try :
160+ rst = get_latest_modification_time (script_path )[0 ]
161+ result_text .delete ("1.0" , tk .END )
162+ result_text .insert (tk .END , rst )
163+ status_label .config (text = "Status: Check completed." )
164+ except Exception as e :
165+ messagebox .showerror ("Error" , str (e ))
166+ status_label .config (text = "Status: Error occurred." )
167+
168+ def copy_to_clipboard ():
169+ result = result_text .get ("1.0" , tk .END )
170+ if result .strip ():
171+ pyperclip .copy (result )
172+ messagebox .showinfo ("Info" , "Result copied to clipboard." )
173+ else :
174+ messagebox .showwarning ("Warning" , "Nothing to copy." )
175+
176+ def save_as_txt ():
177+ result = result_text .get ("1.0" , tk .END )
178+ if result .strip ():
179+ filename = filedialog .asksaveasfilename (
180+ defaultextension = ".txt" ,
181+ filetypes = [("Text files" , "*.txt" )]
182+ )
183+ if filename :
184+ with open (filename , 'w' , encoding = 'utf-8' ) as f :
185+ f .write (result )
186+ messagebox .showinfo ("Info" , f"Result saved as { filename } ." )
187+ else :
188+ messagebox .showwarning ("Warning" , "Nothing to save." )
189+
190+ def save_as_json ():
191+ result = result_text .get ("1.0" , tk .END )
192+ if result .strip ():
193+ filename = filedialog .asksaveasfilename (
194+ defaultextension = ".json" ,
195+ filetypes = [("JSON files" , "*.json" )]
196+ )
197+ if filename :
198+ paragraphs = result .split ('\n \n ' )
199+ # 去除空段落
200+ for paragraph in paragraphs :
201+ if not paragraph :
202+ paragraphs .remove (paragraph )
203+ json_dict = {}
204+ for paragraph in paragraphs :
205+ lines = paragraph .split ('\n ' )
206+ target_path = lines [0 ][3 :- 3 ]
207+ json_dict [target_path ] = []
208+ for line in lines [1 :]:
209+ try :
210+ mtime , entry_name = line .strip ().split (' - ' )
211+ except ValueError :
212+ # 提醒用户尽量避免修改结果文本之后再保存
213+ error_msg = (f"Invalid text: \n '{ line } '\n "
214+ f"Please avoid modifying the "
215+ f"result text before saving." )
216+ messagebox .showerror ("Error" , error_msg )
217+ return
218+ json_dict [target_path ].append ({mtime : entry_name })
219+ with open (filename , 'w' , encoding = 'utf-8' ) as f :
220+ json .dump (json_dict , f , ensure_ascii = False , indent = 4 )
221+ messagebox .showinfo ("Info" , f"Result saved as { filename } ." )
222+ else :
223+ messagebox .showwarning ("Warning" , "Nothing to save." )
224+
132225 root = tk .Tk ()
133- root .title ("Modtime Pecker - Latest Modification Time Checke " )
226+ root .title ("Modtime Pecker - Latest Modification Time Checker " )
134227 root .geometry ('800x600' )
135228
229+ # 文件夹路径
230+ folder_frame = ttk .Frame (root )
231+ folder_frame .pack (pady = 10 )
232+
233+ ttk .Label (folder_frame , text = "Folder Path:" ).grid (
234+ row = 0 , column = 0 , padx = 5 , pady = 5 )
235+ path_entry = ttk .Entry (folder_frame , width = 50 )
236+ path_entry .grid (row = 0 , column = 1 , padx = 5 , pady = 5 )
237+
238+ browse_button = ttk .Button (folder_frame ,
239+ text = "Browse" ,
240+ command = browse_folder )
241+ browse_button .grid (row = 0 , column = 2 , padx = 5 , pady = 5 )
242+
243+ # 功能按钮
244+ action_frame = ttk .Frame (root )
245+ action_frame .pack (pady = 10 )
246+
247+ check_button = ttk .Button (action_frame ,
248+ text = "Check Modification Time" ,
249+ command = check_modification_time )
250+ check_button .grid (row = 0 , column = 0 , padx = 5 , pady = 5 )
251+
252+ check_script_button = ttk .Button (action_frame ,
253+ text = "Check Script Folder Time" ,
254+ command = check_script_folder_time )
255+ check_script_button .grid (row = 0 , column = 1 , padx = 5 , pady = 5 )
256+
257+ copy_button = ttk .Button (action_frame ,
258+ text = "Copy Result" ,
259+ command = copy_to_clipboard )
260+ copy_button .grid (row = 0 , column = 2 , padx = 5 , pady = 5 )
261+
262+ save_txt_button = ttk .Button (action_frame ,
263+ text = "Save as TXT" ,
264+ command = save_as_txt )
265+ save_txt_button .grid (row = 0 , column = 3 , padx = 5 , pady = 5 )
266+
267+ save_json_button = ttk .Button (action_frame ,
268+ text = "Save as JSON" ,
269+ command = save_as_json )
270+ save_json_button .grid (row = 0 , column = 4 , padx = 5 , pady = 5 )
271+
272+ # 结果显示框
273+ result_frame = ttk .Frame (root )
274+ result_frame .pack (fill = tk .BOTH , expand = True , padx = 10 , pady = 10 )
275+
276+ ttk .Label (result_frame , text = "Result:" ).pack (anchor = tk .W , padx = 5 , pady = 5 )
277+ result_text = tk .Text (result_frame , wrap = tk .WORD , width = 80 , height = 20 )
278+ result_text .pack (fill = tk .BOTH , expand = True , padx = 5 , pady = 5 )
279+
280+ # 状态栏
281+ status_label = ttk .Label (root , text = "Status: Ready" )
282+ status_label .pack (side = tk .BOTTOM , padx = 10 , pady = 5 )
283+
284+ root .mainloop ()
285+
136286def argparser ():
137287 parser = argparse .ArgumentParser (
138288 description = 'Check the latest modification time of all '
@@ -207,5 +357,6 @@ def cli():
207357
208358if __name__ == '__main__' :
209359 if len (sys .argv ) == 1 :
210- sys .argv .extend (['-c' , '-st' ])
211- cli ()
360+ gui ()
361+ else :
362+ cli ()
0 commit comments