11import os
2+ import io
23import json
34import random
45import datetime
1213from tiklocal .services import LibraryService , FavoriteService , RecommendService
1314from tiklocal .services .thumbnail import ThumbnailService
1415
15- try :
16- app_version = version ("tiklocal" )
17- except PackageNotFoundError :
18- app_version = '1.0.0'
16+
17+ def get_app_version ():
18+ """获取应用版本号,开发模式下从 pyproject.toml 读取"""
19+ # 开发模式:优先从 pyproject.toml 读取
20+ pyproject_path = Path (__file__ ).parent .parent / 'pyproject.toml'
21+ if pyproject_path .exists ():
22+ try :
23+ import tomllib
24+ except ImportError :
25+ try :
26+ import tomli as tomllib
27+ except ImportError :
28+ tomllib = None
29+
30+ if tomllib :
31+ try :
32+ with open (pyproject_path , 'rb' ) as f :
33+ data = tomllib .load (f )
34+ return data .get ('tool' , {}).get ('poetry' , {}).get ('version' , '1.0.0' )
35+ except Exception :
36+ pass
37+
38+ # 生产模式:从已安装的包元数据获取
39+ try :
40+ return version ("tiklocal" )
41+ except PackageNotFoundError :
42+ return '1.0.0'
43+
44+
45+ app_version = get_app_version ()
1946
2047def create_app (test_config = None ):
2148 app = Flask (__name__ , instance_relative_config = True )
@@ -71,32 +98,35 @@ def browse():
7198 """Video Library List"""
7299 # Using scan_videos instead of recursive get_files
73100 videos = library_service .scan_videos ()
74-
101+
75102 # Filter Logic
76- size_mode = request .args .get ('size ' , 'all' )
103+ filter_mode = request .args .get ('filter ' , 'all' )
77104 min_mb = int (request .args .get ('min_mb' , 50 ))
78-
79- if size_mode == 'big' :
105+
106+ if filter_mode == 'big' :
80107 threshold = min_mb * 1024 * 1024
81108 videos = [v for v in videos if v .stat ().st_size >= threshold ]
109+ elif filter_mode == 'favorite' :
110+ favorites = favorite_service .load ()
111+ videos = [v for v in videos if library_service .get_relative_path (v ) in favorites ]
82112
83113 # Pagination
84114 count = len (videos )
85115 page = int (request .args .get ('page' , 1 ))
86116 length = 20
87117 offset = length * (page - 1 )
88-
118+
89119 # Convert to relative strings for template
90120 sliced_videos = [library_service .get_relative_path (v ) for v in videos [offset :offset + length ]]
91-
121+
92122 return render_template (
93123 'browse.html' ,
94124 page = page ,
95125 count = count ,
96126 length = length ,
97127 files = sliced_videos ,
98128 menu = 'browse' ,
99- size_mode = size_mode ,
129+ filter = filter_mode ,
100130 min_mb = min_mb ,
101131 has_min_mb = request .args .get ('min_mb' ) is not None ,
102132 has_previous = page > 1 ,
@@ -105,8 +135,29 @@ def browse():
105135
106136 @app .route ('/settings/' )
107137 def settings_view ():
138+ from tiklocal .paths import get_thumbnails_dir
139+
140+ # 获取各类统计
108141 video_count = len (library_service .scan_videos ())
109- return render_template ('settings.html' , menu = 'settings' , version = app_version , videos = video_count )
142+ image_count = len (library_service .scan_images ())
143+ favorite_count = len (favorite_service .load ())
144+
145+ # 缩略图缓存信息
146+ thumb_dir = get_thumbnails_dir ()
147+ thumb_files = list (thumb_dir .glob ('*.jpg' ))
148+ cache_count = len (thumb_files )
149+ cache_size_mb = round (sum (f .stat ().st_size for f in thumb_files if f .exists ()) / (1024 * 1024 ), 2 )
150+
151+ return render_template (
152+ 'settings.html' ,
153+ menu = 'settings' ,
154+ version = app_version ,
155+ videos = video_count ,
156+ images = image_count ,
157+ favorites = favorite_count ,
158+ cache_count = cache_count ,
159+ cache_size_mb = cache_size_mb
160+ )
110161
111162 @app .route ('/library' )
112163 def library_redirect ():
@@ -251,17 +302,65 @@ def api_favorite(name):
251302 def api_set_thumbnail (name ):
252303 target = library_service .resolve_path (name )
253304 if not target : return {'success' : False , 'error' : 'Invalid path' }, 400
254-
305+
255306 payload = request .get_json (silent = True ) or {}
256307 ts = payload .get ('time' )
257-
308+
258309 # This logic is a bit specific to app.py still, ideally move to ThumbnailService
259310 # But for now, we just need to regen the thumb
260311 thumb_path = thumbnail_service ._get_thumb_path (name )
261312 success = thumbnail_service ._generate (target , thumb_path , timestamp = float (ts ) if ts else None )
262-
313+
263314 if success :
264315 return {'success' : True , 'url' : f"/thumb?uri={ quote (name )} &v={ int (datetime .datetime .now ().timestamp ())} " }
265316 return {'success' : False , 'error' : 'Failed to generate' }, 500
266317
318+ @app .route ('/api/cache/clear' , methods = ['POST' ])
319+ def api_clear_cache ():
320+ """清理缩略图缓存"""
321+ from tiklocal .paths import get_thumbnails_dir
322+
323+ thumb_dir = get_thumbnails_dir ()
324+ deleted_count = 0
325+ freed_bytes = 0
326+
327+ try :
328+ for thumb_file in thumb_dir .glob ('*.jpg' ):
329+ try :
330+ freed_bytes += thumb_file .stat ().st_size
331+ thumb_file .unlink ()
332+ deleted_count += 1
333+ except Exception :
334+ continue
335+
336+ return {
337+ 'success' : True ,
338+ 'deleted_count' : deleted_count ,
339+ 'freed_mb' : round (freed_bytes / (1024 * 1024 ), 2 )
340+ }
341+ except Exception as e :
342+ return {'success' : False , 'error' : str (e )}, 500
343+
344+ @app .route ('/api/library/stats' )
345+ def api_library_stats ():
346+ """获取媒体库统计信息"""
347+ from tiklocal .paths import get_thumbnails_dir
348+
349+ videos = library_service .scan_videos ()
350+ images = library_service .scan_images ()
351+ favorites = favorite_service .load ()
352+
353+ # 计算缩略图缓存信息
354+ thumb_dir = get_thumbnails_dir ()
355+ thumb_files = list (thumb_dir .glob ('*.jpg' ))
356+ thumb_size = sum (f .stat ().st_size for f in thumb_files if f .exists ())
357+
358+ return {
359+ 'videos' : len (videos ),
360+ 'images' : len (images ),
361+ 'favorites' : len (favorites ),
362+ 'cache_count' : len (thumb_files ),
363+ 'cache_mb' : round (thumb_size / (1024 * 1024 ), 2 )
364+ }
365+
267366 return app
0 commit comments