move images to /recipes/{slug}/images

This commit is contained in:
hay-kot 2021-05-02 14:22:00 -08:00
commit 0a6a29a004
15 changed files with 121 additions and 128 deletions

View file

@ -10,8 +10,8 @@
encode gzip encode gzip
uri strip_suffix / uri strip_suffix /
handle_path /api/recipes/image/* { handle_path /api/recipes/media/* {
root * /app/data/img/ root * /app/data/recipes/
file_server file_server
} }

View file

@ -14,9 +14,9 @@ const recipeURLs = {
recipe: slug => prefix + slug, recipe: slug => prefix + slug,
update: slug => prefix + slug, update: slug => prefix + slug,
delete: slug => prefix + slug, delete: slug => prefix + slug,
createAsset: slug => `${prefix}media/${slug}/assets`,
recipeImage: slug => `${prefix}${slug}/image`, recipeImage: slug => `${prefix}${slug}/image`,
updateImage: slug => `${prefix}${slug}/image`, updateImage: slug => `${prefix}${slug}/image`,
createAsset: slug => `${prefix}${slug}/asset`,
}; };
export const recipeAPI = { export const recipeAPI = {
@ -84,7 +84,7 @@ export const recipeAPI = {
fd.append("extension", fileObject.name.split(".").pop()); fd.append("extension", fileObject.name.split(".").pop());
fd.append("name", name); fd.append("name", name);
fd.append("icon", icon); fd.append("icon", icon);
let response = apiReq.post(recipeURLs.createAsset(recipeSlug), fd); const response = apiReq.post(recipeURLs.createAsset(recipeSlug), fd);
return response; return response;
}, },
@ -135,14 +135,14 @@ export const recipeAPI = {
}, },
recipeImage(recipeSlug) { recipeImage(recipeSlug) {
return `/api/recipes/image/${recipeSlug}/original.webp`; return `/api/recipes/media/${recipeSlug}/image/original.webp`;
}, },
recipeSmallImage(recipeSlug) { recipeSmallImage(recipeSlug) {
return `/api/recipes/image/${recipeSlug}/min-original.webp`; return `/api/recipes/media/${recipeSlug}/image/min-original.webp`;
}, },
recipeTinyImage(recipeSlug) { recipeTinyImage(recipeSlug) {
return `/api/recipes/image/${recipeSlug}/tiny-original.webp`; return `/api/recipes/media/${recipeSlug}/image/tiny-original.webp`;
}, },
}; };

View file

@ -18,7 +18,7 @@
v-if="!edit" v-if="!edit"
color="primary" color="primary"
icon icon
:href="`/api/recipes/${slug}/asset?file_name=${item.fileName}`" :href="`/api/recipes/media/${slug}/assets/${item.fileName}`"
target="_blank" target="_blank"
top top
> >
@ -135,7 +135,7 @@ export default {
this.value.splice(index, 1); this.value.splice(index, 1);
}, },
copyLink(name, fileName) { copyLink(name, fileName) {
const copyText = `![${name}](${this.baseURL}/api/recipes/${this.slug}/assets/${fileName})`; const copyText = `![${name}](${this.baseURL}/api/recipes/media/${this.slug}/assets/${fileName})`;
navigator.clipboard.writeText(copyText).then( navigator.clipboard.writeText(copyText).then(
() => console.log("Copied", copyText), () => console.log("Copied", copyText),
() => console.log("Copied Failed", copyText) () => console.log("Copied Failed", copyText)

View file

@ -3,6 +3,7 @@ import shutil
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status
from mealie.core.config import app_dirs from mealie.core.config import app_dirs
from mealie.core.root_logger import get_logger
from mealie.core.security import create_file_token from mealie.core.security import create_file_token
from mealie.db.db_setup import generate_session from mealie.db.db_setup import generate_session
from mealie.routes.deps import get_current_user from mealie.routes.deps import get_current_user
@ -12,6 +13,7 @@ from mealie.services.backups.exports import backup_all
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
router = APIRouter(prefix="/api/backups", tags=["Backups"], dependencies=[Depends(get_current_user)]) router = APIRouter(prefix="/api/backups", tags=["Backups"], dependencies=[Depends(get_current_user)])
logger = get_logger()
@router.get("/available", response_model=Imports) @router.get("/available", response_model=Imports)
@ -44,7 +46,8 @@ def export_database(data: BackupJob, session: Session = Depends(generate_session
export_groups=data.options.groups, export_groups=data.options.groups,
) )
return {"export_path": export_path} return {"export_path": export_path}
except Exception: except Exception as e:
logger.error(e)
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR) raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)

View file

@ -88,7 +88,7 @@ def get_todays_image(session: Session = Depends(generate_session), group_name: s
recipe = get_todays_meal(session, group_in_db) recipe = get_todays_meal(session, group_in_db)
if recipe: if recipe:
recipe_image = image.read_image(recipe.slug, image_type=image.IMG_OPTIONS.ORIGINAL_IMAGE) recipe_image = recipe.image_dir.joinpath(image.ImageOptions.ORIGINAL_IMAGE)
else: else:
raise HTTPException(status.HTTP_404_NOT_FOUND) raise HTTPException(status.HTTP_404_NOT_FOUND)
if recipe_image: if recipe_image:

View file

@ -1,10 +1,10 @@
from fastapi import APIRouter from fastapi import APIRouter
from mealie.routes.recipe import all_recipe_routes, category_routes, recipe_assets, recipe_crud_routes, tag_routes from mealie.routes.recipe import all_recipe_routes, category_routes, recipe_crud_routes, recipe_media, tag_routes
router = APIRouter() router = APIRouter()
router.include_router(all_recipe_routes.router) router.include_router(all_recipe_routes.router)
router.include_router(recipe_crud_routes.router) router.include_router(recipe_crud_routes.router)
router.include_router(recipe_assets.router) router.include_router(recipe_media.router)
router.include_router(category_routes.router) router.include_router(category_routes.router)
router.include_router(tag_routes.router) router.include_router(tag_routes.router)

View file

@ -4,7 +4,8 @@ from mealie.db.database import db
from mealie.db.db_setup import generate_session from mealie.db.db_setup import generate_session
from mealie.routes.deps import get_current_user from mealie.routes.deps import get_current_user
from mealie.schema.recipe import Recipe, RecipeURLIn from mealie.schema.recipe import Recipe, RecipeURLIn
from mealie.services.image.image import delete_image, rename_image, scrape_image, write_image from mealie.services.image.image import scrape_image, write_image
from mealie.services.recipe.asset import check_asset
from mealie.services.scraper.scraper import create_from_url from mealie.services.scraper.scraper import create_from_url
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
@ -58,7 +59,7 @@ def update_recipe(
print(recipe.assets) print(recipe.assets)
if recipe_slug != recipe.slug: if recipe_slug != recipe.slug:
rename_image(original_slug=recipe_slug, new_slug=recipe.slug) check_asset(original_slug=recipe_slug, recipe=recipe)
return recipe return recipe
@ -76,7 +77,7 @@ def patch_recipe(
session, recipe_slug, new_data=data.dict(exclude_unset=True, exclude_defaults=True) session, recipe_slug, new_data=data.dict(exclude_unset=True, exclude_defaults=True)
) )
if recipe_slug != recipe.slug: if recipe_slug != recipe.slug:
rename_image(original_slug=recipe_slug, new_slug=recipe.slug) check_asset(original_slug=recipe_slug, recipe=recipe)
return recipe return recipe
@ -91,7 +92,6 @@ def delete_recipe(
try: try:
delete_data = db.recipes.delete(session, recipe_slug) delete_data = db.recipes.delete(session, recipe_slug)
delete_image(recipe_slug)
return delete_data return delete_data
except Exception: except Exception:

View file

@ -3,7 +3,6 @@ from enum import Enum
from fastapi import APIRouter, Depends, File, Form, HTTPException, status from fastapi import APIRouter, Depends, File, Form, HTTPException, status
from fastapi.datastructures import UploadFile from fastapi.datastructures import UploadFile
from mealie.core.config import app_dirs
from mealie.db.database import db from mealie.db.database import db
from mealie.db.db_setup import generate_session from mealie.db.db_setup import generate_session
from mealie.routes.deps import get_current_user from mealie.routes.deps import get_current_user
@ -12,7 +11,7 @@ from slugify import slugify
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from starlette.responses import FileResponse from starlette.responses import FileResponse
router = APIRouter(prefix="/api/recipes", tags=["Recipe Media"]) router = APIRouter(prefix="/api/recipes/media", tags=["Recipe Media"])
class ImageType(str, Enum): class ImageType(str, Enum):
@ -21,11 +20,12 @@ class ImageType(str, Enum):
tiny = "tiny-original.webp" tiny = "tiny-original.webp"
@router.get("/image/{recipe_slug}/{file_name}") @router.get("/{recipe_slug}/image/{file_name}")
async def get_recipe_img(recipe_slug: str, file_name: ImageType = ImageType.original): async def get_recipe_img(recipe_slug: str, file_name: ImageType = ImageType.original):
"""Takes in a recipe slug, returns the static image. This route is proxied in the docker image """Takes in a recipe slug, returns the static image. This route is proxied in the docker image
and should not hit the API in production""" and should not hit the API in production"""
recipe_image = app_dirs.IMG_DIR.joinpath(recipe_slug, file_name.value) recipe_image = Recipe(slug=recipe_slug).image_dir.joinpath(file_name.value)
if recipe_image: if recipe_image:
return FileResponse(recipe_image) return FileResponse(recipe_image)
else: else:
@ -33,13 +33,17 @@ async def get_recipe_img(recipe_slug: str, file_name: ImageType = ImageType.orig
@router.get("/{recipe_slug}/assets/{file_name}") @router.get("/{recipe_slug}/assets/{file_name}")
async def get_recipe_asset(recipe_slug, file_name: str): async def get_recipe_asset(recipe_slug: str, file_name: str):
""" Returns a recipe asset """ """ Returns a recipe asset """
file = app_dirs.RECIPE_DATA_DIR.joinpath(recipe_slug, file_name) file = Recipe(slug=recipe_slug).asset_dir.joinpath(file_name)
return FileResponse(file)
try:
return FileResponse(file)
except Exception:
raise HTTPException(status.HTTP_404_NOT_FOUND)
@router.post("/{recipe_slug}/asset", response_model=RecipeAsset) @router.post("/{recipe_slug}/assets", response_model=RecipeAsset)
def upload_recipe_asset( def upload_recipe_asset(
recipe_slug: str, recipe_slug: str,
name: str = Form(...), name: str = Form(...),
@ -52,8 +56,7 @@ def upload_recipe_asset(
""" Upload a file to store as a recipe asset """ """ Upload a file to store as a recipe asset """
file_name = slugify(name) + "." + extension file_name = slugify(name) + "." + extension
asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name) asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name)
dest = app_dirs.RECIPE_DATA_DIR.joinpath(recipe_slug, file_name) dest = Recipe(slug=recipe_slug).asset_dir.joinpath(file_name)
dest.parent.mkdir(exist_ok=True, parents=True)
with dest.open("wb") as buffer: with dest.open("wb") as buffer:
shutil.copyfileobj(file.file, buffer) shutil.copyfileobj(file.file, buffer)

View file

@ -1,7 +1,9 @@
import datetime import datetime
from pathlib import Path
from typing import Any, Optional from typing import Any, Optional
from fastapi_camelcase import CamelModel from fastapi_camelcase import CamelModel
from mealie.core.config import app_dirs
from mealie.db.models.recipe.recipe import RecipeModel from mealie.db.models.recipe.recipe import RecipeModel
from pydantic import BaseModel, Field, validator from pydantic import BaseModel, Field, validator
from pydantic.utils import GetterDict from pydantic.utils import GetterDict
@ -58,8 +60,8 @@ class Nutrition(CamelModel):
class RecipeSummary(CamelModel): class RecipeSummary(CamelModel):
id: Optional[int] id: Optional[int]
name: str name: Optional[str]
slug: Optional[str] = "" slug: str = ""
image: Optional[Any] image: Optional[Any]
description: Optional[str] description: Optional[str]
@ -98,6 +100,28 @@ class Recipe(RecipeSummary):
org_url: Optional[str] = Field(None, alias="orgURL") org_url: Optional[str] = Field(None, alias="orgURL")
extras: Optional[dict] = {} extras: Optional[dict] = {}
@staticmethod
def directory_from_slug(slug) -> Path:
return app_dirs.RECIPE_DATA_DIR.joinpath(slug)
@property
def directory(self) -> Path:
dir = app_dirs.RECIPE_DATA_DIR.joinpath(self.slug)
dir.mkdir(exist_ok=True, parents=True)
return dir
@property
def asset_dir(self) -> Path:
dir = self.directory.joinpath("assets")
dir.mkdir(exist_ok=True, parents=True)
return dir
@property
def image_dir(self) -> Path:
dir = self.directory.joinpath("images")
dir.mkdir(exist_ok=True, parents=True)
return dir
class Config: class Config:
orm_mode = True orm_mode = True
@ -140,6 +164,8 @@ class Recipe(RecipeSummary):
@validator("slug", always=True, pre=True) @validator("slug", always=True, pre=True)
def validate_slug(slug: str, values): def validate_slug(slug: str, values):
if not values["name"]:
return slug
name: str = values["name"] name: str = values["name"]
calc_slug: str = slugify(name) calc_slug: str = slugify(name)

View file

@ -32,7 +32,7 @@ class ExportDatabase:
export_tag = datetime.now().strftime("%Y-%b-%d") export_tag = datetime.now().strftime("%Y-%b-%d")
self.main_dir = app_dirs.TEMP_DIR.joinpath(export_tag) self.main_dir = app_dirs.TEMP_DIR.joinpath(export_tag)
self.img_dir = self.main_dir.joinpath("images") self.recipes = self.main_dir.joinpath("recipes")
self.templates_dir = self.main_dir.joinpath("templates") self.templates_dir = self.main_dir.joinpath("templates")
try: try:
@ -43,7 +43,7 @@ class ExportDatabase:
required_dirs = [ required_dirs = [
self.main_dir, self.main_dir,
self.img_dir, self.recipes,
self.templates_dir, self.templates_dir,
] ]
@ -67,10 +67,10 @@ class ExportDatabase:
with open(out_file, "w") as f: with open(out_file, "w") as f:
f.write(content) f.write(content)
def export_images(self): def export_recipe_dirs(self):
shutil.copytree(app_dirs.IMG_DIR, self.img_dir, dirs_exist_ok=True) shutil.copytree(app_dirs.RECIPE_DATA_DIR, self.recipes, dirs_exist_ok=True)
def export_items(self, items: list[BaseModel], folder_name: str, export_list=True): def export_items(self, items: list[BaseModel], folder_name: str, export_list=True, slug_folder=False):
items = [x.dict() for x in items] items = [x.dict() for x in items]
out_dir = self.main_dir.joinpath(folder_name) out_dir = self.main_dir.joinpath(folder_name)
out_dir.mkdir(parents=True, exist_ok=True) out_dir.mkdir(parents=True, exist_ok=True)
@ -79,8 +79,9 @@ class ExportDatabase:
ExportDatabase._write_json_file(items, out_dir.joinpath(f"{folder_name}.json")) ExportDatabase._write_json_file(items, out_dir.joinpath(f"{folder_name}.json"))
else: else:
for item in items: for item in items:
filename = sanitize_filename(f"{item.get('name')}.json") final_dest = out_dir if not slug_folder else out_dir.joinpath(item.get("slug"))
ExportDatabase._write_json_file(item, out_dir.joinpath(filename)) filename = sanitize_filename(f"{item.get('slug')}.json")
ExportDatabase._write_json_file(item, final_dest.joinpath(filename))
@staticmethod @staticmethod
def _write_json_file(data: Union[dict, list], out_file: Path): def _write_json_file(data: Union[dict, list], out_file: Path):
@ -121,9 +122,9 @@ def backup_all(
if export_recipes: if export_recipes:
all_recipes = db.recipes.get_all(session) all_recipes = db.recipes.get_all(session)
db_export.export_items(all_recipes, "recipes", export_list=False) db_export.export_recipe_dirs()
db_export.export_items(all_recipes, "recipes", export_list=False, slug_folder=True)
db_export.export_templates(all_recipes) db_export.export_templates(all_recipes)
db_export.export_images()
if export_settings: if export_settings:
all_settings = db.settings.get_all(session) all_settings = db.settings.get_all(session)

View file

@ -2,7 +2,7 @@ import json
import shutil import shutil
import zipfile import zipfile
from pathlib import Path from pathlib import Path
from typing import Callable, List from typing import Callable
from mealie.core.config import app_dirs from mealie.core.config import app_dirs
from mealie.db.database import db from mealie.db.database import db
@ -49,7 +49,7 @@ class ImportDatabase:
def import_recipes(self): def import_recipes(self):
recipe_dir: Path = self.import_dir.joinpath("recipes") recipe_dir: Path = self.import_dir.joinpath("recipes")
imports = [] imports = []
successful_imports = [] successful_imports = {}
recipes = ImportDatabase.read_models_file( recipes = ImportDatabase.read_models_file(
file_path=recipe_dir, model=Recipe, single_file=False, migrate=ImportDatabase._recipe_migration file_path=recipe_dir, model=Recipe, single_file=False, migrate=ImportDatabase._recipe_migration
@ -68,7 +68,7 @@ class ImportDatabase:
) )
if import_status.status: if import_status.status:
successful_imports.append(recipe.slug) successful_imports.update({recipe.slug: recipe})
imports.append(import_status) imports.append(import_status)
@ -105,15 +105,21 @@ class ImportDatabase:
return recipe_dict return recipe_dict
def _import_images(self, successful_imports: List[str]): def _import_images(self, successful_imports: list[Recipe]):
image_dir = self.import_dir.joinpath("images") image_dir = self.import_dir.joinpath("images")
for image in image_dir.iterdir():
if image.stem in successful_imports: if image_dir.exists():
if image.is_dir(): for image in image_dir.iterdir():
dest = app_dirs.IMG_DIR.joinpath(image.stem) item: Recipe = successful_imports.get(image.stem)
shutil.copytree(image, dest, dirs_exist_ok=True)
if image.is_file(): if item:
shutil.copy(image, app_dirs.IMG_DIR) dest_dir = item.image_dir
if image.is_dir():
shutil.copytree(image, dest_dir, dirs_exist_ok=True)
if image.is_file():
shutil.copy(image, dest_dir)
minify.migrate_images() minify.migrate_images()
@ -227,7 +233,7 @@ class ImportDatabase:
return [model(**g) for g in file_data] return [model(**g) for g in file_data]
all_models = [] all_models = []
for file in file_path.glob("*.json"): for file in file_path.glob("**/*.json"):
with open(file, "r") as f: with open(file, "r") as f:
file_data = json.loads(f.read()) file_data = json.loads(f.read())

