Compare commits

..

8 Commits

Author SHA1 Message Date
mealie-commit-bot[bot]
70b5865dce chore: bump version to v3.9.2 2026-01-02 19:40:19 +00:00
Michael Genson
3be7056f2c fix: Exception handling for recipe image reprocessing (#6822) 2026-01-02 13:17:07 -06:00
Arsène Reymond
1b57310535 fix: allow start attribute on ordered lists (SafeMarkdown) (#6820)
Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
2026-01-02 19:02:11 +00:00
Patrick Lehner (he/him)
2b15d9a515 fix: Make quantity input in shopping list item editor visually consistent with other inputs (#6810) 2026-01-02 12:51:53 -06:00
Hayden
adc9c0b970 chore(l10n): New Crowdin updates (#6804) 2025-12-31 00:36:01 +00:00
renovate[bot]
bec1708891 chore(deps): update node.js to b52a8d1 (#6800)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-30 10:33:30 -06:00
Patrick Lehner (he/him)
66bb545454 dev: Small .gitignore fixes (#6796) 2025-12-30 15:42:38 +00:00
renovate[bot]
c1ebf04291 chore(deps): update node.js to 33587cf (#6795)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-30 05:20:34 +00:00
13 changed files with 56 additions and 58 deletions

5
.gitignore vendored
View File

@@ -70,8 +70,11 @@ wheels/
.installed.cfg .installed.cfg
*.egg *.egg
# packaged output - temporarily written here by `uv build`
/mealie-*
# frontend copied into Python module for packaging purposes # frontend copied into Python module for packaging purposes
/mealie/frontend/ /mealie/frontend
# PyInstaller # PyInstaller
# Usually these files are written by a python script from a template # Usually these files are written by a python script from a template

View File

@@ -1,7 +1,7 @@
############################################### ###############################################
# Frontend Build # Frontend Build
############################################### ###############################################
FROM node:24@sha256:20988bcdc6dc76690023eb2505dd273bdeefddcd0bde4bfd1efe4ebf8707f747 \ FROM node:24@sha256:b52a8d1206132b36d60e51e413d9a81336e8a0206d3b648cabd6d5a49c4c0f54 \
AS frontend-builder AS frontend-builder
WORKDIR /frontend WORKDIR /frontend

View File

@@ -31,7 +31,7 @@ To deploy mealie on your local network, it is highly recommended to use Docker t
We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do: We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do:
1. Take a backup just in case! 1. Take a backup just in case!
2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.9.1` 2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v3.9.2`
3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access. 3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access.
4. Restart the container 4. Restart the container

View File

@@ -10,7 +10,7 @@ PostgreSQL might be considered if you need to support many concurrent users. In
```yaml ```yaml
services: services:
mealie: mealie:
image: ghcr.io/mealie-recipes/mealie:v3.9.1 # (3) image: ghcr.io/mealie-recipes/mealie:v3.9.2 # (3)
container_name: mealie container_name: mealie
restart: always restart: always
ports: ports:

View File

@@ -11,7 +11,7 @@ SQLite is a popular, open source, self-contained, zero-configuration database th
```yaml ```yaml
services: services:
mealie: mealie:
image: ghcr.io/mealie-recipes/mealie:v3.9.1 # (3) image: ghcr.io/mealie-recipes/mealie:v3.9.2 # (3)
container_name: mealie container_name: mealie
restart: always restart: always
ports: ports:

View File

@@ -10,11 +10,8 @@
:label="$t('form.quantity-label-abbreviated')" :label="$t('form.quantity-label-abbreviated')"
:min="0" :min="0"
:precision="null" :precision="null"
variant="plain"
control-variant="stacked" control-variant="stacked"
inset inset
density="compact"
class="centered-number-input"
style="width: 100px;" style="width: 100px;"
/> />
</div> </div>
@@ -242,10 +239,3 @@ export default defineNuxtComponent({
}, },
}); });
</script> </script>
<style scoped>
.centered-number-input :deep(.v-field) {
display: flex;
align-items: center;
}
</style>

View File

@@ -31,7 +31,7 @@ export default defineNuxtComponent({
], ],
ALLOWED_ATTR: [ ALLOWED_ATTR: [
"href", "src", "alt", "height", "width", "class", "allow", "title", "allowfullscreen", "frameborder", "href", "src", "alt", "height", "width", "class", "allow", "title", "allowfullscreen", "frameborder",
"scrolling", "cite", "datetime", "name", "abbr", "target", "border", "scrolling", "cite", "datetime", "name", "abbr", "target", "border", "start",
], ],
}); });

View File

