mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-09 03:04:54 -04:00
fix: Recipe Keeper Errors and Other Safari Issues (#3712)
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
parent
eab7c0d9e5
commit
4634ad5666
@ -132,14 +132,14 @@ export default defineComponent({
|
||||
text: i18n.tc("migration.plantoeat.title"),
|
||||
value: MIGRATIONS.plantoeat,
|
||||
},
|
||||
{
|
||||
text: i18n.tc("migration.tandoor.title"),
|
||||
value: MIGRATIONS.tandoor,
|
||||
},
|
||||
{
|
||||
text: i18n.tc("migration.recipekeeper.title"),
|
||||
value: MIGRATIONS.recipekeeper,
|
||||
},
|
||||
{
|
||||
text: i18n.tc("migration.tandoor.title"),
|
||||
value: MIGRATIONS.tandoor,
|
||||
},
|
||||
];
|
||||
const _content = {
|
||||
[MIGRATIONS.mealie]: {
|
||||
@ -312,6 +312,26 @@ export default defineComponent({
|
||||
}
|
||||
],
|
||||
},
|
||||
[MIGRATIONS.recipekeeper]: {
|
||||
text: i18n.tc("migration.recipekeeper.description-long"),
|
||||
acceptedFileType: ".zip",
|
||||
tree: [
|
||||
{
|
||||
id: 1,
|
||||
icon: $globals.icons.zip,
|
||||
name: "recipekeeperhtml.zip",
|
||||
children: [
|
||||
{ id: 2, name: "recipes.html", icon: $globals.icons.codeJson },
|
||||
{ id: 3, name: "images", icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{ id: 4, name: "image1.jpg", icon: $globals.icons.fileImage },
|
||||
{ id: 5, name: "image2.jpg", icon: $globals.icons.fileImage },
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
[MIGRATIONS.tandoor]: {
|
||||
text: i18n.tc("migration.tandoor.description-long"),
|
||||
acceptedFileType: ".zip",
|
||||
@ -352,26 +372,6 @@ export default defineComponent({
|
||||
}
|
||||
],
|
||||
},
|
||||
[MIGRATIONS.recipekeeper]: {
|
||||
text: i18n.tc("migration.recipekeeper.description-long"),
|
||||
acceptedFileType: ".zip",
|
||||
tree: [
|
||||
{
|
||||
id: 1,
|
||||
icon: $globals.icons.zip,
|
||||
name: "recipekeeperhtml.zip",
|
||||
children: [
|
||||
{ id: 2, name: "recipes.html", icon: $globals.icons.codeJson },
|
||||
{ id: 3, name: "images", icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{ id: 4, name: "image1.jpeg", icon: $globals.icons.fileImage },
|
||||
{ id: 5, name: "image2.jpeg", icon: $globals.icons.fileImage },
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
function setFileObject(fileObject: File) {
|
||||
|
@ -74,6 +74,28 @@ class BaseMigrator(BaseService):
|
||||
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def get_zip_base_path(cls, path: Path) -> Path:
|
||||
# Safari mangles our ZIP structure and adds a "__MACOSX" directory at the root along with
|
||||
# an arbitrarily-named directory containing the actual contents. So, if we find a dunder directory
|
||||
# at the root (i.e. __MACOSX) we traverse down the first non-dunder directory and assume this is the base.
|
||||
# We assume migration exports never contain a directory that starts with "__".
|
||||
normal_dirs: list[Path] = []
|
||||
dunder_dirs: list[Path] = []
|
||||
for dir in path.iterdir():
|
||||
if not dir.is_dir():
|
||||
continue
|
||||
|
||||
if dir.name.startswith("__"):
|
||||
dunder_dirs.append(dir)
|
||||
else:
|
||||
normal_dirs.append(dir)
|
||||
|
||||
if len(normal_dirs) == 1 and len(dunder_dirs) == 1:
|
||||
return normal_dirs[0]
|
||||
else:
|
||||
return path
|
||||
|
||||
def _migrate(self) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -20,12 +20,24 @@ class ChowdownMigrator(BaseMigrator):
|
||||
MigrationAlias(key="tags", alias="tags", func=split_by_comma),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_zip_base_path(cls, path: Path) -> Path:
|
||||
potential_path = super().get_zip_base_path(path)
|
||||
if path == potential_path:
|
||||
return path
|
||||
|
||||
# make sure we didn't accidentally open a recipe dir
|
||||
if (potential_path / "recipe.json").exists():
|
||||
return path
|
||||
else:
|
||||
return potential_path
|
||||
|
||||
def _migrate(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
with zipfile.ZipFile(self.archive) as zip_file:
|
||||
zip_file.extractall(tmpdir)
|
||||
|
||||
temp_path = Path(tmpdir)
|
||||
temp_path = self.get_zip_base_path(Path(tmpdir))
|
||||
|
||||
chow_dir = next(temp_path.iterdir())
|
||||
image_dir = temp_path.joinpath(chow_dir, "images")
|
||||
|
@ -86,7 +86,7 @@ class CopyMeThatMigrator(BaseMigrator):
|
||||
with zipfile.ZipFile(self.archive) as zip_file:
|
||||
zip_file.extractall(tmpdir)
|
||||
|
||||
source_dir = Path(tmpdir)
|
||||
source_dir = self.get_zip_base_path(Path(tmpdir))
|
||||
|
||||
recipes_as_dicts: list[dict] = []
|
||||
for recipes_data_file in source_dir.glob("*.html"):
|
||||
|
@ -25,6 +25,18 @@ class MealieAlphaMigrator(BaseMigrator):
|
||||
MigrationAlias(key="tags", alias="tags", func=split_by_comma),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_zip_base_path(cls, path: Path) -> Path:
|
||||
potential_path = super().get_zip_base_path(path)
|
||||
if path == potential_path:
|
||||
return path
|
||||
|
||||
# make sure we didn't accidentally open the "recipes" dir
|
||||
if potential_path.name == "recipes":
|
||||
return path
|
||||
else:
|
||||
return potential_path
|
||||
|
||||
def _convert_to_new_schema(self, recipe: dict) -> Recipe:
|
||||
if recipe.get("categories", False):
|
||||
recipe["recipeCategory"] = recipe.get("categories")
|
||||
@ -55,7 +67,7 @@ class MealieAlphaMigrator(BaseMigrator):
|
||||
with zipfile.ZipFile(self.archive) as zip_file:
|
||||
zip_file.extractall(tmpdir)
|
||||
|
||||
temp_path = Path(tmpdir)
|
||||
temp_path = self.get_zip_base_path(Path(tmpdir))
|
||||
recipe_lookup: dict[str, Path] = {}
|
||||
|
||||
recipes: list[Recipe] = []
|
||||
|
@ -57,6 +57,18 @@ class NextcloudMigrator(BaseMigrator):
|
||||
MigrationAlias(key="performTime", alias="cookTime", func=parse_iso8601_duration),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_zip_base_path(cls, path: Path) -> Path:
|
||||
potential_path = super().get_zip_base_path(path)
|
||||
if path == potential_path:
|
||||
return path
|
||||
|
||||
# make sure we didn't accidentally open a recipe dir
|
||||
if (potential_path / "recipe.json").exists():
|
||||
return path
|
||||
else:
|
||||
return potential_path
|
||||
|
||||
def _migrate(self) -> None:
|
||||
# Unzip File into temp directory
|
||||
|
||||
@ -65,7 +77,8 @@ class NextcloudMigrator(BaseMigrator):
|
||||
with zipfile.ZipFile(self.archive) as zip_file:
|
||||
zip_file.extractall(tmpdir)
|
||||
|
||||
potential_recipe_dirs = glob_walker(Path(tmpdir), glob_str="**/[!.]*.json", return_parent=True)
|
||||
base_dir = self.get_zip_base_path(Path(tmpdir))
|
||||
potential_recipe_dirs = glob_walker(base_dir, glob_str="**/[!.]*.json", return_parent=True)
|
||||
nextcloud_dirs = {y.slug: y for x in potential_recipe_dirs if (y := NextcloudDir.from_dir(x))}
|
||||
|
||||
all_recipes = []
|
||||
|
@ -11,6 +11,17 @@ from .utils.migration_alias import MigrationAlias
|
||||
from .utils.migration_helpers import import_image, parse_iso8601_duration
|
||||
|
||||
|
||||
def clean_instructions(instructions: list[str]) -> list[str]:
|
||||
try:
|
||||
for i, instruction in enumerate(instructions):
|
||||
if instruction.startswith(f"{i + 1}. "):
|
||||
instructions[i] = instruction.removeprefix(f"{i + 1}. ")
|
||||
|
||||
return instructions
|
||||
except Exception:
|
||||
return instructions
|
||||
|
||||
|
||||
def parse_recipe_div(recipe, image_path):
|
||||
meta = {}
|
||||
for item in recipe.find_all(lambda x: x.has_attr("itemprop")):
|
||||
@ -59,7 +70,7 @@ class RecipeKeeperMigrator(BaseMigrator):
|
||||
key="recipeIngredient",
|
||||
alias="recipeIngredients",
|
||||
),
|
||||
MigrationAlias(key="recipeInstructions", alias="recipeDirections"),
|
||||
MigrationAlias(key="recipeInstructions", alias="recipeDirections", func=clean_instructions),
|
||||
MigrationAlias(key="performTime", alias="cookTime", func=parse_iso8601_duration),
|
||||
MigrationAlias(key="prepTime", alias="prepTime", func=parse_iso8601_duration),
|
||||
MigrationAlias(key="image", alias="photo0"),
|
||||
@ -77,7 +88,7 @@ class RecipeKeeperMigrator(BaseMigrator):
|
||||
with zipfile.ZipFile(self.archive) as zip_file:
|
||||
zip_file.extractall(tmpdir)
|
||||
|
||||
source_dir = Path(tmpdir) / "recipekeeperhtml"
|
||||
source_dir = self.get_zip_base_path(Path(tmpdir))
|
||||
|
||||
recipes_as_dicts: list[dict] = []
|
||||
with open(source_dir / "recipes.html") as fp:
|
||||
|
@ -109,7 +109,7 @@ class TandoorMigrator(BaseMigrator):
|
||||
with zipfile.ZipFile(self.archive) as zip_file:
|
||||
zip_file.extractall(tmpdir)
|
||||
|
||||
source_dir = Path(tmpdir)
|
||||
source_dir = self.get_zip_base_path(Path(tmpdir))
|
||||
|
||||
recipes_as_dicts: list[dict] = []
|
||||
for i, recipe_zip_file in enumerate(source_dir.glob("*.zip")):
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user