View file

@ -4,7 +4,7 @@ from pathlib import Path
import requests import requests
from mealie.core import root_logger from mealie.core import root_logger
from mealie.core.config import app_dirs from mealie.schema.recipe import Recipe
from mealie.services.image import minify from mealie.services.image import minify
logger = root_logger.get_logger() logger = root_logger.get_logger()
@ -20,47 +20,11 @@ class ImageOptions:
IMG_OPTIONS = ImageOptions() IMG_OPTIONS = ImageOptions()
def read_image(recipe_slug: str, image_type: str = "original") -> Path:
"""returns the path to the image file for the recipe base of image_type
Args:
recipe_slug (str): Recipe Slug
image_type (str, optional): Glob Style Matcher "original*" | "min-original* | "tiny-original*"
Returns:
Path: [description]
"""
recipe_slug = recipe_slug.split(".")[0] # Incase of File Name
recipe_image_dir = app_dirs.IMG_DIR.joinpath(recipe_slug)
for file in recipe_image_dir.glob(image_type):
return file
return None
def rename_image(original_slug, new_slug) -> Path:
current_path = app_dirs.IMG_DIR.joinpath(original_slug)
new_path = app_dirs.IMG_DIR.joinpath(new_slug)
try:
new_path = current_path.rename(new_path)
except FileNotFoundError:
logger.error(f"Image Directory {original_slug} Doesn't Exist")
return new_path
def write_image(recipe_slug: str, file_data: bytes, extension: str) -> Path: def write_image(recipe_slug: str, file_data: bytes, extension: str) -> Path:
try: image_dir = Recipe(slug=recipe_slug).image_dir
delete_image(recipe_slug)
except Exception:
pass
image_dir = Path(app_dirs.IMG_DIR.joinpath(f"{recipe_slug}"))
image_dir.mkdir(exist_ok=True, parents=True)
extension = extension.replace(".", "") extension = extension.replace(".", "")
image_path = image_dir.joinpath(f"original.{extension}") image_path = image_dir.joinpath(f"original.{extension}")
image_path.unlink(missing_ok=True)
if isinstance(file_data, Path): if isinstance(file_data, Path):
shutil.copy2(file_data, image_path) shutil.copy2(file_data, image_path)
@ -77,12 +41,6 @@ def write_image(recipe_slug: str, file_data: bytes, extension: str) -> Path:
return image_path return image_path
def delete_image(recipe_slug: str) -> str:
recipe_slug = recipe_slug.split(".")[0]
for file in app_dirs.IMG_DIR.glob(f"{recipe_slug}*"):
return shutil.rmtree(file)
def scrape_image(image_url: str, slug: str) -> Path: def scrape_image(image_url: str, slug: str) -> Path:
if isinstance(image_url, str): # Handles String Types if isinstance(image_url, str): # Handles String Types
image_url = image_url image_url = image_url
@ -96,7 +54,7 @@ def scrape_image(image_url: str, slug: str) -> Path:
image_url = image_url.get("url") image_url = image_url.get("url")
filename = slug + "." + image_url.split(".")[-1] filename = slug + "." + image_url.split(".")[-1]
filename = app_dirs.IMG_DIR.joinpath(filename) filename = Recipe(slug=slug).image_dir.joinpath(filename)
try: try:
r = requests.get(image_url, stream=True) r = requests.get(image_url, stream=True)

