bug/bug-fixes (#424)

* fix image write/caching

* Caddyfile Caching header

* more aggressive caching

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden 2021-05-23 15:05:39 -08:00 committed by GitHub
parent eb3d56936e
commit 503fe5cb2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 44 additions and 34 deletions

View file

@ -5,12 +5,18 @@
:80 { :80 {
@proxied path /api/* /docs /openapi.json @proxied path /api/* /docs /openapi.json
@static {
file
path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff *.woff2 *.webp
}
encode gzip zstd encode gzip zstd
uri strip_suffix / uri strip_suffix /
# Handles Recipe Images / Assets # Handles Recipe Images / Assets
handle_path /api/media/recipes/* { handle_path /api/media/recipes/* {
header @static Cache-Control max-age=31536000
root * /app/data/recipes/ root * /app/data/recipes/
file_server file_server
} }
@ -20,6 +26,7 @@
} }
handle { handle {
header @static Cache-Control max-age=31536000
root * /app/dist root * /app/dist
try_files {path}.html {path} /index.html try_files {path}.html {path} /index.html
file_server file_server

View file

@ -146,16 +146,16 @@ export const recipeAPI = {
return response.data; return response.data;
}, },
recipeImage(recipeSlug) { recipeImage(recipeSlug, version = null, key = null) {
return `/api/media/recipes/${recipeSlug}/images/original.webp`; return `/api/media/recipes/${recipeSlug}/images/original.webp?&rnd=${key}&version=${version}`;
}, },
recipeSmallImage(recipeSlug) { recipeSmallImage(recipeSlug, version = null, key = null) {
return `/api/media/recipes/${recipeSlug}/images/min-original.webp`; return `/api/media/recipes/${recipeSlug}/images/min-original.webp?&rnd=${key}&version=${version}`;
}, },
recipeTinyImage(recipeSlug) { recipeTinyImage(recipeSlug, version = null, key = null) {
return `/api/media/recipes/${recipeSlug}/images/tiny-original.webp`; return `/api/media/recipes/${recipeSlug}/images/tiny-original.webp?&rnd=${key}&version=${version}`;
}, },
recipeAssetPath(recipeSlug, assetName) { recipeAssetPath(recipeSlug, assetName) {

View file

@ -209,10 +209,6 @@ export default {
} }
}, },
getImage(image) {
return api.recipes.recipeSmallImage(image);
},
formatDate(date) { formatDate(date) {
if (!date) return null; if (!date) return null;

View file

@ -42,6 +42,9 @@ export default {
slug: { slug: {
default: null, default: null,
}, },
imageVersion: {
default: null,
},
height: { height: {
default: 200, default: 200,
}, },
@ -65,14 +68,14 @@ export default {
}; };
}, },
methods: { methods: {
getImage(image) { getImage(slug) {
switch (this.imageSize) { switch (this.imageSize) {
case "tiny": case "tiny":
return api.recipes.recipeTinyImage(image); return api.recipes.recipeTinyImage(slug, this.imageVersion);
case "small": case "small":
return api.recipes.recipeSmallImage(image); return api.recipes.recipeSmallImage(slug, this.imageVersion);
case "large": case "large":
return api.recipes.recipeImage(image); return api.recipes.recipeImage(slug, this.imageVersion);
} }
}, },
}, },

View file

@ -59,8 +59,8 @@ export default {
}; };
}, },
methods: { methods: {
getImage(image) { getImage(slug) {
return api.recipes.recipeSmallImage(image); return api.recipes.recipeSmallImage(slug, this.image);
}, },
}, },
}; };

View file

@ -7,7 +7,7 @@
@click="$emit('click')" @click="$emit('click')"
min-height="275" min-height="275"
> >
<CardImage icon-size="200" :slug="slug"> <CardImage icon-size="200" :slug="slug" :image-version="image">
<v-expand-transition v-if="description"> <v-expand-transition v-if="description">
<div v-if="hover" class="d-flex transition-fast-in-fast-out secondary v-card--reveal " style="height: 100%;"> <div v-if="hover" class="d-flex transition-fast-in-fast-out secondary v-card--reveal " style="height: 100%;">
<v-card-text class="v-card--text-show white--text"> <v-card-text class="v-card--text-show white--text">
@ -65,8 +65,8 @@ export default {
}; };
}, },
methods: { methods: {
getImage(image) { getImage(slug) {
return api.recipes.recipeSmallImage(image); return api.recipes.recipeSmallImage(slug, this.image);
}, },
}, },
}; };

View file

@ -155,9 +155,9 @@ export default {
this.recipeDetails = await api.recipes.requestDetails(this.currentRecipe); this.recipeDetails = await api.recipes.requestDetails(this.currentRecipe);
this.skeleton = false; this.skeleton = false;
}, },
getImage(image) { getImage(slug) {
if (image) { if (slug) {
return api.recipes.recipeImage(image) + "?&rnd=" + this.imageKey; return api.recipes.recipeImage(slug, this.imageKey, this.recipeDetails.image);
} }
}, },
async deleteRecipe() { async deleteRecipe() {
@ -175,7 +175,9 @@ export default {
}, },
async saveImage(overrideSuccessMsg = false) { async saveImage(overrideSuccessMsg = false) {
if (this.fileObject) { if (this.fileObject) {
if (api.recipes.updateImage(this.recipeDetails.slug, this.fileObject, overrideSuccessMsg)) { const newVersion = await api.recipes.updateImage(this.recipeDetails.slug, this.fileObject, overrideSuccessMsg);
if (newVersion) {
this.recipeDetails.image = newVersion.data.version;
this.imageKey += 1; this.imageKey += 1;
} }
} }
@ -192,6 +194,7 @@ export default {
if (slug != this.recipeDetails.slug) { if (slug != this.recipeDetails.slug) {
this.$router.push(`/recipe/${slug}`); this.$router.push(`/recipe/${slug}`);
} }
window.URL.revokeObjectURL(this.getImage(this.recipeDetails.slug));
} }
}, },
printPage() { printPage() {

View file

@ -1,4 +1,5 @@
from logging import getLogger from logging import getLogger
from random import randint
from mealie.db.db_base import BaseDocument from mealie.db.db_base import BaseDocument
from mealie.db.models.event import Event, EventNotification from mealie.db.models.event import Event, EventNotification
@ -34,10 +35,10 @@ class _Recipes(BaseDocument):
def update_image(self, session: Session, slug: str, extension: str = None) -> str: def update_image(self, session: Session, slug: str, extension: str = None) -> str:
entry: RecipeModel = self._query_one(session, match_value=slug) entry: RecipeModel = self._query_one(session, match_value=slug)
entry.image = f"{slug}.{extension}" entry.image = randint(0, 255)
session.commit() session.commit()
return f"{slug}.{extension}" return entry.image
def count_uncategorized(self, session: Session, count=True, override_schema=None) -> int: def count_uncategorized(self, session: Session, count=True, override_schema=None) -> int:
return self._count_attribute( return self._count_attribute(

View file

@ -128,19 +128,18 @@ def delete_recipe(
raise HTTPException(status.HTTP_400_BAD_REQUEST) raise HTTPException(status.HTTP_400_BAD_REQUEST)
@router.put("/{recipe_slug}/image") @router.put("/{recipe_slug}/image", dependencies=[Depends(get_current_user)])
def update_recipe_image( def update_recipe_image(
recipe_slug: str, recipe_slug: str,
image: bytes = File(...), image: bytes = File(...),
extension: str = Form(...), extension: str = Form(...),
session: Session = Depends(generate_session), session: Session = Depends(generate_session),
current_user=Depends(get_current_user),
): ):
""" Removes an existing image and replaces it with the incoming file. """ """ Removes an existing image and replaces it with the incoming file. """
response = write_image(recipe_slug, image, extension) write_image(recipe_slug, image, extension)
db.recipes.update_image(session, recipe_slug, extension) new_version = db.recipes.update_image(session, recipe_slug, extension)
return response return {"image": new_version}
@router.post("/{recipe_slug}/image") @router.post("/{recipe_slug}/image")

View file

@ -36,7 +36,7 @@ def write_image(recipe_slug: str, file_data: bytes, extension: str) -> Path:
shutil.copyfileobj(file_data, f) shutil.copyfileobj(file_data, f)
print(image_path) print(image_path)
minify.minify_image(image_path) minify.minify_image(image_path, force=True)
return image_path return image_path

View file

@ -21,7 +21,7 @@ def get_image_sizes(org_img: Path, min_img: Path, tiny_img: Path) -> ImageSizes:
return ImageSizes(org=sizeof_fmt(org_img), min=sizeof_fmt(min_img), tiny=sizeof_fmt(tiny_img)) return ImageSizes(org=sizeof_fmt(org_img), min=sizeof_fmt(min_img), tiny=sizeof_fmt(tiny_img))
def minify_image(image_file: Path) -> ImageSizes: def minify_image(image_file: Path, force=False) -> ImageSizes:
"""Minifies an image in it's original file format. Quality is lost """Minifies an image in it's original file format. Quality is lost
Args: Args:
@ -39,7 +39,7 @@ def minify_image(image_file: Path) -> ImageSizes:
min_dest = image_file.parent.joinpath("min-original.webp") min_dest = image_file.parent.joinpath("min-original.webp")
tiny_dest = image_file.parent.joinpath("tiny-original.webp") tiny_dest = image_file.parent.joinpath("tiny-original.webp")
if min_dest.exists() and tiny_dest.exists() and org_dest.exists(): if min_dest.exists() and tiny_dest.exists() and org_dest.exists() and not force:
return return
try: try:
img = Image.open(image_file) img = Image.open(image_file)
@ -56,7 +56,8 @@ def minify_image(image_file: Path) -> ImageSizes:
cleanup_images = True cleanup_images = True
except Exception: except Exception as e:
logger.error(e)
shutil.copy(image_file, min_dest) shutil.copy(image_file, min_dest)
shutil.copy(image_file, tiny_dest) shutil.copy(image_file, tiny_dest)