import io import logging import re from typing import Iterator from fastapi import APIRouter, Depends, HTTPException, status from fastapi.responses import StreamingResponse from PIL import Image from webdav3.exceptions import RemoteResourceNotFound from .. import CLIENT from ..dav_file import DavFile _logger = logging.getLogger(__name__) router = APIRouter(prefix="/image", tags=["image"]) @router.on_event("startup") async def on_startup(): _logger.debug("image router started") _re_image_file = re.compile( r"\.(gif|jpe?g|tiff?|png|bmp)$", flags=re.IGNORECASE, ) async def get_image_file_names() -> Iterator[str]: try: file_names = CLIENT.list("img") return ( name for name in file_names if _re_image_file.search(name) ) except RemoteResourceNotFound: pass @router.get("/list", response_model=list[str]) async def list_images( image_file_names: Iterator[str] = Depends(get_image_file_names), ) -> list[str]: return list(image_file_names) async def find_file_names( prefix: str = "", image_file_names: Iterator[str] = Depends(get_image_file_names), ) -> Iterator[str]: return ( file_name for file_name in image_file_names if file_name.lower().startswith(prefix.lower()) ) @router.get("/find/{prefix}", response_model=list[str]) async def find_images( file_names: Iterator[str] = Depends(find_file_names), ) -> list[str]: return list(file_names) @router.get( "/get/{prefix}", responses={ status.HTTP_200_OK: { "description": "Operation successful", }, status.HTTP_404_NOT_FOUND: { "description": "image file not found", "content": None, }, status.HTTP_409_CONFLICT: { "description": "ambiguous image file name", "content": None, }, }, ) async def get_image( prefix: str, file_names: Iterator[str] = Depends(find_file_names), ) -> StreamingResponse: file_names = list(file_names) if not (file_names := list(file_names)): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) elif len(file_names) > 1: raise HTTPException(status_code=status.HTTP_409_CONFLICT) file_name = file_names[0] file = DavFile(CLIENT.resource(f"img/{file_name}"), refresh=False) await file.download() img = Image.open(io.BytesIO(file.bytes)).convert("RGB") img_buffer = io.BytesIO() img.save(img_buffer, format='JPEG', quality=85) img_buffer.seek(0) return StreamingResponse( img_buffer, media_type="image/jpeg", headers={ "Content-Disposition": f"filename={prefix}.jpg" }, )