View file

@ -4,10 +4,8 @@ from pathlib import Path
from mealie.core import root_logger from mealie.core import root_logger
from mealie.core.config import app_dirs from mealie.core.config import app_dirs
from mealie.db.database import db from mealie.schema.recipe import Recipe
from mealie.db.db_setup import create_session
from PIL import Image from PIL import Image
from sqlalchemy.orm.session import Session
logger = root_logger.get_logger() logger = root_logger.get_logger()
@ -20,11 +18,7 @@ class ImageSizes:
def get_image_sizes(org_img: Path, min_img: Path, tiny_img: Path) -> ImageSizes: def get_image_sizes(org_img: Path, min_img: Path, tiny_img: Path) -> ImageSizes:
return ImageSizes( return ImageSizes(org=sizeof_fmt(org_img), min=sizeof_fmt(min_img), tiny=sizeof_fmt(tiny_img))
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) -> ImageSizes:
@ -110,28 +104,9 @@ def move_all_images():
if new_file.is_file(): if new_file.is_file():
new_file.unlink() new_file.unlink()
image_file.rename(new_file) image_file.rename(new_file)
if image_file.is_dir():
slug = image_file.name
def validate_slugs_in_database(session: Session = None): image_file.rename(Recipe(slug=slug).image_dir)
def check_image_path(image_name: str, slug_path: str) -> bool:
existing_path: Path = app_dirs.IMG_DIR.joinpath(image_name)
slug_path: Path = app_dirs.IMG_DIR.joinpath(slug_path)
if existing_path.is_dir():
slug_path.rename(existing_path)
else:
logger.info("No Image Found")
session = session or create_session()
all_recipes = db.recipes.get_all(session)
slugs_and_images = [(x.slug, x.image) for x in all_recipes]
for slug, image in slugs_and_images:
image_slug = image.split(".")[0] # Remove Extension
if slug != image_slug:
logger.info(f"{slug}, Doesn't Match '{image_slug}'")
check_image_path(image, slug)
def migrate_images(): def migrate_images():
@ -139,7 +114,7 @@ def migrate_images():
move_all_images() move_all_images()
for image in app_dirs.IMG_DIR.glob("*/original.*"): for image in app_dirs.RECIPE_DATA_DIR.glob("**/original.*"):
minify_image(image) minify_image(image)
@ -148,4 +123,3 @@ def migrate_images():
if __name__ == "__main__": if __name__ == "__main__":
migrate_images() migrate_images()
validate_slugs_in_database()

View file

View file

@ -0,0 +1,22 @@
from pathlib import Path
from mealie.core.config import app_dirs
from mealie.core.root_logger import get_logger
from mealie.schema.recipe import Recipe
logger = get_logger()
def check_asset(original_slug, recipe: Recipe) -> Path:
if original_slug == recipe.slug:
return recipe.assets
current_dir = app_dirs.RECIPE_DATA_DIR.joinpath(original_slug)
try:
current_dir.rename(recipe.directory)
except FileNotFoundError:
logger.error(f"Recipe Directory not Found: {original_slug}")
logger.info(f"Renaming Recipe Directory: {original_slug} -> {recipe.slug}")
return current_dir.absolute()