mirror of
https://github.com/StepanovPlaton/torrent_backend.git
synced 2026-04-03 20:30:38 +04:00
Small fixes
This commit is contained in:
@@ -6,6 +6,7 @@ import database
|
|||||||
|
|
||||||
cli = typer.Typer()
|
cli = typer.Typer()
|
||||||
|
|
||||||
|
|
||||||
@cli.command(name="create")
|
@cli.command(name="create")
|
||||||
def create_database(): aiorun(database.create_all())
|
def create_database(): aiorun(database.create_all())
|
||||||
@cli.command(name="drop")
|
@cli.command(name="drop")
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
from .crud import *
|
from .crud import *
|
||||||
from .schemas import *
|
from .schemas import *
|
||||||
from .database import get_session, drop_all, create_all, recreate_all
|
from .database import get_session as get_session, \
|
||||||
|
drop_all as drop_all, \
|
||||||
|
create_all as create_all, \
|
||||||
|
recreate_all as recreate_all
|
||||||
from .crud import *
|
from .crud import *
|
||||||
@@ -1 +1 @@
|
|||||||
from .games import *
|
from .games import *
|
||||||
|
|||||||
@@ -5,14 +5,17 @@ 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,
|
async def add_game(db: AsyncSession,
|
||||||
|
game_info: sch.GameCreate,
|
||||||
user_id: int):
|
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)
|
||||||
|
|
||||||
|
|
||||||
async def get_games(db: AsyncSession):
|
async def get_games(db: AsyncSession):
|
||||||
return (await db.execute(select(mdl.Game))).scalars().all()
|
return (await db.execute(select(mdl.Game))).scalars().all()
|
||||||
|
|
||||||
|
|
||||||
async def get_game(db: AsyncSession, game_id: int):
|
async def get_game(db: AsyncSession, game_id: int):
|
||||||
return await db.get(mdl.Game, game_id)
|
return await db.get(mdl.Game, game_id)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.ext.asyncio import create_async_engine
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||||
|
|
||||||
DATABASE_URL = "sqlite+aiosqlite:///./dev_database.db"
|
DATABASE_URL = "sqlite+aiosqlite:///./dev_database.db"
|
||||||
# DATABASE_URL = "postgresql://user:password@postgresserver/db"
|
# DATABASE_URL = "postgresql://user:password@postgresserver/db"
|
||||||
@@ -9,27 +8,31 @@ DATABASE_URL = "sqlite+aiosqlite:///./dev_database.db"
|
|||||||
engine = create_async_engine(
|
engine = create_async_engine(
|
||||||
DATABASE_URL, connect_args={"check_same_thread": False}, echo=True
|
DATABASE_URL, connect_args={"check_same_thread": False}, echo=True
|
||||||
)
|
)
|
||||||
async_session = sessionmaker(
|
async_session = sessionmaker( # type: ignore
|
||||||
engine, class_=AsyncSession, expire_on_commit=False)
|
engine, class_=AsyncSession, expire_on_commit=False) # type: ignore
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
async def get_session() -> AsyncSession: # type: ignore
|
async def get_session() -> AsyncSession: # type: ignore
|
||||||
# Dependency
|
|
||||||
async with async_session() as session: # type: ignore
|
async with async_session() as session: # type: ignore
|
||||||
yield session
|
yield session
|
||||||
|
|
||||||
|
|
||||||
async def drop_all():
|
async def drop_all():
|
||||||
async with engine.begin() as conn:
|
async with engine.begin() as conn:
|
||||||
await conn.run_sync(Base.metadata.drop_all)
|
await conn.run_sync(Base.metadata.drop_all)
|
||||||
|
|
||||||
|
|
||||||
async def create_all():
|
async def create_all():
|
||||||
async with engine.begin() as conn:
|
async with engine.begin() as conn:
|
||||||
await conn.run_sync(Base.metadata.create_all)
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
|
|
||||||
|
|
||||||
async def recreate_all():
|
async def recreate_all():
|
||||||
await drop_all()
|
await drop_all()
|
||||||
await create_all()
|
await create_all()
|
||||||
|
|
||||||
|
|
||||||
async def add_transaction[T](db: AsyncSession, entity: T) -> T:
|
async def add_transaction[T](db: AsyncSession, entity: T) -> T:
|
||||||
try:
|
try:
|
||||||
db.add(entity)
|
db.add(entity)
|
||||||
@@ -38,4 +41,4 @@ async def add_transaction[T](db: AsyncSession, entity: T) -> T:
|
|||||||
return entity
|
return entity
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
await db.rollback()
|
await db.rollback()
|
||||||
raise ex
|
raise ex
|
||||||
|
|||||||
@@ -7,36 +7,51 @@ import aiofiles
|
|||||||
from fastapi import UploadFile
|
from fastapi import UploadFile
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
def create_hash_name(filename: str):
|
def create_hash_name(filename: str):
|
||||||
return str(hashlib.sha1(filename.encode()).hexdigest())
|
return str(hashlib.sha1(filename.encode()).hexdigest())
|
||||||
|
|
||||||
|
|
||||||
async def save_torrent_file(torrent: UploadFile):
|
async def save_torrent_file(torrent: UploadFile):
|
||||||
|
if(torrent.filename is None): raise ValueError("Filename not found")
|
||||||
hash_filename = create_hash_name(torrent.filename)+".torrent"
|
hash_filename = create_hash_name(torrent.filename)+".torrent"
|
||||||
async with aiofiles.open(Path() / "content" / "torrent"
|
async with aiofiles.open(Path() / "content" / "torrent"
|
||||||
/ hash_filename, 'wb') as file:
|
/ hash_filename, 'wb') as file:
|
||||||
await file.write(await torrent.read())
|
torrent_data = await torrent.read()
|
||||||
|
if (isinstance(torrent_data, str)):
|
||||||
|
raise ValueError("Invalid torrent file")
|
||||||
|
await file.write(torrent_data)
|
||||||
return hash_filename
|
return hash_filename
|
||||||
|
|
||||||
|
|
||||||
async def save_image(cover: UploadFile, type: Literal["cover", "screenshot"]):
|
async def save_image(cover: UploadFile, type: Literal["cover", "screenshot"]):
|
||||||
hash_filename = create_hash_name(cover.filename) \
|
if(cover.filename is None): raise ValueError("Filename not found")
|
||||||
+ mimetypes.guess_extension(cover.content_type)
|
if(cover.content_type is None): raise ValueError("File content type unknown")
|
||||||
async with aiofiles.open(Path() / "content" / "images" / type / "full_size"
|
|
||||||
/ hash_filename, 'wb') as full_size_file, \
|
hash_filename = create_hash_name(cover.filename)
|
||||||
aiofiles.open(Path() / "content" / "images" / type /
|
file_extension = mimetypes.guess_extension(cover.content_type)
|
||||||
"preview" / hash_filename, 'wb') as preview_file:
|
if (file_extension is None): raise NameError("File extension not found")
|
||||||
|
else: hash_filename += file_extension
|
||||||
|
|
||||||
|
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()
|
cover_data = await cover.read()
|
||||||
|
if (isinstance(cover_data, str)):
|
||||||
|
raise ValueError("Invalid image file")
|
||||||
await full_size_file.write(cover_data)
|
await full_size_file.write(cover_data)
|
||||||
image = Image.open(BytesIO(cover_data))
|
image = Image.open(BytesIO(cover_data))
|
||||||
compressed_coefficient = (image.size[0] * image.size[1]) / (1280*720/4)
|
compressed_coefficient = (image.size[0] * image.size[1]) / (1280*720/4)
|
||||||
if(compressed_coefficient < 1): compressed_coefficient = 1
|
if (compressed_coefficient < 1):
|
||||||
|
compressed_coefficient = 1
|
||||||
compressed_image = image.resize(
|
compressed_image = image.resize(
|
||||||
( int(image.size[0] / compressed_coefficient),
|
(int(image.size[0] / compressed_coefficient),
|
||||||
int(image.size[1] / compressed_coefficient) )
|
int(image.size[1] / compressed_coefficient))
|
||||||
)
|
)
|
||||||
|
|
||||||
buf = BytesIO()
|
buf = BytesIO()
|
||||||
compressed_image.save(buf, format=
|
compressed_image.save(
|
||||||
cover.content_type.upper().replace("IMAGE/", ""))
|
buf, format=cover.content_type.upper().replace("IMAGE/", ""))
|
||||||
await preview_file.write(buf.getbuffer())
|
await preview_file.write(buf.getbuffer())
|
||||||
return hash_filename
|
return hash_filename
|
||||||
|
|
||||||
|
|||||||
6
main.py
6
main.py
@@ -1,5 +1,4 @@
|
|||||||
from fastapi import Depends, FastAPI, HTTPException
|
from fastapi import FastAPI
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
import cli_commands
|
import cli_commands
|
||||||
@@ -13,4 +12,5 @@ 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")
|
||||||
|
|
||||||
if(__name__ == "__main__"): cli()
|
if (__name__ == "__main__"):
|
||||||
|
cli()
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ 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
|
aiofiles==23.2.1
|
||||||
|
Pillow==10.3.0
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
from .games import router as games_router
|
from .games import games_router as games_router
|
||||||
from .files import router as files_router
|
from .files import files_router as files_router
|
||||||
from .startup import router as startup_router
|
from .startup import startup_router as startup_router
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, UploadFile
|
from fastapi import APIRouter, HTTPException, UploadFile
|
||||||
|
|
||||||
from database import *
|
from database import *
|
||||||
from file_handler import *
|
from file_handler import *
|
||||||
|
|
||||||
router = APIRouter(prefix="/files", tags=["Files"])
|
files_router = APIRouter(prefix="/files", tags=["Files"])
|
||||||
|
|
||||||
@router.post("/torrent", response_model=str)
|
|
||||||
|
@files_router.post("/torrent", response_model=str)
|
||||||
async def upload_torrent(torrent: UploadFile):
|
async def upload_torrent(torrent: UploadFile):
|
||||||
try: return await save_torrent_file(torrent)
|
try:
|
||||||
except Exception as ex:
|
return await save_torrent_file(torrent)
|
||||||
|
except Exception as ex:
|
||||||
print(ex)
|
print(ex)
|
||||||
raise HTTPException(500)
|
raise HTTPException(500)
|
||||||
|
|
||||||
@router.post("/cover", response_model=str)
|
|
||||||
|
@files_router.post("/cover", response_model=str)
|
||||||
async def upload_cover(cover: UploadFile):
|
async def upload_cover(cover: UploadFile):
|
||||||
try: return await save_image(cover, "cover")
|
try:
|
||||||
except Exception as ex:
|
return await save_image(cover, "cover")
|
||||||
|
except Exception as ex:
|
||||||
print(ex)
|
print(ex)
|
||||||
raise HTTPException(500)
|
raise HTTPException(500)
|
||||||
|
|||||||
@@ -1,27 +1,29 @@
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, UploadFile
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
|
||||||
from database import *
|
from database import *
|
||||||
from file_handler import *
|
from file_handler import *
|
||||||
|
|
||||||
router = APIRouter(prefix="/games", tags=["Games"])
|
games_router = APIRouter(prefix="/games", tags=["Games"])
|
||||||
|
|
||||||
@router.get("/", response_model=list[Game])
|
|
||||||
|
@games_router.get("/", response_model=list[Game])
|
||||||
async def get_games(db: AsyncSession = Depends(get_session)):
|
async def get_games(db: AsyncSession = Depends(get_session)):
|
||||||
try: return await crud.get_games(db)
|
try:
|
||||||
except Exception as ex: raise HTTPException(500)
|
return await crud.get_games(db)
|
||||||
|
except Exception:
|
||||||
|
raise HTTPException(500)
|
||||||
|
|
||||||
@router.get("/{game_id}", response_model=Game)
|
|
||||||
|
@games_router.get("/{game_id}", response_model=Game)
|
||||||
async def get_game(game_id: int, db: AsyncSession = Depends(get_session)):
|
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)
|
|
||||||
async def add_game(game: GameCreate,
|
@games_router.post("/", response_model=Game)
|
||||||
user_id: int,
|
async def add_game(game: GameCreate,
|
||||||
db:AsyncSession = Depends(get_session)):
|
user_id: int,
|
||||||
|
db: AsyncSession = Depends(get_session)):
|
||||||
try:
|
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)
|
return await crud.add_game(db, game, user_id)
|
||||||
except Exception as ex:
|
except Exception:
|
||||||
raise HTTPException(500)
|
raise HTTPException(500)
|
||||||
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
router = APIRouter()
|
startup_router = APIRouter()
|
||||||
|
|
||||||
@router.on_event("startup")
|
|
||||||
|
@startup_router.on_event("startup")
|
||||||
def startup():
|
def startup():
|
||||||
need_paths = [
|
need_paths = [
|
||||||
Path() / "content" / "images" / "cover" / "full_size",
|
Path() / "content" / "images" / "cover" / "full_size",
|
||||||
@@ -13,4 +14,4 @@ def startup():
|
|||||||
Path() / "content" / "torrent"
|
Path() / "content" / "torrent"
|
||||||
]
|
]
|
||||||
for path in need_paths:
|
for path in need_paths:
|
||||||
path.mkdir(parents=True, exist_ok=True)
|
path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user