__init__.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from fastapi import APIRouter, Request, Depends,Response,HTTPException,status,Query,UploadFile,File,Form
  4. from typing import List, Optional
  5. from fastapi.responses import JSONResponse
  6. from fastapi.responses import FileResponse
  7. from sqlalchemy.orm import Session
  8. from database import get_db
  9. from config import settings
  10. from urllib import parse
  11. # from PIL import Image
  12. from models import *
  13. from utils import *
  14. import requests
  15. import hashlib
  16. import random
  17. import string
  18. import json
  19. import time
  20. import os
  21. router = APIRouter()
  22. UPLOAD_IMAGE_PATH = '/data/upload/img/'
  23. UPLOAD_mergefile_PATH = '/data/upload/mergefile/'
  24. @router.post("/upload/upload_img")
  25. async def upload_img(
  26. request: Request,
  27. file: UploadFile = File(...),
  28. db: Session = Depends(get_db)
  29. ):
  30. file_name = file.filename
  31. # 文件后续名校验
  32. suffix = os.path.splitext(file_name)[-1]
  33. if suffix.lower() not in ['.png', '.jpg', '.jpeg']:
  34. return {
  35. 'code': 1,
  36. 'msg': '文件类型不在png,jpg范围内',
  37. }
  38. upload_path = UPLOAD_IMAGE_PATH
  39. file_dir = os.path.join(upload_path, "{}".format("poster"))
  40. if os.path.exists(file_dir) == False:
  41. os.makedirs(file_dir)
  42. file_name = new_guid() + suffix.lower()
  43. file_path = os.path.abspath("{}/{}".format(file_dir, file_name))
  44. if os.path.exists(file_path):
  45. os.remove(file_path)
  46. content = await file.read()
  47. with open(file_path, 'wb') as f:
  48. f.write(content)
  49. print('file_path:', file_path)
  50. return {
  51. 'code': 0,
  52. 'msg': '上传成功',
  53. 'data': file_name
  54. }
  55. @router.get('/get_img/get_img_by_id/{id}', response_class=FileResponse)
  56. async def get_poster_by_id(
  57. request: Request,
  58. id: str,
  59. db: Session = Depends(get_db)
  60. ):
  61. image_filepath = os.path.abspath(os.path.join(UPLOAD_IMAGE_PATH+'poster/', id )) #+ ".png"
  62. # print(image_filepath)
  63. if os.path.exists(image_filepath) == False:
  64. return {'err':'错误'}
  65. image_filepath = "./static/img/video_poster.png"
  66. # else:
  67. # file_size = os.path.getsize(image_filepath)
  68. # if file_size > (1024 * 1024 * 1.5): # 1.5M
  69. # image = Image.open(image_filepath)
  70. # image.thumbnail((675, 390))
  71. # image.save(image_filepath, 'png')
  72. return FileResponse(image_filepath)
  73. @router.post("/upload/uploadfile")
  74. async def upload_big_file( request: Request,
  75. file: UploadFile = File(...),
  76. chunknumber: str = Query(''),
  77. identifier: str = Query('')): # 分片上传文件【用唯一标志符+分片序号】作为文件名
  78. if not file:
  79. raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="文件字段缺失")
  80. if len(chunknumber) == 0 or len(identifier) == 0:
  81. return {"eroor": "没有传递相关参数"}
  82. print(1111)
  83. task = identifier # 获取文件唯一标识符
  84. chunk = chunknumber # 获取该分片在所有分片中的序号【客户端设定】
  85. filename = '%s%s' % (task, chunk) # 构成该分片唯一标识符
  86. file_dir = f"{UPLOAD_mergefile_PATH}/uploads/"
  87. if os.path.exists(file_dir) == False:
  88. os.makedirs(file_dir)
  89. contents = await file.read() # 异步读取文件
  90. with open(file_dir+f"{filename}", "wb") as f:
  91. f.write(contents)
  92. return {"filename": file.filename}
  93. @router.post("/upload/mergefile")
  94. async def mergefile(identifier: str = Query(''),
  95. filename: str = Query(''),
  96. chunkstar: int = Query(0)): # 根据唯一标识符合并文件
  97. if len(filename) == 0 or len(identifier) == 0:
  98. return {"eroor": "没有传递相关参数"}
  99. suffix = os.path.splitext(filename)[-1]
  100. filename = new_guid() + suffix.lower()
  101. target_filename = filename # 获取上传文件的文件名【保存的文件名】
  102. task = identifier # 获取文件的唯一标识符
  103. chunk = chunkstar # 分片序号开始的序号默认=0
  104. if os.path.isfile(f"{UPLOAD_mergefile_PATH}/uploads/{target_filename}"): # 如果客户端传递过来的文件名在服务器上已经存在,那么另外新建一个【时间戳.后缀名】文件
  105. t = time.time() # 时间戳
  106. timeUnix = str(round(t * 1000)) # 毫秒级时间戳
  107. filesuffix = os.path.splitext(target_filename)[1] # 后缀名
  108. target_filename = timeUnix + filesuffix # 新文件名【时间戳.后缀名】
  109. error_i = 0
  110. chunkfilename = ""
  111. with open(f"{UPLOAD_mergefile_PATH}/uploads/{target_filename}", 'wb') as target_file: # 创建新文件
  112. while True: # 循环把分片文件写入新建的文件
  113. if os.path.isfile(f"{UPLOAD_mergefile_PATH}/uploads/{task}{chunk}"): # 存在这个文件
  114. try:
  115. # 分片文件名
  116. chunkfilename = f"{UPLOAD_mergefile_PATH}/uploads/{task}{chunk}"
  117. # 按序打开每个分片
  118. source_file = open(chunkfilename, 'rb')
  119. # 读取分片内容写入新文件
  120. target_file.write(source_file.read())
  121. source_file.close()
  122. except IOError: # 当分片标志chunk累加到最后,文件夹里面不存在{task}{chunk}文件时,退出循环
  123. break
  124. os.remove(f"{UPLOAD_mergefile_PATH}/uploads/{task}{chunk}") # 删除分片文件
  125. else: # 【如果分片文件上传中途出错,导致中间缺少某个分片文件,跳过它,不退出循环,直到累计缺少次数大于3次,再跳出循环】
  126. error_i += 1
  127. if error_i > 3:
  128. break
  129. chunk += 1
  130. os.chmod(f"{UPLOAD_mergefile_PATH}uploads/{target_filename}", 0o664) # linux设置权限0o664、0o400
  131. return {"code": 200, "filename": f"{target_filename}"}
  132. @router.get("/download/{filename}")
  133. async def download_file(filename: str):
  134. """
  135. 根据提供的文件名下载文件。
  136. :param filename: 要下载的文件的名称。
  137. """
  138. try:
  139. # 构造文件的完整路径
  140. file_path = os.path.join(UPLOAD_mergefile_PATH, 'uploads/', filename)
  141. # 检查文件是否存在
  142. if not os.path.isfile(file_path):
  143. raise HTTPException(status_code=404, detail="文件未找到")
  144. # 设置文件头部和内容类型
  145. headers = {
  146. 'Content-Disposition': f'attachment; filename={filename}'
  147. }
  148. # 使用FileResponse返回文件流
  149. return FileResponse(
  150. path=file_path,
  151. headers=headers,
  152. media_type='application/octet-stream' # 可以按需更改为适当的MIME类型
  153. )
  154. except HTTPException as e:
  155. raise e
  156. except Exception as e:
  157. # 处理其他异常情况
  158. raise HTTPException(status_code=500, detail=str(e))