@@ -342,9 +342,9 @@
"breakfast": "Café da manhã", "breakfast": "Café da manhã",
"lunch": "Almoço", "lunch": "Almoço",
"dinner": "Jantar", "dinner": "Jantar",
"snack": "Snack", "snack": "Lanche",
"drink": "Drink", "drink": "Bebida",
"dessert": "Dessert", "dessert": "Sobremesa",
"type-any": "Qualquer", "type-any": "Qualquer",
"day-any": "Qualquer", "day-any": "Qualquer",
"editor": "Editor", "editor": "Editor",
@@ -445,7 +445,7 @@
"upload-a-recipe": "Enviar uma Receita", "upload-a-recipe": "Enviar uma Receita",
"upload-individual-zip-file": "Enviar um arquivo .zip individual exportado a partir de outra instância do Mealie.", "upload-individual-zip-file": "Enviar um arquivo .zip individual exportado a partir de outra instância do Mealie.",
"url-form-hint": "Copie e cole um link do seu site de receita favorito", "url-form-hint": "Copie e cole um link do seu site de receita favorito",
"copy-and-paste-the-source-url-of-your-data-optional": "Copy and paste the source URL of your data (optional)", "copy-and-paste-the-source-url-of-your-data-optional": "Copie e cole o URL de origem dos seus dados (opcional)",
"view-scraped-data": "Visualizar Dados Rastreados", "view-scraped-data": "Visualizar Dados Rastreados",
"trim-whitespace-description": "Aparar o espaço em branco e à direita, bem como linhas em branco", "trim-whitespace-description": "Aparar o espaço em branco e à direita, bem como linhas em branco",
"trim-prefix-description": "Aparar primeiro caractere de cada linha", "trim-prefix-description": "Aparar primeiro caractere de cada linha",
@@ -637,8 +637,8 @@
"scrape-recipe-suggest-bulk-importer": "Tente o importador em massa", "scrape-recipe-suggest-bulk-importer": "Tente o importador em massa",
"scrape-recipe-have-raw-html-or-json-data": "Tem dados HTML ou JSON brutos?", "scrape-recipe-have-raw-html-or-json-data": "Tem dados HTML ou JSON brutos?",
"scrape-recipe-you-can-import-from-raw-data-directly": "Você pode importar diretamente de dados brutos", "scrape-recipe-you-can-import-from-raw-data-directly": "Você pode importar diretamente de dados brutos",
"scrape-recipe-website-being-blocked": "Website being blocked?", "scrape-recipe-website-being-blocked": "Site sendo bloqueado?",
"scrape-recipe-try-importing-raw-html-instead": "Try importing the raw HTML instead.", "scrape-recipe-try-importing-raw-html-instead": "Tente importar o HTML ao invés disso.",
"import-original-keywords-as-tags": "Importar palavras-chave originais como marcadores", "import-original-keywords-as-tags": "Importar palavras-chave originais como marcadores",
"stay-in-edit-mode": "Permanecer no modo de edição", "stay-in-edit-mode": "Permanecer no modo de edição",
"parse-recipe-ingredients-after-import": "Interpretar os ingredientes da receita após importar", "parse-recipe-ingredients-after-import": "Interpretar os ingredientes da receita após importar",
@@ -1430,11 +1430,11 @@
} }
}, },
"validators": { "validators": {
"required": "This Field is Required", "required": "Este campo é obrigatório",
"invalid-email": "Email Must Be Valid", "invalid-email": "O e-mail deve ser válido",
"invalid-url": "Must Be A Valid URL", "invalid-url": "Precisa ser uma URL válida",
"no-whitespace": "No Whitespace Allowed", "no-whitespace": "Nenhum espaço em branco é permitido",
"min-length": "Must Be At Least {min} Characters", "min-length": "Precisa ter pelo menos {min} caracteres",
"max-length": "Must Be At Most {max} Characters" "max-length": "Pode ter até {max} caracteres"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "mealie", "name": "mealie",
"version": "3.9.1", "version": "3.9.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "nuxt dev", "dev": "nuxt dev",

View File

@@ -5043,14 +5043,14 @@
"hake": { "hake": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "hake", "name": "merlu",
"plural_name": "hakes" "plural_name": "merlus"
}, },
"pollock": { "pollock": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "pollock", "name": "lieu noir",
"plural_name": "pollocks" "plural_name": "lieu noir"
}, },
"salt cod": { "salt cod": {
"aliases": [], "aliases": [],
@@ -5217,8 +5217,8 @@
"pike": { "pike": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "pike", "name": "brochet",
"plural_name": "pikes" "plural_name": "brochets"
}, },
"pickled herring": { "pickled herring": {
"aliases": [], "aliases": [],
@@ -5469,8 +5469,8 @@
"tiny fish": { "tiny fish": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "tiny fish", "name": "petit poisson",
"plural_name": "tiny fish" "plural_name": "petits poissons"
}, },
"tuna belly": { "tuna belly": {
"aliases": [], "aliases": [],
@@ -5569,8 +5569,8 @@
"crawfish": { "crawfish": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "crawfish", "name": "écrevisse",
"plural_name": "crawfish" "plural_name": "écrevisses"
}, },
"octopu": { "octopu": {
"aliases": [], "aliases": [],
@@ -5635,8 +5635,8 @@
"squid ink": { "squid ink": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "squid ink", "name": "encre de seiche",
"plural_name": "squid inks" "plural_name": "encres de seiches"
}, },
"dried prawn": { "dried prawn": {
"aliases": [], "aliases": [],
@@ -5719,8 +5719,8 @@
"sea urchin": { "sea urchin": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "sea urchin", "name": "oursin",
"plural_name": "sea urchins" "plural_name": "oursins"
}, },
"abalone": { "abalone": {
"aliases": [], "aliases": [],
@@ -5743,8 +5743,8 @@
"smoked mussel": { "smoked mussel": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "smoked mussel", "name": "moule fumée",
"plural_name": "smoked mussels" "plural_name": "moules fumées"
}, },
"sea snail": { "sea snail": {
"aliases": [], "aliases": [],
@@ -5761,8 +5761,8 @@
"prepared crab cake": { "prepared crab cake": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "prepared crab cake", "name": "gâteau de crabe",
"plural_name": "prepared crab cakes" "plural_name": "gâteaux de crabe"
}, },
"sea lettuce": { "sea lettuce": {
"aliases": [], "aliases": [],
@@ -6095,8 +6095,8 @@
"chipotle": { "chipotle": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "chipotle", "name": "piment chipotle",
"plural_name": "chipotles" "plural_name": "piments chipotles"
}, },
"fenugreek": { "fenugreek": {
"aliases": [], "aliases": [],
@@ -6107,8 +6107,8 @@
"onion flake": { "onion flake": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "onion flake", "name": "oignon émincé",
"plural_name": "onion flakes" "plural_name": "oignons émincés"
}, },
"matcha powder": { "matcha powder": {
"aliases": [], "aliases": [],
@@ -6263,8 +6263,8 @@
"garlic flake": { "garlic flake": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "garlic flake", "name": "ail émincé",
"plural_name": "garlic flakes" "plural_name": "aulx émincés"
}, },
"dried cilantro": { "dried cilantro": {
"aliases": [], "aliases": [],
@@ -15705,7 +15705,7 @@
"almond extract": { "almond extract": {
"aliases": [], "aliases": [],
"description": "", "description": "",
"name": "extrait d'amandes", "name": "extrait d'amande",
"plural_name": "extraits d'amandes" "plural_name": "extraits d'amandes"
}, },
"food coloring": { "food coloring": {

View File

@@ -4,7 +4,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path from pathlib import Path
import sqlalchemy as sa import sqlalchemy as sa
from PIL import Image from PIL import Image, UnidentifiedImageError
from pydantic import UUID4 from pydantic import UUID4
from mealie.core import root_logger from mealie.core import root_logger
@@ -84,7 +84,12 @@ def reprocess_recipe_images(recipe_id: UUID4, force_all: bool = False) -> None:
image_file = service.dir_image / image_filename image_file = service.dir_image / image_filename
image_file.unlink(missing_ok=True) image_file.unlink(missing_ok=True)
try:
service.minifier.minify(original_image, force=True) service.minifier.minify(original_image, force=True)
except UnidentifiedImageError:
pass # source image is corrupted or invalid; skip
except Exception:
logger.exception(f"Failed to reprocess images for recipe {recipe_id}")
# Reprocess timeline event images # Reprocess timeline event images
timeline_dir = service.dir_image_timeline timeline_dir = service.dir_image_timeline

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "mealie" name = "mealie"
version = "3.9.1" version = "3.9.2"
description = "A Recipe Manager" description = "A Recipe Manager"
authors = [{ name = "Hayden", email = "hay-kot@pm.me" }] authors = [{ name = "Hayden", email = "hay-kot@pm.me" }]
license = "AGPL-3.0-only" license = "AGPL-3.0-only"

2
uv.lock generated
View File

@@ -811,7 +811,7 @@ wheels = [
[[package]] [[package]]
name = "mealie" name = "mealie"
version = "3.9.1" version = "3.9.2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "aiofiles" }, { name = "aiofiles" },