Compare commits
No commits in common. "4f603d3cb1333e1df5de2d1cfe86e2e379d2be76" and "af08917155107e8890800b966a35943818f3123e" have entirely different histories.
4f603d3cb1
...
af08917155
5 changed files with 30 additions and 62 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 80
|
max-line-length = 80
|
||||||
extend-select = B950
|
select = C,E,F,W,B,B950
|
||||||
extend-ignore = E203,E501
|
extend-ignore = E203, E501
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
[settings]
|
|
||||||
profile = black
|
|
||||||
line_length = 80
|
|
||||||
|
|
@ -24,8 +24,6 @@ from .helpers import (
|
||||||
set_len,
|
set_len,
|
||||||
)
|
)
|
||||||
|
|
||||||
RE_NUM = re.compile(r"/(\d+)\.", flags=re.IGNORECASE)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_all_sorted_days(
|
async def get_all_sorted_days(
|
||||||
cal_cfg: CalendarConfig = Depends(get_calendar_config),
|
cal_cfg: CalendarConfig = Depends(get_calendar_config),
|
||||||
|
|
@ -111,10 +109,11 @@ async def get_all_manual_image_names(
|
||||||
Bilder: "manual" zuordnen
|
Bilder: "manual" zuordnen
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
num_re = re.compile(r"/(\d+)\.", flags=re.IGNORECASE)
|
||||||
return {
|
return {
|
||||||
int(num_match.group(1)): name
|
int(num_match.group(1)): name
|
||||||
for name in manual_image_names
|
for name in manual_image_names
|
||||||
if (num_match := RE_NUM.search(name)) is not None
|
if (num_match := num_re.search(name)) is not None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import base64
|
|
||||||
import itertools
|
import itertools
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
|
@ -6,9 +5,9 @@ from datetime import date, datetime, timedelta
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Any, Awaitable, Callable, Iterable, Self, Sequence, TypeVar
|
from typing import Any, Awaitable, Callable, Iterable, Self, Sequence, TypeVar
|
||||||
|
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
from PIL.Image import Image, Resampling
|
from PIL.Image import Image, Resampling
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
from .config import get_config
|
from .config import get_config
|
||||||
from .dav.webdav import WebDAV
|
from .dav.webdav import WebDAV
|
||||||
|
|
@ -116,51 +115,25 @@ async def load_image(file_name: str) -> Image:
|
||||||
return PILImage.open(BytesIO(await WebDAV.read_bytes(file_name)))
|
return PILImage.open(BytesIO(await WebDAV.read_bytes(file_name)))
|
||||||
|
|
||||||
|
|
||||||
class ImageData(BaseModel):
|
async def api_return_ico(img: Image) -> StreamingResponse:
|
||||||
width: int
|
|
||||||
height: int
|
|
||||||
aspect_ratio: float
|
|
||||||
data_url: str
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create(
|
|
||||||
cls,
|
|
||||||
*,
|
|
||||||
media_type: str,
|
|
||||||
content: BytesIO,
|
|
||||||
width: int,
|
|
||||||
height: int,
|
|
||||||
) -> Self:
|
|
||||||
img_data = base64.b64encode(content.getvalue()).decode("utf-8")
|
|
||||||
|
|
||||||
return cls(
|
|
||||||
width=width,
|
|
||||||
height=height,
|
|
||||||
aspect_ratio=width / height,
|
|
||||||
data_url=f"data:{media_type};base64,{img_data}",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def api_return_ico(img: Image) -> ImageData:
|
|
||||||
"""
|
"""
|
||||||
ICO-Bild mit API zurückgeben
|
ICO-Bild mit API zurückgeben
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ICO-Daten in Puffer speichern (256px)
|
# JPEG-Daten in Puffer speichern
|
||||||
img_buffer = BytesIO()
|
img_buffer = BytesIO()
|
||||||
img.resize(size=(256, 256), resample=Resampling.LANCZOS)
|
img.resize(size=(256, 256), resample=Resampling.LANCZOS)
|
||||||
img.save(img_buffer, format="ICO")
|
img.save(img_buffer, format="ICO")
|
||||||
|
img_buffer.seek(0)
|
||||||
|
|
||||||
# zurückgeben
|
# zurückgeben
|
||||||
return ImageData.create(
|
return StreamingResponse(
|
||||||
media_type="image/x-icon",
|
media_type="image/x-icon",
|
||||||
content=img_buffer,
|
content=img_buffer,
|
||||||
width=img.width,
|
|
||||||
height=img.height,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def api_return_jpeg(img: Image) -> ImageData:
|
async def api_return_jpeg(img: Image) -> StreamingResponse:
|
||||||
"""
|
"""
|
||||||
JPEG-Bild mit API zurückgeben
|
JPEG-Bild mit API zurückgeben
|
||||||
"""
|
"""
|
||||||
|
|
@ -168,13 +141,12 @@ async def api_return_jpeg(img: Image) -> ImageData:
|
||||||
# JPEG-Daten in Puffer speichern
|
# JPEG-Daten in Puffer speichern
|
||||||
img_buffer = BytesIO()
|
img_buffer = BytesIO()
|
||||||
img.save(img_buffer, format="JPEG", quality=85)
|
img.save(img_buffer, format="JPEG", quality=85)
|
||||||
|
img_buffer.seek(0)
|
||||||
|
|
||||||
# zurückgeben
|
# zurückgeben
|
||||||
return ImageData.create(
|
return StreamingResponse(
|
||||||
media_type="image/jpeg",
|
media_type="image/jpeg",
|
||||||
content=img_buffer,
|
content=img_buffer,
|
||||||
width=img.width,
|
|
||||||
height=img.height,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,25 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
from PIL.Image import Image
|
from PIL.Image import Image
|
||||||
|
|
||||||
from ..core.calendar_config import (
|
from ..core.calendar_config import CalendarConfig, DoorsSaved, get_calendar_config
|
||||||
CalendarConfig,
|
|
||||||
DoorsSaved,
|
|
||||||
get_calendar_config,
|
|
||||||
)
|
|
||||||
from ..core.config import Config, Site, get_config
|
from ..core.config import Config, Site, get_config
|
||||||
from ..core.depends import get_all_event_dates, get_day_image
|
from ..core.depends import get_all_event_dates, get_day_image
|
||||||
from ..core.helpers import (
|
from ..core.helpers import EventDates, api_return_ico, api_return_jpeg, load_image
|
||||||
EventDates,
|
|
||||||
ImageData,
|
|
||||||
api_return_ico,
|
|
||||||
api_return_jpeg,
|
|
||||||
load_image,
|
|
||||||
)
|
|
||||||
from ._security import user_can_view_day, user_is_admin, user_visible_days
|
from ._security import user_can_view_day, user_is_admin, user_visible_days
|
||||||
|
|
||||||
router = APIRouter(prefix="/user", tags=["user"])
|
router = APIRouter(prefix="/user", tags=["user"])
|
||||||
|
|
||||||
|
|
||||||
@router.get("/background_image")
|
@router.get(
|
||||||
|
"/background_image",
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
)
|
||||||
async def get_background_image(
|
async def get_background_image(
|
||||||
cal_cfg: CalendarConfig = Depends(get_calendar_config),
|
cal_cfg: CalendarConfig = Depends(get_calendar_config),
|
||||||
) -> ImageData:
|
) -> StreamingResponse:
|
||||||
"""
|
"""
|
||||||
Hintergrundbild laden
|
Hintergrundbild laden
|
||||||
"""
|
"""
|
||||||
|
|
@ -33,10 +27,13 @@ async def get_background_image(
|
||||||
return await api_return_jpeg(await load_image(f"files/{cal_cfg.background}"))
|
return await api_return_jpeg(await load_image(f"files/{cal_cfg.background}"))
|
||||||
|
|
||||||
|
|
||||||
@router.get("/favicon")
|
@router.get(
|
||||||
|
"/favicon",
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
)
|
||||||
async def get_favicon(
|
async def get_favicon(
|
||||||
cal_cfg: CalendarConfig = Depends(get_calendar_config),
|
cal_cfg: CalendarConfig = Depends(get_calendar_config),
|
||||||
) -> ImageData:
|
) -> StreamingResponse:
|
||||||
"""
|
"""
|
||||||
Favicon laden
|
Favicon laden
|
||||||
"""
|
"""
|
||||||
|
|
@ -71,12 +68,15 @@ async def get_doors(
|
||||||
return [door for door in cal_cfg.doors if door.day in visible_days]
|
return [door for door in cal_cfg.doors if door.day in visible_days]
|
||||||
|
|
||||||
|
|
||||||
@router.get("/image_{day}")
|
@router.get(
|
||||||
|
"/image_{day}",
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
)
|
||||||
async def get_image_for_day(
|
async def get_image_for_day(
|
||||||
user_can_view: bool = Depends(user_can_view_day),
|
user_can_view: bool = Depends(user_can_view_day),
|
||||||
is_admin: bool = Depends(user_is_admin),
|
is_admin: bool = Depends(user_is_admin),
|
||||||
image: Image | None = Depends(get_day_image),
|
image: Image | None = Depends(get_day_image),
|
||||||
) -> ImageData:
|
) -> StreamingResponse:
|
||||||
"""
|
"""
|
||||||
Bild für einen Tag erstellen
|
Bild für einen Tag erstellen
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue