🐛 修复下载历史重复计数

This commit is contained in:
2026-06-05 16:34:07 +08:00
parent 87d8f522a6
commit 85af153b38
3 changed files with 37 additions and 7 deletions
+14 -1
View File
@@ -3,7 +3,7 @@ import json
import os
import time
from datetime import datetime, timedelta
from typing import Any, Optional
from typing import Any, Dict, List, Optional, Tuple
from core.response import APIResponse
from core.storage import FileStorageInterface, storages
@@ -82,6 +82,18 @@ class FileService:
def _file_metadata_key(self, file_id: int) -> str:
return f"{self.FILE_METADATA_KEY_PREFIX}{file_id}"
def _dedupe_download_stats(self, stats: List[TransferStats]) -> List[TransferStats]:
deduped: List[TransferStats] = []
recent_downloads: Dict[Tuple[Optional[int], str, int], datetime] = {}
for stat in stats:
key = (stat.file_code_id, stat.ip or "", int(stat.size or 0))
previous = recent_downloads.get(key)
if previous and (stat.created_at - previous).total_seconds() <= 5:
continue
recent_downloads[key] = stat.created_at
deduped.append(stat)
return deduped
async def _delete_file_code(self, file_code: FileCodes):
try:
name = (
@@ -1289,6 +1301,7 @@ class FileService:
download_stats = await TransferStats.filter(
action="download", file_code_id=file_code.id
).order_by("created_at")
download_stats = self._dedupe_download_stats(download_stats)
timeline.append(
{
"key": "retrieved",
+16 -1
View File
@@ -189,10 +189,25 @@ async def analytics(start: str = "", end: str = ""):
end_day = parse_day(end, now.replace(hour=0, minute=0, second=0, microsecond=0))
start_day = parse_day(start, end_day - datetime.timedelta(days=29))
end_exclusive = end_day + datetime.timedelta(days=1)
stats = await TransferStats.filter(
raw_stats = await TransferStats.filter(
created_at__gte=start_day,
created_at__lt=end_exclusive,
).order_by("created_at", "id")
stats = []
recent_downloads = {}
for item in raw_stats:
if item.action == "download":
dedupe_key = (
item.file_code_id or item.code or "",
item.ip or "",
int(item.size or 0),
)
previous = recent_downloads.get(dedupe_key)
if previous and (item.created_at - previous).total_seconds() <= 5:
continue
recent_downloads[dedupe_key] = item.created_at
stats.append(item)
files = await FileCodes.all()
file_map = {item.code: item for item in files}
+4 -2
View File
@@ -292,6 +292,7 @@ async def select_file(data: SelectFileModel, ip: str = Depends(ip_limit["error"]
return APIResponse(code=404, detail=file_code)
assert isinstance(file_code, FileCodes)
if file_code.text is not None:
await update_file_usage(file_code)
await record_transfer_stat("download", file_code, file_code.size, ip)
return APIResponse(detail=await build_select_detail(file_code, file_storage))
@@ -303,10 +304,11 @@ async def download_file(key: str, code: str, ip: str = Depends(ip_limit["error"]
if await get_select_token(code) != key:
ip_limit["error"].add_ip(ip)
raise HTTPException(status_code=403, detail="下载鉴权失败")
has, file_code = await get_code_file_by_code(code, False)
has, file_code = await get_code_file_by_code(code)
if not has:
return APIResponse(code=404, detail="文件不存在")
return APIResponse(code=404, detail=file_code)
assert isinstance(file_code, FileCodes)
await update_file_usage(file_code)
await record_transfer_stat("download", file_code, file_code.size, ip)
return (
APIResponse(detail=file_code.text)