__init__.py 7.3 KB

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