Add file upload

This commit is contained in:
2024-05-10 14:20:46 +04:00
parent 698cca0aeb
commit a45c2dfee2
11 changed files with 102 additions and 9 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
content
dev_database.db dev_database.db
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files

View File

@@ -5,7 +5,9 @@ from .. import models as mdl
from .. import schemas as sch from .. import schemas as sch
from ..database import add_transaction from ..database import add_transaction
async def add_game(db: AsyncSession, game_info: sch.GameCreate, user_id: int): async def add_game(db: AsyncSession,
game_info: sch.GameCreate,
user_id: int):
game = mdl.Game(**game_info.model_dump(), owner_id=user_id) game = mdl.Game(**game_info.model_dump(), owner_id=user_id)
return await add_transaction(db, game) return await add_transaction(db, game)

View File

@@ -10,7 +10,7 @@ class Game(Base):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
cover = Column(String) cover = Column(String)
title = Column(String, nullable=False) title = Column(String, nullable=False, unique=True)
description = Column(String) description = Column(String)
torrent_file = Column(String, nullable=False) torrent_file = Column(String, nullable=False)
language = Column(String) language = Column(String)

View File

@@ -2,8 +2,8 @@ from pydantic import BaseModel
class GameBase(BaseModel): class GameBase(BaseModel):
cover: str | None = None
title: str title: str
cover: str | None = None
description: str | None = None description: str | None = None
torrent_file: str torrent_file: str
language: str | None = None language: str | None = None

42
file_handler.py Normal file
View File

@@ -0,0 +1,42 @@
import hashlib
from io import BytesIO
import mimetypes
from pathlib import Path
from typing import Literal
import aiofiles
from fastapi import UploadFile
from PIL import Image
def create_hash_name(filename: str):
return str(hashlib.sha1(filename.encode()).hexdigest())
async def save_torrent_file(torrent: UploadFile):
hash_filename = create_hash_name(torrent.filename)+".torrent"
async with aiofiles.open(Path() / "content" / "torrent"
/ hash_filename, 'wb') as file:
await file.write(await torrent.read())
return hash_filename
async def save_image(cover: UploadFile, type: Literal["cover", "screenshot"]):
hash_filename = create_hash_name(cover.filename) \
+ mimetypes.guess_extension(cover.content_type)
async with aiofiles.open(Path() / "content" / "images" / type / "full_size"
/ hash_filename, 'wb') as full_size_file, \
aiofiles.open(Path() / "content" / "images" / type /
"preview" / hash_filename, 'wb') as preview_file:
cover_data = await cover.read()
await full_size_file.write(cover_data)
image = Image.open(BytesIO(cover_data))
compressed_coefficient = (image.size[0] * image.size[1]) / (1280*720/4)
if(compressed_coefficient < 1): compressed_coefficient = 1
compressed_image = image.resize(
( int(image.size[0] / compressed_coefficient),
int(image.size[1] / compressed_coefficient) )
)
buf = BytesIO()
compressed_image.save(buf, format=
cover.content_type.upper().replace("IMAGE/", ""))
await preview_file.write(buf.getbuffer())
return hash_filename

View File

@@ -6,7 +6,9 @@ import cli_commands
from routes import * from routes import *
app = FastAPI() app = FastAPI()
app.include_router(startup_router)
app.include_router(games_router) app.include_router(games_router)
app.include_router(files_router)
cli = typer.Typer() cli = typer.Typer()
cli.add_typer(cli_commands.cli, name="database") cli.add_typer(cli_commands.cli, name="database")

View File

@@ -2,4 +2,5 @@ fastapi==0.111.0
pydantic==2.7.1 pydantic==2.7.1
SQLAlchemy==2.0.30 SQLAlchemy==2.0.30
aiosqlite==0.20.0 aiosqlite==0.20.0
typer==0.12.3 typer==0.12.3
aiofiles==23.2.1

View File

@@ -1 +1,3 @@
from .games import router as games_router from .games import router as games_router
from .files import router as files_router
from .startup import router as startup_router

20
routes/files.py Normal file
View File

@@ -0,0 +1,20 @@
from fastapi import APIRouter, Depends, HTTPException, UploadFile
from database import *
from file_handler import *
router = APIRouter(prefix="/files", tags=["Files"])
@router.post("/torrent", response_model=str)
async def upload_torrent(torrent: UploadFile):
try: return await save_torrent_file(torrent)
except Exception as ex:
print(ex)
raise HTTPException(500)
@router.post("/cover", response_model=str)
async def upload_cover(cover: UploadFile):
try: return await save_image(cover, "cover")
except Exception as ex:
print(ex)
raise HTTPException(500)

View File

@@ -1,6 +1,7 @@
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException, UploadFile
from database import * from database import *
from file_handler import *
router = APIRouter(prefix="/games", tags=["Games"]) router = APIRouter(prefix="/games", tags=["Games"])
@@ -14,7 +15,13 @@ async def get_game(game_id: int, db: AsyncSession = Depends(get_session)):
return await crud.get_game(db, game_id) return await crud.get_game(db, game_id)
@router.post("/", response_model=Game) @router.post("/", response_model=Game)
async def add_game(game: GameCreate, user_id: int, db:AsyncSession = Depends(get_session)): async def add_game(game: GameCreate,
try: return await crud.add_game(db, game, user_id) user_id: int,
except Exception as ex: raise HTTPException(500) db:AsyncSession = Depends(get_session)):
try:
torrent_filename = save_torrent_file(torrent, game.title)
cover_filename = save_image(cover, game.title, "cover")
return await crud.add_game(db, game, user_id)
except Exception as ex:
raise HTTPException(500)

16
routes/startup.py Normal file
View File

@@ -0,0 +1,16 @@
from fastapi import APIRouter
from pathlib import Path
router = APIRouter()
@router.on_event("startup")
def startup():
need_paths = [
Path() / "content" / "images" / "cover" / "full_size",
Path() / "content" / "images" / "cover" / "preview",
Path() / "content" / "images" / "screenshot" / "full_size",
Path() / "content" / "images" / "screenshot" / "preview",
Path() / "content" / "torrent"
]
for path in need_paths:
path.mkdir(parents=True, exist_ok=True)