1616import tkinter .ttk as ttk
1717import typing as ty
1818import webbrowser
19+ from datetime import datetime
1920from logging import getLogger
2021from pathlib import Path
2122from tempfile import NamedTemporaryFile
@@ -86,7 +87,7 @@ def __init__(self, root: tk.Widget):
8687
8788 self ._videos = ttk .Treeview (
8889 frame ,
89- columns = ("duration" , "framerate" , "resolution" , "path" ),
90+ columns = ("duration" , "framerate" , "resolution" , "path" , "date" ),
9091 )
9192
9293 scroll_horizontal = ttk .Scrollbar (frame , orient = tk .HORIZONTAL , command = self ._videos .xview )
@@ -100,16 +101,24 @@ def __init__(self, root: tk.Widget):
100101 self ._videos .grid (row = 0 , column = 0 , sticky = tk .NSEW )
101102 frame .grid (row = 0 , column = 0 , rowspan = 2 , columnspan = 6 , sticky = tk .NSEW )
102103
103- self ._videos .heading ("#0" , text = "Name" )
104+ self ._videos .heading ("#0" , text = "Name" , command = lambda : self . _sort_column ( "#0" , False ) )
104105 self ._videos .column ("#0" , width = 180 , minwidth = 80 , stretch = False )
105- self ._videos .heading ("duration" , text = "Duration" )
106+ self ._videos .heading (
107+ "duration" , text = "Duration" , command = lambda : self ._sort_column ("duration" , False )
108+ )
106109 self ._videos .column ("duration" , width = 80 , minwidth = 80 , stretch = False )
107- self ._videos .heading ("framerate" , text = "Framerate" )
110+ self ._videos .heading (
111+ "framerate" , text = "Framerate" , command = lambda : self ._sort_column ("framerate" , False )
112+ )
108113 self ._videos .column ("framerate" , width = 80 , minwidth = 80 , stretch = False )
109- self ._videos .heading ("resolution" , text = "Resolution" )
114+ self ._videos .heading (
115+ "resolution" , text = "Resolution" , command = lambda : self ._sort_column ("resolution" , False )
116+ )
110117 self ._videos .column ("resolution" , width = 80 , minwidth = 80 , stretch = False )
111- self ._videos .heading ("path" , text = "Path" )
118+ self ._videos .heading ("path" , text = "Path" , command = lambda : self . _sort_column ( "path" , False ) )
112119 self ._videos .column ("path" , width = 80 , minwidth = 80 , stretch = False )
120+ self ._videos .heading ("date" , text = "Date" , command = lambda : self ._sort_column ("date" , False ))
121+ self ._videos .column ("date" , width = 140 , minwidth = 80 , stretch = False )
113122
114123 self ._videos .grid (row = 0 , column = 0 , columnspan = 6 , sticky = tk .NSEW )
115124
@@ -213,6 +222,16 @@ def update(self, settings: ScanSettings) -> ty.Optional[ScanSettings]:
213222 settings .set ("regions" , self ._region_editor .shapes )
214223 return settings
215224
225+ def _sort_column (self , col , reverse ):
226+ if col == "#0" :
227+ items = [(self ._videos .item (k , "text" ), k ) for k in self ._videos .get_children ("" )]
228+ else :
229+ items = [(self ._videos .set (k , col ), k ) for k in self ._videos .get_children ("" )]
230+ items .sort (reverse = reverse )
231+ for index , (_val , k ) in enumerate (items ):
232+ self ._videos .move (k , "" , index )
233+ self ._videos .heading (col , command = lambda : self ._sort_column (col , not reverse ))
234+
216235 def _add_video (self , path : str = "" ):
217236 paths = []
218237 if not path :
@@ -232,7 +251,15 @@ def _add_video(self, path: str = ""):
232251 logger .error (f"File does not exist: { path } " )
233252 return
234253 try :
235- video = open_video (path , backend = "opencv" )
254+ video = open_video (path , backend = "opencv" ) # logs errors on failure
255+ try :
256+ # On Windows, ctime is creation time. On other systems, it may be the
257+ # last metadata change time.
258+ create_time = datetime .fromtimestamp (Path (path ).stat ().st_ctime )
259+ create_time_str = create_time .strftime ("%Y-%m-%d %H:%M:%S" )
260+ except OSError as ex :
261+ logger .debug (f"Failed to stat { path } : { ex } " )
262+ create_time_str = "N/A"
236263 except VideoOpenFailure :
237264 failed_to_load = True
238265 continue
@@ -244,7 +271,7 @@ def _add_video(self, path: str = ""):
244271 "" ,
245272 tk .END ,
246273 text = video .name ,
247- values = (duration , framerate , resolution , path ),
274+ values = (duration , framerate , resolution , path , create_time_str ),
248275 )
249276 if failed_to_load :
250277 tkinter .messagebox .showwarning (
0 commit comments