diff --git a/index.html b/index.html
new file mode 100644
index 0000000..dab37c9
--- /dev/null
+++ b/index.html
@@ -0,0 +1,137 @@
+
+
+
+
+
+ 画廊下载管理器
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
暂无待下载任务
+
所有任务已完成或暂无数据
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main.py b/main.py
index eda065b..2df8b2c 100644
--- a/main.py
+++ b/main.py
@@ -6,11 +6,12 @@ from pathlib import Path
from typing import Dict, Any, List
import asyncio
import httpx
+import shutil
import aiofiles
from fastapi import FastAPI, HTTPException, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
-from fastapi.responses import HTMLResponse
+from fastapi.responses import HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
import uvicorn
@@ -96,17 +97,25 @@ def get_all_galleries() -> List[GalleryInfo]:
downloaded_count = 0
if 'all_images' in data:
- for filename, url in data['all_images'].items():
- image_path = gallery_dir / filename
- if image_path.exists():
+ # 获取目录下所有图片文件
+ image_files = list(gallery_dir.glob("*.*"))
+ image_filenames = {file.stem for file in image_files if file.is_file() and file.name != "data.json"}
+
+ # 检查JSON中每个图片是否有对应的实际文件(忽略后缀名)
+ for filename in data['all_images'].keys():
+ # 移除可能的扩展名(如果有的话),只比较文件名主体
+ filename_stem = Path(filename).stem
+ if filename_stem in image_filenames:
downloaded_count += 1
- galleries.append(GalleryInfo(
- title=data.get('title', gallery_dir.name),
- path=str(gallery_dir),
- total_images=data.get('total_images', 0),
- downloaded_images=downloaded_count
- ))
+ # 只显示未完成的任务(下载进度不是100%的)
+ if downloaded_count < data.get('total_images', 0):
+ galleries.append(GalleryInfo(
+ title=data.get('title', gallery_dir.name),
+ path=str(gallery_dir),
+ total_images=data.get('total_images', 0),
+ downloaded_images=downloaded_count
+ ))
except Exception as e:
logger.error(f"读取画廊数据失败 {gallery_dir}: {e}")
@@ -130,7 +139,8 @@ async def download_single_image(client: httpx.AsyncClient, url: str, file_path:
# 创建带后缀的文件路径
file_path_with_suffix = file_path.with_suffix('.' + suffix)
- if file_path_with_suffix.exists():
+ # 检查是否已存在(考虑所有可能的扩展名)
+ if check_image_exists(file_path):
return True
img_response = await client.get(real_img_url, timeout=DOWNLOAD_TIMEOUT)
@@ -145,6 +155,25 @@ async def download_single_image(client: httpx.AsyncClient, url: str, file_path:
logger.error(f"下载失败 {url}: {e}")
return False
+def check_image_exists(file_path: Path) -> bool:
+ """检查图片文件是否存在(忽略扩展名)"""
+ if file_path.exists():
+ return True
+
+ # 检查是否有相同文件名但不同扩展名的文件
+ parent_dir = file_path.parent
+ stem = file_path.stem
+
+ # 常见的图片扩展名
+ image_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'}
+
+ for ext in image_extensions:
+ potential_file = parent_dir / f"{stem}{ext}"
+ if potential_file.exists():
+ return True
+
+ return False
+
async def download_gallery_images(title: str) -> DownloadStatusResponse:
safe_title = sanitize_filename(title)
gallery_path = downloads_path / safe_title
@@ -197,7 +226,8 @@ async def download_gallery_images(title: str) -> DownloadStatusResponse:
for filename, url in all_images.items():
image_path = gallery_path / filename
- if image_path.exists():
+ # 使用新的检查方法,忽略扩展名
+ if check_image_exists(image_path):
download_status[title]["downloaded"] += 1
continue
@@ -264,6 +294,46 @@ async def download_all_pending_galleries():
logger.info("批量下载任务完成")
+def delete_completed_json_files():
+ """删除已完成任务的JSON文件"""
+ downloads_path = Path(DOWNLOADS_DIR)
+ deleted_count = 0
+
+ if not downloads_path.exists():
+ return deleted_count
+
+ for gallery_dir in downloads_path.iterdir():
+ if gallery_dir.is_dir():
+ data_file = gallery_dir / "data.json"
+ if data_file.exists():
+ try:
+ with open(data_file, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+
+ # 检查是否所有图片都已下载
+ downloaded_count = 0
+ if 'all_images' in data:
+ image_files = list(gallery_dir.glob("*.*"))
+ image_filenames = {file.stem for file in image_files if file.is_file() and file.name != "data.json"}
+
+ for filename in data['all_images'].keys():
+ filename_stem = Path(filename).stem
+ if filename_stem in image_filenames:
+ downloaded_count += 1
+
+ total_images = len(data.get('all_images', {}))
+
+ # 如果所有图片都已下载,删除JSON文件
+ if downloaded_count == total_images and total_images > 0:
+ data_file.unlink()
+ deleted_count += 1
+ logger.info(f"已删除已完成任务的JSON文件: {gallery_dir.name}")
+
+ except Exception as e:
+ logger.error(f"处理画廊目录失败 {gallery_dir}: {e}")
+
+ return deleted_count
+
# 初始化
downloads_path = setup_downloads_directory()
@@ -295,128 +365,9 @@ async def save_url_data(request: SaveDataRequest = None):
logger.error(f"保存数据失败: {e}")
raise HTTPException(status_code=500, detail=f"保存失败: {str(e)}")
-@app.get("/", response_class=HTMLResponse)
+@app.get("/")
async def read_gallery_manager():
- return """
-
-
-
-
-
- 画廊下载管理器
-
-
-
-
-
-
-
-
-
-
-
-
-
-
暂无待下载任务
-
点击"读取文件夹"按钮加载数据
-
-
-
-
-
-
-
- """
+ return FileResponse("index.html")
@app.get("/api/galleries")
async def get_galleries():
@@ -440,6 +391,20 @@ async def download_gallery(title: str, background_tasks: BackgroundTasks):
"title": title
}
+@app.post("/api/cleanup")
+async def cleanup_completed_galleries():
+ """清理已完成任务的JSON文件"""
+ try:
+ deleted_count = delete_completed_json_files()
+ return {
+ "status": "success",
+ "message": f"成功删除 {deleted_count} 个已完成任务的JSON文件",
+ "deleted_count": deleted_count
+ }
+ except Exception as e:
+ logger.error(f"清理JSON文件失败: {e}")
+ raise HTTPException(status_code=500, detail=f"清理失败: {str(e)}")
+
@app.get("/health")
async def health_check():
return {"status": "healthy"}