Files

324 lines
10 KiB
Python

"""
SQLite下载历史管理器
用于记录图片下载历史,不修改生产MySQL数据库
"""
import os
import sqlite3
from datetime import datetime
from typing import List, Dict, Optional
import sys
# 添加父目录到路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import SQLITE_DB_PATH
class SQLiteManager:
"""SQLite下载历史管理器"""
def __init__(self, db_path: str = SQLITE_DB_PATH):
"""初始化SQLite连接"""
self.db_path = db_path
self._init_database()
def _init_database(self):
"""初始化数据库表结构"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# 创建下载历史表
cursor.execute('''
CREATE TABLE IF NOT EXISTS download_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
datasource TEXT NOT NULL,
goods_id INTEGER,
goods_name TEXT,
image_url TEXT NOT NULL,
local_path TEXT NOT NULL,
download_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
file_size INTEGER,
UNIQUE(datasource, image_url)
)
''')
# 创建索引
cursor.execute('''
CREATE INDEX IF NOT EXISTS idx_datasource_goods_id
ON download_history(datasource, goods_id)
''')
cursor.execute('''
CREATE INDEX IF NOT EXISTS idx_download_time
ON download_history(download_time)
''')
conn.commit()
conn.close()
print(f"SQLite数据库初始化成功: {self.db_path}")
except Exception as e:
print(f"SQLite数据库初始化失败: {e}")
raise
def add_download_record(
self,
datasource: str,
goods_id: int,
goods_name: str,
image_url: str,
local_path: str,
file_size: int
) -> bool:
"""
添加下载记录
Returns:
是否成功
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
INSERT OR REPLACE INTO download_history
(datasource, goods_id, goods_name, image_url, local_path, file_size, download_time)
VALUES (?, ?, ?, ?, ?, ?, ?)
''', (
datasource,
goods_id,
goods_name,
image_url,
local_path,
file_size,
datetime.now()
))
conn.commit()
conn.close()
return True
except Exception as e:
print(f"添加下载记录失败: {e}")
return False
def is_downloaded(self, datasource: str, image_url: str) -> bool:
"""
检查图片是否已下载(检查数据库记录 + 文件是否存在)
Args:
datasource: 数据源
image_url: 图片URL
Returns:
是否已下载
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
SELECT local_path FROM download_history
WHERE datasource = ? AND image_url = ?
''', (datasource, image_url))
result = cursor.fetchone()
conn.close()
if result:
local_path = result[0]
# 检查文件是否真实存在
return os.path.exists(local_path)
return False
except Exception as e:
print(f"检查下载状态失败: {e}")
return False
def get_download_history(
self,
datasource: Optional[str] = None,
start_date: Optional[datetime] = None,
end_date: Optional[datetime] = None,
limit: int = 100
) -> List[Dict]:
"""
获取下载历史
Returns:
下载记录列表
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
query = 'SELECT * FROM download_history WHERE 1=1'
params = []
if datasource:
query += ' AND datasource = ?'
params.append(datasource)
if start_date:
query += ' AND download_time >= ?'
params.append(start_date.strftime('%Y-%m-%d %H:%M:%S'))
if end_date:
query += ' AND download_time <= ?'
params.append(end_date.strftime('%Y-%m-%d %H:%M:%S'))
query += ' ORDER BY download_time DESC LIMIT ?'
params.append(limit)
cursor.execute(query, params)
columns = [desc[0] for desc in cursor.description]
results = []
for row in cursor.fetchall():
results.append(dict(zip(columns, row)))
conn.close()
return results
except Exception as e:
print(f"获取下载历史失败: {e}")
return []
def get_download_statistics(self) -> Dict:
"""获取下载统计信息"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# 总下载数
cursor.execute('SELECT COUNT(*) FROM download_history')
total_count = cursor.fetchone()[0]
# 各数据源下载数
cursor.execute('''
SELECT datasource, COUNT(*) as count
FROM download_history
GROUP BY datasource
''')
datasource_stats = {row[0]: row[1] for row in cursor.fetchall()}
# 今日下载数
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
cursor.execute('''
SELECT COUNT(*) FROM download_history
WHERE download_time >= ?
''', (today.strftime('%Y-%m-%d %H:%M:%S'),))
today_count = cursor.fetchone()[0]
conn.close()
return {
'total_count': total_count,
'datasource_stats': datasource_stats,
'today_count': today_count
}
except Exception as e:
print(f"获取下载统计失败: {e}")
return {}
def get_local_path(self, datasource: str, image_url: str) -> Optional[str]:
"""
获取图片的本地文件路径
Args:
datasource: 数据源
image_url: 图片URL
Returns:
本地文件路径,如果未下载则返回None
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
SELECT local_path FROM download_history
WHERE datasource = ? AND image_url = ?
''', (datasource, image_url))
result = cursor.fetchone()
conn.close()
return result[0] if result else None
except Exception as e:
print(f"获取本地路径失败: {e}")
return None
def delete_download_record(self, datasource: str, image_url: str, delete_file: bool = True) -> bool:
"""
删除下载记录(可选删除物理文件)
Args:
datasource: 数据源
image_url: 图片URL
delete_file: 是否删除物理文件
Returns:
是否成功
"""
try:
# 如果需要删除文件,先获取文件路径
local_path = None
if delete_file:
local_path = self.get_local_path(datasource, image_url)
# 删除数据库记录
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
DELETE FROM download_history
WHERE datasource = ? AND image_url = ?
''', (datasource, image_url))
conn.commit()
conn.close()
# 删除物理文件
if delete_file and local_path and os.path.exists(local_path):
try:
os.remove(local_path)
print(f"已删除本地文件: {local_path}")
except Exception as e:
print(f"删除本地文件失败: {e}")
return True
except Exception as e:
print(f"删除下载记录失败: {e}")
return False
def clear_invalid_records(self) -> int:
"""清理文件不存在的下载记录"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('SELECT id, local_path FROM download_history')
records = cursor.fetchall()
deleted_count = 0
for record_id, local_path in records:
if not os.path.exists(local_path):
cursor.execute('DELETE FROM download_history WHERE id = ?', (record_id,))
deleted_count += 1
conn.commit()
conn.close()
print(f"已清理 {deleted_count} 条无效记录")
return deleted_count
except Exception as e:
print(f"清理无效记录失败: {e}")
return 0