feat: ✨ Paprika/Mealie Migration support (#873)
* feat: ✨ paprika support - partial * feat: ✨ add full paprika support * re-organize data directory * add data directory auto-gen * rewrite migration tests * remove print statements * remove hard-coded paths * add auto-tag support * add mealie migration support * add looking for migraiton button
1
.gitignore
vendored
|
@ -11,6 +11,7 @@ docs/site/
|
|||
.secret
|
||||
frontend/dist/
|
||||
|
||||
dev/code-generation/generated/*
|
||||
dev/data/backups/*
|
||||
dev/data/debug/*
|
||||
dev/data/img/*
|
||||
|
|
10
.vscode/settings.json
vendored
|
@ -6,7 +6,15 @@
|
|||
"code-generation"
|
||||
],
|
||||
"cSpell.enableFiletypes": ["!javascript", "!python", "!yaml"],
|
||||
"cSpell.words": ["compression", "hkotel", "performant", "postgres", "webp"],
|
||||
"cSpell.words": [
|
||||
"chowdown",
|
||||
"compression",
|
||||
"hkotel",
|
||||
"nextcloud",
|
||||
"performant",
|
||||
"postgres",
|
||||
"webp"
|
||||
],
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true,
|
||||
"source.organizeImports": false
|
||||
|
|
|
@ -3,15 +3,15 @@ from dataclasses import dataclass
|
|||
from pathlib import Path
|
||||
from typing import Tuple
|
||||
|
||||
from black import FileMode, format_str
|
||||
import black
|
||||
from jinja2 import Template
|
||||
|
||||
|
||||
def render_python_template(template_file: Path, dest: Path, data: dict) -> str:
|
||||
"""Render and Format a Jinja2 Template for Python Code"""
|
||||
tplt = Template(template_file.read_text())
|
||||
text = tplt.render(data)
|
||||
text = format_str(text, mode=FileMode())
|
||||
text = tplt.render(data=data)
|
||||
text = black.format_str(text, mode=black.FileMode())
|
||||
dest.write_text(text)
|
||||
|
||||
|
||||
|
|
124
dev/code-generation/gen_test_data_paths.py
Normal file
|
@ -0,0 +1,124 @@
|
|||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from _gen_utils import render_python_template
|
||||
from slugify import slugify
|
||||
|
||||
CWD = Path(__file__).parent
|
||||
|
||||
TEMPLATE = CWD / "templates" / "test_data.py.j2"
|
||||
|
||||
TEST_DATA = CWD.parent.parent / "tests" / "data"
|
||||
|
||||
GENERATED = CWD / "generated"
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestDataPath:
|
||||
var: str
|
||||
path: str
|
||||
|
||||
@classmethod
|
||||
def from_path(cls, path: Path):
|
||||
var = str(path)
|
||||
var = var.replace(str(TEST_DATA), "")
|
||||
|
||||
rel_path = var.removeprefix("/")
|
||||
|
||||
# Remove any file extension
|
||||
var = var.split(".")[0]
|
||||
|
||||
var = var.replace("'", "")
|
||||
|
||||
var = slugify(var, separator="_")
|
||||
|
||||
return cls(var, rel_path)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataDir:
|
||||
name: str
|
||||
path: Path
|
||||
children: list[TestDataPath]
|
||||
|
||||
|
||||
def get_data_paths(path: Path) -> list[DataDir]:
|
||||
"""
|
||||
Recursively walks the given path and returns a list of TestDataPaths
|
||||
"""
|
||||
|
||||
def recursive_test_paths(p: Path) -> list[TestDataPath]:
|
||||
test_paths = []
|
||||
for child in p.iterdir():
|
||||
if child.is_dir():
|
||||
test_paths += recursive_test_paths(child)
|
||||
else:
|
||||
test_paths.append(TestDataPath.from_path(child))
|
||||
return [x for x in test_paths if not None]
|
||||
|
||||
data_paths = []
|
||||
|
||||
for p in path.iterdir():
|
||||
if p.is_dir():
|
||||
data_paths.append(DataDir(p.name, p, recursive_test_paths(p)))
|
||||
|
||||
return data_paths
|
||||
|
||||
|
||||
def rename_non_compliant_paths():
|
||||
"""
|
||||
Recursively itterates through a directory and renames all files/folders to be
|
||||
kabab case.
|
||||
"""
|
||||
|
||||
ignore_files = ["DS_Store", ".gitkeep"]
|
||||
|
||||
ignore_extensions = [".pyc", ".pyo", ".py"]
|
||||
|
||||
def recursive_rename(p: Path):
|
||||
for child in p.iterdir():
|
||||
if str(child).startswith("."):
|
||||
continue
|
||||
|
||||
if child.suffix in ignore_extensions:
|
||||
continue
|
||||
|
||||
if child.name in ignore_files:
|
||||
continue
|
||||
|
||||
if child.is_dir():
|
||||
recursive_rename(child)
|
||||
|
||||
else:
|
||||
new_name = slugify(child.stem)
|
||||
extension = child.suffix
|
||||
if new_name != child.name:
|
||||
child.rename(child.parent / f"{new_name}{extension}")
|
||||
|
||||
recursive_rename(TEST_DATA)
|
||||
|
||||
|
||||
def main():
|
||||
print("Starting Template Generation")
|
||||
|
||||
rename_non_compliant_paths()
|
||||
|
||||
GENERATED.mkdir(exist_ok=True)
|
||||
data_dirs = get_data_paths(TEST_DATA)
|
||||
|
||||
all_children = [x.children for x in data_dirs]
|
||||
|
||||
# Flatten list of lists
|
||||
all_children = [item for sublist in all_children for item in sublist]
|
||||
|
||||
render_python_template(
|
||||
TEMPLATE,
|
||||
GENERATED / "__init__.py",
|
||||
{"children": all_children},
|
||||
)
|
||||
|
||||
print("Finished Template Generation")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
7
dev/code-generation/templates/test_data.py.j2
Normal file
|
@ -0,0 +1,7 @@
|
|||
from pathlib import Path
|
||||
|
||||
CWD = Path(__file__).parent
|
||||
|
||||
{% for f in data.children %}
|
||||
{{ f.var }} = CWD / "{{ f.path }}"
|
||||
{% endfor %}
|
|
@ -3,9 +3,10 @@ import { ReportSummary } from "./group-reports";
|
|||
|
||||
const prefix = "/api";
|
||||
|
||||
export type SupportedMigration = "nextcloud" | "chowdown";
|
||||
export type SupportedMigration = "nextcloud" | "chowdown" | "mealie_alpha" | "paprika";
|
||||
|
||||
export interface MigrationPayload {
|
||||
addMigrationTag: boolean;
|
||||
migrationType: SupportedMigration;
|
||||
archive: File;
|
||||
}
|
||||
|
@ -17,6 +18,7 @@ const routes = {
|
|||
export class GroupMigrationApi extends BaseAPI {
|
||||
async startMigration(payload: MigrationPayload) {
|
||||
const form = new FormData();
|
||||
form.append("add_migration_tag", String(payload.addMigrationTag));
|
||||
form.append("migration_type", payload.migrationType);
|
||||
form.append("archive", payload.archive);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export default {
|
||||
mode: "universal",
|
||||
// Global page headers: https://go.nuxtjs.dev/config-head
|
||||
head: {
|
||||
title: "Home",
|
||||
|
|
|
@ -306,6 +306,10 @@
|
|||
</v-card-actions>
|
||||
</section>
|
||||
</v-container>
|
||||
|
||||
<v-container v-if="$auth.user.advanced" class="narrow-container d-flex justify-end">
|
||||
<v-btn outlined rounded to="/user/group/data/migrations"> Looking For Migrations? </v-btn>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -42,6 +42,14 @@
|
|||
{{ fileObject.name || "No file selected" }}
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text>
|
||||
<v-checkbox v-model="addMigrationTag">
|
||||
<template #label>
|
||||
Tag all recipes with <b class="mx-1"> {{ migrationType }} </b> tag
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="justify-end">
|
||||
<BaseButton :disabled="!fileObject.name" submit @click="startMigration">
|
||||
{{ $t("general.submit") }}</BaseButton
|
||||
|
@ -65,6 +73,8 @@ import { useUserApi } from "~/composables/api";
|
|||
const MIGRATIONS = {
|
||||
nextcloud: "nextcloud",
|
||||
chowdown: "chowdown",
|
||||
paprika: "paprika",
|
||||
mealie: "mealie_alpha",
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -75,6 +85,7 @@ export default defineComponent({
|
|||
const api = useUserApi();
|
||||
|
||||
const state = reactive({
|
||||
addMigrationTag: false,
|
||||
loading: false,
|
||||
treeState: true,
|
||||
migrationType: MIGRATIONS.nextcloud as SupportedMigration,
|
||||
|
@ -91,6 +102,14 @@ export default defineComponent({
|
|||
text: "Chowdown",
|
||||
value: MIGRATIONS.chowdown,
|
||||
},
|
||||
{
|
||||
text: "Paprika",
|
||||
value: MIGRATIONS.paprika,
|
||||
},
|
||||
{
|
||||
text: "Mealie",
|
||||
value: MIGRATIONS.mealie,
|
||||
},
|
||||
];
|
||||
|
||||
const _content = {
|
||||
|
@ -128,8 +147,95 @@ export default defineComponent({
|
|||
},
|
||||
[MIGRATIONS.chowdown]: {
|
||||
text: "Mealie natively supports the chowdown repository format. Download the code repository as a .zip file and upload it below",
|
||||
tree: [
|
||||
{
|
||||
id: 1,
|
||||
icon: $globals.icons.zip,
|
||||
name: "nextcloud.zip",
|
||||
children: [
|
||||
{
|
||||
id: 2,
|
||||
name: "Recipe 1",
|
||||
icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{ id: 3, name: "recipe.json", icon: $globals.icons.codeJson },
|
||||
{ id: 4, name: "full.jpg", icon: $globals.icons.fileImage },
|
||||
{ id: 5, name: "thumb.jpg", icon: $globals.icons.fileImage },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Recipe 2",
|
||||
icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{ id: 7, name: "recipe.json", icon: $globals.icons.codeJson },
|
||||
{ id: 8, name: "full.jpg", icon: $globals.icons.fileImage },
|
||||
{ id: 9, name: "thumb.jpg", icon: $globals.icons.fileImage },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
[MIGRATIONS.paprika]: {
|
||||
text: "Mealie can import recipes from the Paprika application. Export your recipes from paprika, rename the export extension to .zip and upload it below.",
|
||||
tree: false,
|
||||
},
|
||||
[MIGRATIONS.mealie]: {
|
||||
text: "Mealie can import recipes from the Mealie application from a pre v1.0 release. Export your recipes from your old instance, and upload the zip file below. Note that only recipes can be imported from the export.",
|
||||
tree: [
|
||||
{
|
||||
id: 1,
|
||||
icon: $globals.icons.zip,
|
||||
name: "mealie.zip",
|
||||
children: [
|
||||
{
|
||||
id: 2,
|
||||
name: "recipes",
|
||||
icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{
|
||||
id: 3,
|
||||
name: "recipe-name",
|
||||
icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{ id: 4, name: "recipe-name.json", icon: $globals.icons.codeJson },
|
||||
{
|
||||
id: 5,
|
||||
name: "images",
|
||||
icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{ id: 6, name: "original.webp", icon: $globals.icons.codeJson },
|
||||
{ id: 7, name: "full.jpg", icon: $globals.icons.fileImage },
|
||||
{ id: 8, name: "thumb.jpg", icon: $globals.icons.fileImage },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "recipe-name-1",
|
||||
icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{ id: 10, name: "recipe-name-1.json", icon: $globals.icons.codeJson },
|
||||
{
|
||||
id: 11,
|
||||
name: "images",
|
||||
icon: $globals.icons.folderOutline,
|
||||
children: [
|
||||
{ id: 12, name: "original.webp", icon: $globals.icons.codeJson },
|
||||
{ id: 13, name: "full.jpg", icon: $globals.icons.fileImage },
|
||||
{ id: 14, name: "thumb.jpg", icon: $globals.icons.fileImage },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
function setFileObject(fileObject: File) {
|
||||
|
@ -139,6 +245,7 @@ export default defineComponent({
|
|||
async function startMigration() {
|
||||
state.loading = true;
|
||||
const payload = {
|
||||
addMigrationTag: state.addMigrationTag,
|
||||
migrationType: state.migrationType,
|
||||
archive: state.fileObject,
|
||||
};
|
||||
|
|
|
@ -229,8 +229,12 @@ class AccessModel(Generic[T, D]):
|
|||
result = self.session.query(self.sql_model).filter_by(**{self.primary_key: primary_key_value}).one()
|
||||
results_as_model = self.schema.from_orm(result)
|
||||
|
||||
self.session.delete(result)
|
||||
self.session.commit()
|
||||
try:
|
||||
self.session.delete(result)
|
||||
self.session.commit()
|
||||
except Exception as e:
|
||||
self.session.rollback()
|
||||
raise e
|
||||
|
||||
if self.observers:
|
||||
self.update_observers()
|
||||
|
|
|
@ -31,7 +31,7 @@ class Tag(SqlAlchemyBase, BaseMixins):
|
|||
assert name != ""
|
||||
return name
|
||||
|
||||
def __init__(self, name, session=None) -> None:
|
||||
def __init__(self, name, **_) -> None:
|
||||
self.name = name.strip()
|
||||
self.slug = slugify(self.name)
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ router = UserAPIRouter()
|
|||
|
||||
@router.post("", response_model=ReportSummary)
|
||||
def start_data_migration(
|
||||
add_migration_tag: bool = Form(False),
|
||||
migration_type: SupportedMigrations = Form(...),
|
||||
archive: UploadFile = File(...),
|
||||
temp_path: str = Depends(temporary_zip_path),
|
||||
|
@ -23,4 +24,4 @@ def start_data_migration(
|
|||
with temp_path.open("wb") as buffer:
|
||||
shutil.copyfileobj(archive.file, buffer)
|
||||
|
||||
return gm_service.migrate(migration_type, temp_path)
|
||||
return gm_service.migrate(migration_type, add_migration_tag, temp_path)
|
||||
|
|
|
@ -6,6 +6,8 @@ from fastapi_camelcase import CamelModel
|
|||
class SupportedMigrations(str, enum.Enum):
|
||||
nextcloud = "nextcloud"
|
||||
chowdown = "chowdown"
|
||||
paprika = "paprika"
|
||||
mealie_alpha = "mealie_alpha"
|
||||
|
||||
|
||||
class DataMigrationCreate(CamelModel):
|
||||
|
|
|
@ -11,6 +11,8 @@ from mealie.schema.reports.reports import ReportOut, ReportSummary
|
|||
from mealie.services._base_http_service.http_services import UserHttpService
|
||||
from mealie.services.events import create_group_event
|
||||
from mealie.services.migrations import ChowdownMigrator, NextcloudMigrator
|
||||
from mealie.services.migrations.mealie_alpha import MealieAlphaMigrator
|
||||
from mealie.services.migrations.paprika import PaprikaMigrator
|
||||
|
||||
logger = get_logger(module=__name__)
|
||||
|
||||
|
@ -24,14 +26,29 @@ class GroupMigrationService(UserHttpService[int, ReportOut]):
|
|||
def dal(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def populate_item(self, id: UUID4) -> ReportOut:
|
||||
def populate_item(self, _: UUID4) -> ReportOut:
|
||||
return None
|
||||
|
||||
def migrate(self, migration: SupportedMigrations, archive: Path) -> ReportSummary:
|
||||
def migrate(self, migration: SupportedMigrations, add_migration_tag: bool, archive: Path) -> ReportSummary:
|
||||
args = {
|
||||
"archive": archive,
|
||||
"db": self.db,
|
||||
"session": self.session,
|
||||
"user_id": self.user.id,
|
||||
"group_id": self.group_id,
|
||||
"add_migration_tag": add_migration_tag,
|
||||
}
|
||||
|
||||
if migration == SupportedMigrations.nextcloud:
|
||||
self.migration_type = NextcloudMigrator(archive, self.db, self.session, self.user.id, self.group_id)
|
||||
self.migration_type = NextcloudMigrator(**args)
|
||||
|
||||
if migration == SupportedMigrations.chowdown:
|
||||
self.migration_type = ChowdownMigrator(archive, self.db, self.session, self.user.id, self.group_id)
|
||||
self.migration_type = ChowdownMigrator(**args)
|
||||
|
||||
if migration == SupportedMigrations.paprika:
|
||||
self.migration_type = PaprikaMigrator(**args)
|
||||
|
||||
if migration == SupportedMigrations.mealie_alpha:
|
||||
self.migration_type = MealieAlphaMigrator(**args)
|
||||
|
||||
return self.migration_type.migrate(f"{migration.value.title()} Migration")
|
||||
|
|
|
@ -16,6 +16,7 @@ from mealie.schema.reports.reports import (
|
|||
from mealie.services.scraper import cleaner
|
||||
|
||||
from .._base_service import BaseService
|
||||
from .utils.database_helpers import DatabaseMigrationHelpers
|
||||
from .utils.migration_alias import MigrationAlias
|
||||
|
||||
|
||||
|
@ -26,17 +27,22 @@ class BaseMigrator(BaseService):
|
|||
report_id: int
|
||||
report: ReportOut
|
||||
|
||||
def __init__(self, archive: Path, db: Database, session, user_id: int, group_id: UUID):
|
||||
def __init__(self, archive: Path, db: Database, session, user_id: int, group_id: UUID, add_migration_tag: bool):
|
||||
self.archive = archive
|
||||
self.db = db
|
||||
self.session = session
|
||||
self.user_id = user_id
|
||||
self.group_id = group_id
|
||||
self.add_migration_tag = add_migration_tag
|
||||
|
||||
self.name = "migration"
|
||||
|
||||
self.report_entries = []
|
||||
|
||||
self.logger = root_logger.get_logger()
|
||||
|
||||
self.helpers = DatabaseMigrationHelpers(self.db, self.session, self.group_id, self.user_id)
|
||||
|
||||
super().__init__()
|
||||
|
||||
def _migrate(self) -> None:
|
||||
|
@ -94,6 +100,8 @@ class BaseMigrator(BaseService):
|
|||
Args:
|
||||
validated_recipes (list[Recipe]):
|
||||
"""
|
||||
if self.add_migration_tag:
|
||||
migration_tag = self.helpers.get_or_set_tags([self.name])[0]
|
||||
|
||||
return_vars = []
|
||||
|
||||
|
@ -102,6 +110,9 @@ class BaseMigrator(BaseService):
|
|||
recipe.user_id = self.user_id
|
||||
recipe.group_id = self.group_id
|
||||
|
||||
if self.add_migration_tag:
|
||||
recipe.tags.append(migration_tag)
|
||||
|
||||
exception = ""
|
||||
status = False
|
||||
try:
|
||||
|
@ -109,7 +120,7 @@ class BaseMigrator(BaseService):
|
|||
status = True
|
||||
|
||||
except Exception as inst:
|
||||
exception = inst
|
||||
exception = str(inst)
|
||||
self.logger.exception(inst)
|
||||
self.session.rollback()
|
||||
|
||||
|
@ -165,6 +176,17 @@ class BaseMigrator(BaseService):
|
|||
dictionary and returns the result unpacked into a Recipe object
|
||||
"""
|
||||
recipe_dict = self.rewrite_alias(recipe_dict)
|
||||
|
||||
# Temporary hold out of recipe_dict
|
||||
# temp_categories = recipe_dict["recipeCategory"]
|
||||
# temp_tools = recipe_dict["tools"]
|
||||
# temp_tasg = recipe_dict["tags"]
|
||||
|
||||
recipe_dict = cleaner.clean(recipe_dict, url=recipe_dict.get("org_url", None))
|
||||
|
||||
# Reassign after cleaning
|
||||
# recipe_dict["recipeCategory"] = temp_categories
|
||||
# recipe_dict["tools"] = temp_tools
|
||||
# recipe_dict["tags"] = temp_tasg
|
||||
|
||||
return Recipe(**recipe_dict)
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import tempfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from uuid import UUID
|
||||
|
||||
from mealie.db.database import Database
|
||||
|
||||
from ._migration_base import BaseMigrator
|
||||
from .utils.migration_alias import MigrationAlias
|
||||
|
@ -11,8 +8,10 @@ from .utils.migration_helpers import MigrationReaders, import_image, split_by_co
|
|||
|
||||
|
||||
class ChowdownMigrator(BaseMigrator):
|
||||
def __init__(self, archive: Path, db: Database, session, user_id: int, group_id: UUID):
|
||||
super().__init__(archive, db, session, user_id, group_id)
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.name = "chowdown"
|
||||
|
||||
self.key_aliases = [
|
||||
MigrationAlias(key="name", alias="title", func=None),
|
||||
|
|
87
mealie/services/migrations/mealie_alpha.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
from mealie.schema.recipe.recipe import Recipe
|
||||
|
||||
from ._migration_base import BaseMigrator
|
||||
from .utils.migration_alias import MigrationAlias
|
||||
from .utils.migration_helpers import MigrationReaders, split_by_comma
|
||||
|
||||
|
||||
class MealieAlphaMigrator(BaseMigrator):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.name = "mealie_alpha"
|
||||
|
||||
self.key_aliases = [
|
||||
MigrationAlias(key="name", alias="title", func=None),
|
||||
MigrationAlias(key="recipeIngredient", alias="ingredients", func=None),
|
||||
MigrationAlias(key="recipeInstructions", alias="directions", func=None),
|
||||
MigrationAlias(key="tags", alias="tags", func=split_by_comma),
|
||||
]
|
||||
|
||||
def _convert_to_new_schema(self, recipe: dict) -> Recipe:
|
||||
if recipe.get("categories", False):
|
||||
recipe["recipeCategory"] = recipe.get("categories")
|
||||
del recipe["categories"]
|
||||
try:
|
||||
del recipe["_id"]
|
||||
del recipe["date_added"]
|
||||
except Exception:
|
||||
pass
|
||||
# Migration from list to Object Type Data
|
||||
try:
|
||||
if "" in recipe["tags"]:
|
||||
recipe["tags"] = [tag for tag in recipe["tags"] if tag != ""]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
if "" in recipe["categories"]:
|
||||
recipe["categories"] = [cat for cat in recipe["categories"] if cat != ""]
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if type(recipe["extras"]) == list:
|
||||
recipe["extras"] = {}
|
||||
|
||||
recipe["comments"] = []
|
||||
|
||||
return Recipe(**recipe)
|
||||
|
||||
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)
|
||||
|
||||
recipe_lookup: dict[str, Path] = {}
|
||||
recipes_as_dicts = []
|
||||
|
||||
for x in temp_path.rglob("**/[!.]*.json"):
|
||||
if (y := MigrationReaders.json(x)) is not None:
|
||||
recipes_as_dicts.append(y)
|
||||
slug = y["slug"]
|
||||
recipe_lookup[slug] = x.parent
|
||||
|
||||
recipes = [self._convert_to_new_schema(x) for x in recipes_as_dicts]
|
||||
|
||||
results = self.import_recipes_to_database(recipes)
|
||||
|
||||
recipe_model_lookup = {x.slug: x for x in recipes}
|
||||
|
||||
for slug, status in results:
|
||||
if status:
|
||||
model = recipe_model_lookup.get(slug)
|
||||
dest_dir = model.directory
|
||||
source_dir = recipe_lookup.get(slug)
|
||||
|
||||
if dest_dir.exists():
|
||||
shutil.rmtree(dest_dir)
|
||||
|
||||
shutil.copytree(source_dir, dest_dir)
|
|
@ -3,12 +3,9 @@ import zipfile
|
|||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from slugify import slugify
|
||||
|
||||
from mealie.db.database import Database
|
||||
|
||||
from ._migration_base import BaseMigrator
|
||||
from .utils.migration_alias import MigrationAlias
|
||||
from .utils.migration_helpers import MigrationReaders, glob_walker, import_image, split_by_comma
|
||||
|
@ -40,8 +37,10 @@ class NextcloudDir:
|
|||
|
||||
|
||||
class NextcloudMigrator(BaseMigrator):
|
||||
def __init__(self, archive: Path, db: Database, session, user_id: int, group_id: UUID):
|
||||
super().__init__(archive, db, session, user_id, group_id)
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.name = "nextcloud"
|
||||
|
||||
self.key_aliases = [
|
||||
MigrationAlias(key="tags", alias="keywords", func=split_by_comma),
|
||||
|
|
93
mealie/services/migrations/paprika.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
import base64
|
||||
import io
|
||||
import json
|
||||
import tempfile
|
||||
import zipfile
|
||||
from gzip import GzipFile
|
||||
from pathlib import Path
|
||||
|
||||
import regex as re
|
||||
from slugify import slugify
|
||||
|
||||
from mealie.schema.recipe import RecipeNote
|
||||
|
||||
from ._migration_base import BaseMigrator
|
||||
from .utils.migration_alias import MigrationAlias
|
||||
from .utils.migration_helpers import import_image
|
||||
|
||||
|
||||
def paprika_recipes(file: Path):
|
||||
"""Yields all recipes inside the export file as JSON"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
with zipfile.ZipFile(file) as zip_file:
|
||||
zip_file.extractall(tmpdir)
|
||||
|
||||
for name in Path(tmpdir).glob("**/[!.]*.paprikarecipe"):
|
||||
with open(name, "rb") as fd:
|
||||
with GzipFile("r", fileobj=fd) as recipe_json:
|
||||
recipe = json.load(recipe_json)
|
||||
yield recipe
|
||||
|
||||
|
||||
class PaprikaMigrator(BaseMigrator):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.name = "paprika"
|
||||
|
||||
re_num_list = re.compile(r"^\d+\.\s")
|
||||
|
||||
self.key_aliases = [
|
||||
MigrationAlias(key="recipeIngredient", alias="ingredients", func=lambda x: x.split("\n")),
|
||||
MigrationAlias(key="orgUrl", alias="source_url", func=None),
|
||||
MigrationAlias(key="performTime", alias="cook_time", func=None),
|
||||
MigrationAlias(key="recipeYield", alias="servings", func=None),
|
||||
MigrationAlias(key="image", alias="image_url", func=None),
|
||||
MigrationAlias(key="dateAdded", alias="created", func=lambda x: x[: x.find(" ")]),
|
||||
MigrationAlias(
|
||||
key="notes",
|
||||
alias="notes",
|
||||
func=lambda x: [z for z in [RecipeNote(title="", text=x) if x else None] if z],
|
||||
),
|
||||
MigrationAlias(
|
||||
key="recipeCategory",
|
||||
alias="categories",
|
||||
func=self.helpers.get_or_set_category,
|
||||
),
|
||||
MigrationAlias(
|
||||
key="recipeInstructions",
|
||||
alias="directions",
|
||||
func=lambda x: [{"text": re.sub(re_num_list, "", s)} for s in x.split("\n\n")],
|
||||
),
|
||||
]
|
||||
|
||||
def _migrate(self) -> None:
|
||||
recipe_image_urls = {}
|
||||
|
||||
recipes = []
|
||||
for recipe in paprika_recipes(self.archive):
|
||||
if "name" not in recipe:
|
||||
continue
|
||||
|
||||
recipe_model = self.clean_recipe_dictionary(recipe)
|
||||
|
||||
if "photo_data" in recipe:
|
||||
recipe_image_urls[slugify(recipe["name"])] = recipe["photo_data"]
|
||||
|
||||
recipes.append(recipe_model)
|
||||
|
||||
results = self.import_recipes_to_database(recipes)
|
||||
|
||||
for slug, status in results:
|
||||
if not status:
|
||||
continue
|
||||
|
||||
try:
|
||||
# Images are stored as base64 encoded strings, so we need to decode them before importing.
|
||||
image = io.BytesIO(base64.b64decode(recipe_image_urls[slug]))
|
||||
with tempfile.NamedTemporaryFile(suffix=".jpeg") as temp_file:
|
||||
temp_file.write(image.read())
|
||||
path = Path(temp_file.name)
|
||||
import_image(path, slug)
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to download image for {slug}: {e}")
|
51
mealie/services/migrations/utils/database_helpers.py
Normal file
|
@ -0,0 +1,51 @@
|
|||
from typing import TypeVar
|
||||
|
||||
from pydantic import BaseModel
|
||||
from slugify import slugify
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from mealie.db.data_access_layer.access_model_factory import AccessModel
|
||||
from mealie.db.database import Database
|
||||
from mealie.schema.recipe import RecipeCategory
|
||||
from mealie.schema.recipe.recipe import RecipeTag
|
||||
|
||||
T = TypeVar("T", bound=BaseModel)
|
||||
|
||||
|
||||
class DatabaseMigrationHelpers:
|
||||
def __init__(self, db: Database, session: Session, group_id: int, user_id: int) -> None:
|
||||
self.group_id = group_id
|
||||
self.user_id = user_id
|
||||
self.session = session
|
||||
self.db = db
|
||||
|
||||
def _get_or_set_generic(self, accessor: AccessModel, items: list[str], out_model: T) -> list[T]:
|
||||
"""
|
||||
Utility model for getting or setting categories or tags. This will only work for those two cases.
|
||||
|
||||
This is probably a bad implementation of this pattern.
|
||||
"""
|
||||
items_out = []
|
||||
|
||||
for item_name in items:
|
||||
slug_lookup = slugify(item_name)
|
||||
|
||||
item_model = accessor.get_one(slug_lookup, "slug", override_schema=out_model)
|
||||
|
||||
if not item_model:
|
||||
item_model = accessor.create(
|
||||
out_model(
|
||||
name=item_name,
|
||||
slug=slug_lookup,
|
||||
)
|
||||
)
|
||||
|
||||
items_out.append(item_model.dict())
|
||||
|
||||
return items_out
|
||||
|
||||
def get_or_set_category(self, categories: list[str]) -> list[RecipeCategory]:
|
||||
return self._get_or_set_generic(self.db.categories, categories, RecipeCategory)
|
||||
|
||||
def get_or_set_tags(self, tags: list[str]) -> list[RecipeTag]:
|
||||
return self._get_or_set_generic(self.db.tags, tags, RecipeTag)
|
|
@ -56,10 +56,20 @@ def clean_string(text: str) -> str:
|
|||
|
||||
|
||||
def category(category: str):
|
||||
if isinstance(category, list) and len(category) > 0 and isinstance(category[0], dict):
|
||||
# If the category is a list of dicts, it's probably from a migration
|
||||
# validate that the required fields are present
|
||||
valid = []
|
||||
for cat in category:
|
||||
if "name" in cat and "slug" in cat:
|
||||
valid.append(cat)
|
||||
|
||||
return valid
|
||||
|
||||
if isinstance(category, str) and category != "":
|
||||
return [category]
|
||||
else:
|
||||
return []
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def clean_html(raw_html):
|
||||
|
@ -201,7 +211,7 @@ def yield_amount(yld) -> str:
|
|||
|
||||
|
||||
def clean_time(time_entry):
|
||||
if time_entry is None:
|
||||
if time_entry is None or time_entry == "" or time_entry == " ":
|
||||
return None
|
||||
elif isinstance(time_entry, timedelta):
|
||||
return pretty_print_timedelta(time_entry)
|
||||
|
@ -214,13 +224,11 @@ def clean_time(time_entry):
|
|||
return pretty_print_timedelta(time_delta_object)
|
||||
except ValueError:
|
||||
logger.error(f"Could not parse time_entry `{time_entry}`")
|
||||
return str(time_entry)
|
||||
else:
|
||||
return str(time_entry)
|
||||
|
||||
|
||||
# ! TODO: Cleanup Code Below
|
||||
|
||||
|
||||
def parse_duration(iso_duration):
|
||||
"""Parses an ISO 8601 duration string into a datetime.timedelta instance.
|
||||
Args:
|
||||
|
@ -253,8 +261,9 @@ def parse_duration(iso_duration):
|
|||
def pretty_print_timedelta(t: timedelta, max_components=None, max_decimal_places=2):
|
||||
"""
|
||||
Print a pretty string for a timedelta.
|
||||
For example datetime.timedelta(days=2, seconds=17280) will be printed as '2 days 4 Hours 48 Minutes'. Setting max_components to e.g. 1 will change this to '2.2 days', where the
|
||||
number of decimal points can also be set.
|
||||
For example datetime.timedelta(days=2, seconds=17280) will be printed as '2 days 4 Hours 48 Minutes'.
|
||||
Setting max_components to e.g. 1 will change this to '2.2 days', where the number of decimal
|
||||
points can also be set.
|
||||
"""
|
||||
time_scale_names_dict = {
|
||||
timedelta(days=365): "year",
|
||||
|
|
|
@ -6,8 +6,8 @@ from pytest import fixture
|
|||
from mealie.app import app
|
||||
from mealie.db.db_setup import SessionLocal, generate_session
|
||||
from mealie.db.init_db import main
|
||||
from tests import data as test_data
|
||||
from tests.fixtures import * # noqa: F403 F401
|
||||
from tests.test_config import TEST_DATA
|
||||
|
||||
main()
|
||||
|
||||
|
@ -35,9 +35,9 @@ def api_client():
|
|||
|
||||
@fixture(scope="session")
|
||||
def test_image_jpg():
|
||||
return TEST_DATA.joinpath("images", "test_image.jpg")
|
||||
return test_data.images_test_image_1
|
||||
|
||||
|
||||
@fixture(scope="session")
|
||||
def test_image_png():
|
||||
return TEST_DATA.joinpath("images", "test_image.png")
|
||||
return test_data.images_test_image_2
|
||||
|
|
60
tests/data/__init__.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
from pathlib import Path
|
||||
|
||||
CWD = Path(__file__).parent
|
||||
|
||||
|
||||
migrations_paprika = CWD / "migrations/paprika.zip"
|
||||
|
||||
migrations_chowdown = CWD / "migrations/chowdown.zip"
|
||||
|
||||
migrations_mealie = CWD / "migrations/mealie.zip"
|
||||
|
||||
migrations_nextcloud = CWD / "migrations/nextcloud.zip"
|
||||
|
||||
images_test_image_1 = CWD / "images/test-image-1.jpg"
|
||||
|
||||
images_test_image_2 = CWD / "images/test-image-2.png"
|
||||
|
||||
html_sous_vide_smoked_beef_ribs = CWD / "html/sous-vide-smoked-beef-ribs.html"
|
||||
|
||||
html_sous_vide_shrimp = CWD / "html/sous-vide-shrimp.html"
|
||||
|
||||
html_jam_roly_poly_with_custard = CWD / "html/jam-roly-poly-with-custard.html"
|
||||
|
||||
html_taiwanese_three_cup_chicken_san_bei_gi_recipe = CWD / "html/taiwanese-three-cup-chicken-san-bei-gi-recipe.html"
|
||||
|
||||
html_detroit_style_pepperoni_pizza = CWD / "html/detroit-style-pepperoni-pizza.html"
|
||||
|
||||
html_carottes_rapps_with_rice_and_sunflower_seeds = CWD / "html/carottes-rapps-with-rice-and-sunflower-seeds.html"
|
||||
|
||||
html_schinken_kase_waffeln_ohne_viel_schnickschnack = CWD / "html/schinken-kase-waffeln-ohne-viel-schnickschnack.html"
|
||||
|
||||
html_healthy_pasta_bake_60759 = CWD / "html/healthy-pasta-bake-60759.html"
|
||||
|
||||
json_instant_pot_chicken_and_potatoes = CWD / "json/instant-pot-chicken-and-potatoes.json"
|
||||
|
||||
json_jalapeno_popper_dip = CWD / "json/jalapeno-popper-dip.json"
|
||||
|
||||
json_best_homemade_salsa_recipe = CWD / "json/best-homemade-salsa-recipe.json"
|
||||
|
||||
json_how_to_make_instant_pot_spaghetti = CWD / "json/how-to-make-instant-pot-spaghetti.json"
|
||||
|
||||
json_pizza_knoblauch_champignon_paprika_vegan_html = CWD / "json/pizza-knoblauch-champignon-paprika-vegan-html.json"
|
||||
|
||||
json_bon_appetit = CWD / "json/bon-appetit.json"
|
||||
|
||||
json_moroccan_skirt_steak_with_roasted_pepper_couscous = (
|
||||
CWD / "json/moroccan-skirt-steak-with-roasted-pepper-couscous.json"
|
||||
)
|
||||
|
||||
json_microwave_sweet_potatoes_04783 = CWD / "json/microwave-sweet-potatoes-04783.json"
|
||||
|
||||
json_dairy_free_impossible_pumpkin_pie = CWD / "json/dairy-free-impossible-pumpkin-pie.json"
|
||||
|
||||
json_chunky_apple_cake = CWD / "json/chunky-apple-cake.json"
|
||||
|
||||
json_blue_cheese_stuffed_turkey_meatballs_with_raspberry_balsamic_glaze_2 = (
|
||||
CWD / "json/blue-cheese-stuffed-turkey-meatballs-with-raspberry-balsamic-glaze-2.json"
|
||||
)
|
||||
|
||||
json_instant_pot_kerala_vegetable_stew = CWD / "json/instant-pot-kerala-vegetable-stew.json"
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
tests/data/migrations/mealie.zip
Normal file
Before Width: | Height: | Size: 39 KiB |
|
@ -1,63 +0,0 @@
|
|||
{
|
||||
"@context": "http:\/\/schema.org",
|
||||
"@type": "Recipe",
|
||||
"name": "Air Fryer Shrimp",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Anna"
|
||||
},
|
||||
"description": "These Air Fryer Shrimp are plump, juicy and perfectly seasoned! This healthy dish is ready in just 8 minutes and requires pantry staples to make it.",
|
||||
"datePublished": "2020-07-13T16:48:25+00:00",
|
||||
"image": "https:\/\/www.crunchycreamysweet.com\/wp-content\/uploads\/2020\/07\/air-fryer-shrimp-A-480x270.jpg",
|
||||
"recipeYield": 4,
|
||||
"prepTime": "PT0H15M",
|
||||
"cookTime": "PT0H8M",
|
||||
"totalTime": "PT0H23M",
|
||||
"recipeIngredient": [
|
||||
"1 lb shrimp",
|
||||
"2 teaspoons olive oil",
|
||||
"\u00bd teaspoon garlic powder",
|
||||
"\u00bc teaspoon paprika",
|
||||
"\u00bd teaspoon Italian seasoning",
|
||||
"\u00bd teaspoon salt",
|
||||
"\u00bc teaspoon black pepper"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
"Cleaning the shrimp by removing shells and veins. Run under tap water, then pat dry with paper towel.",
|
||||
"Mix oil with seasoning in a small bowl.",
|
||||
"Brush shrimp with seasoning mixture on both sides.",
|
||||
"Arrange shrimp in air fryer basket or rack, in a single layer.",
|
||||
"Cook at 400 degrees F for 8 minutes (no need to turn them).",
|
||||
"Serve."
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "5",
|
||||
"ratingCount": "4"
|
||||
},
|
||||
"recipeCategory": "Main Course",
|
||||
"recipeCuisine": [
|
||||
"American"
|
||||
],
|
||||
"keywords": "air fryer shrimp",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "134 kcal",
|
||||
"carbohydrateContent": "1 g",
|
||||
"proteinContent": "23 g",
|
||||
"fatContent": "4 g",
|
||||
"saturatedFatContent": "1 g",
|
||||
"cholesterolContent": "286 mg",
|
||||
"sodiumContent": "1172 mg",
|
||||
"fiberContent": "1 g",
|
||||
"sugarContent": "1 g",
|
||||
"servingSize": "1 serving"
|
||||
},
|
||||
"@id": "https:\/\/www.crunchycreamysweet.com\/air-fryer-shrimp\/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https:\/\/www.crunchycreamysweet.com\/air-fryer-shrimp\/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https:\/\/www.crunchycreamysweet.com\/air-fryer-shrimp\/#webpage",
|
||||
"tool": [],
|
||||
"url": "https:\/\/www.crunchycreamysweet.com\/air-fryer-shrimp\/"
|
||||
}
|
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 114 KiB |
|
@ -1,259 +0,0 @@
|
|||
{
|
||||
"@context": "http:\/\/schema.org",
|
||||
"@type": "Recipe",
|
||||
"mainEntityOfPage": "https:\/\/www.allrecipes.com\/recipe\/8975\/chicken-parmigiana\/",
|
||||
"name": "Chicken Parmigiana",
|
||||
"image": "https:\/\/imagesvc.meredithcorp.io\/v3\/mm\/image?url=https%3A%2F%2Fimages.media-allrecipes.com%2Fuserphotos%2F10037.jpg",
|
||||
"datePublished": "1999-04-27T12:40:19.000Z",
|
||||
"description": "This is a very nice dinner for two. Serve it with your favorite pasta and tossed greens.",
|
||||
"prepTime": "PT0H30M",
|
||||
"cookTime": "PT1H0M",
|
||||
"totalTime": "PT1H30M",
|
||||
"recipeYield": 2,
|
||||
"recipeIngredient": [
|
||||
"1 egg, beaten",
|
||||
"2 ounces dry bread crumbs",
|
||||
"2 skinless, boneless chicken breast halves",
|
||||
"\u00be (16 ounce) jar spaghetti sauce",
|
||||
"2 ounces shredded mozzarella cheese",
|
||||
"\u00bc cup grated Parmesan cheese"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
"Preheat oven to 350 degrees F (175 degrees C). Lightly grease a medium baking sheet.\n",
|
||||
"Pour egg into a small shallow bowl. Place bread crumbs in a separate shallow bowl. Dip chicken into egg, then into the bread crumbs. Place coated chicken on the prepared baking sheet and bake in the preheated oven for 40 minutes, or until no longer pink and juices run clear.\n",
|
||||
"Pour 1\/2 of the spaghetti sauce into a 7x11 inch baking dish. Place chicken over sauce, and cover with remaining sauce. Sprinkle mozzarella and Parmesan cheeses on top and return to the preheated oven for 20 minutes.\n"
|
||||
],
|
||||
"recipeCategory": "World Cuisine Recipes",
|
||||
"recipeCuisine": [],
|
||||
"author": [
|
||||
{
|
||||
"@type": "Person",
|
||||
"name": "Candy"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": 4.580034423407917,
|
||||
"ratingCount": 1743,
|
||||
"itemReviewed": "Chicken Parmigiana",
|
||||
"bestRating": "5",
|
||||
"worstRating": "1"
|
||||
},
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "528.3 calories",
|
||||
"carbohydrateContent": "44.9 g",
|
||||
"cholesterolContent": "184.1 mg",
|
||||
"fatContent": "18.3 g",
|
||||
"fiberContent": "5.6 g",
|
||||
"proteinContent": "43.5 g",
|
||||
"saturatedFatContent": "7.6 g",
|
||||
"servingSize": null,
|
||||
"sodiumContent": "1309.5 mg",
|
||||
"sugarContent": "17.2 g",
|
||||
"transFatContent": null,
|
||||
"unsaturatedFatContent": null
|
||||
},
|
||||
"review": [
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2004-02-10T10:18:54.927Z",
|
||||
"reviewBody": "This is a DELICIOUS basic recipe. I have been doing a similar one for years. I also, prefer adding a few more spices TO THE BREAD CRUMBS,like basil, oregano, garlic powder, salt, fresh cracked pepper and onion powder, and a few TBSP of the parmensan cheese;not only ON IT later. For some reason these spices (added separately) are good, but we don't like with an pre-mix of \"Italian\"spice. It seems to taste a little \"soapy\". Not sure which spice does that to it.? Some suggested to \"double dip\" in bread crumbs;if you do, you should really LIKE a heavy battering. It was too thick for our tastes(esp. since you bake in the sauce; to me,the bottom gets a little mushy, and it just adds extra fat and calories). I also use a cookie cooling \"RACK\" SET ON TOP of a baking sheet, to bake the chicken on instead of just on the cookie sheet pan. It comes out much crisper; letting air get to the BOTTOM of the chicken,also. Also,I wait to spoon the SECOND 1\/2 of the sauce UNTIL SERVING, the chicken will stay crisper,(even with the cheese on top). Obviously, we like the chicken on the crisp side (but we don't want to deep fry).\r\nFor company, put the chicken (with just the cheese baked on top) ON TOP of a small mound of spaghetti and sauce,or any pasta; It makes for a delicious looking presentation. A side salad with some sort of CREAMY dressing seems to compliment the red sauce, and completes the meal wonderfully. We get cravings for this one about 2c a month!",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "somethingdifferentagain?!",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/342976\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2004-01-23T16:37:02.013Z",
|
||||
"reviewBody": "This was an extremely easy, very tasty recipe. As many others suggested, I only put sauce on the bottom of the chicken and then spooned a little over the top when serving. I think the recipe could be improved, though, by (1) pounding the chicken to a uniform thickness and (2) by spicing up the bread crumbs. I used Italian bread crumbs but next time will sprinkle pepper on the chicken before dredging through the crumbs, and I also plan to add more Italian seasoning and maybe a little parmesan to the crumbs. Both these steps, in my opinion, would take this from a really good recipe to an excellent dish!",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "JBAGNALL",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/642772\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2005-11-19T20:22:40.53Z",
|
||||
"reviewBody": "I BRINED my chicken in 4 cups water , 1\/2 cup kosher salt (1\/4 table salt) \u00bd cup sugar for 30 minutes. No need to brine if you are using quick frozen chicken that has been enhanced. Kosher chicken is prebrined. Brining=juicy chicken. Took brined chicken, cut off thin edges, pounded out & shook chicken w\/flour (preflouring allows bread crumbs to stick) in a Ziploc-letting floured chicken sit for 5 min. I heated 6 TBS vegetable oil till it shimmered & then added 2 TBS butter to my pan, reserving half of this mixture for my second batch. Bread crumb mixture: I use \u00bd cup seasoned bread crumbs(same as 2 ounces), \u00bd cup grated parmesan( double what recipe calls for), 1tsp. Mrs. Dash Garlic and Herb, \u00bd tsp. garlic powder, \u00bd tsp, onion powder, \u00bd tsp. Italian seasoning & a pinch of pepper. Took pre-floured chicken, coated it with egg mixture, then dipped in bread crumbs & FRIED the chicken to a medium golden brown. Shook some parmesan on them right away when done frying to absorb any oil. Side-by side I plated plain spaghetti noodles & cutlets, w\/2 TBSP sauce on cutlet & desired amount of sauce on pasta, covered in cheese & baked each individual plate till cheese melted, serving them straight out of the oven. \r\nThe reviews on this were probably the best I have ever gotten, I used to work in an Italian Restaurant owned by NY Italians & have picked up some techniques. My Fettuccine Alfredo used to be my husband favorite dish, after last night he told me he has a new favorite. \r\n",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "KC MARTEL",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/526291\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-10-22T15:32:26.607Z",
|
||||
"reviewBody": "After several Chicken Parm recipes THIS is THE ONE:-) I've finally found one that we all love! It's simple and it's darned good:-) I will definately make this recipe again and again; thanks so much:-)",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "STARCHILD1166",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/736533\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-11-14T16:55:26.39Z",
|
||||
"reviewBody": "This chicken was so easy to make and turned out excellent! Used Best Marinara Sauce Yet (found here as well)instead of regular spaghetti sauce. This added even more flavor.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Alison",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/516223\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-01-23T04:38:19.873Z",
|
||||
"reviewBody": "I REALLY liked this recipe. I made my own spaghetti sauce and used parmesan reggiano. I also skipped dipping the breasts in egg as I thought it was unnecessary and it was. Cooking temp. and time are accurate. Even my fussy fiance liked this. I'll definitely make this again.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "CSANDST1",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/115553\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-08-05T20:26:00.81Z",
|
||||
"reviewBody": "Wow! This was really tasty and simple. Something quick to make when you can't spend too much time figuring out what's for dinner. Also great on a toasted roll\/hero as a sandwich. I varied the recipe a little by adding some parmesan cheese (big cheese lover that I am!), garlic powder, onion powder and some salt into the bread crumbs and then mixing it up before breading the chicken with it. Also added a little salt to the beaten egg to make sure the chicken wouldn't end up bland, but that's just my preference. In response to the one reviewer who wanted thicker breading, what I did was double dip the chicken - coat first with the bread crumbs, then dip into the beaten egg and re-coat with breadcrumbs before actually baking (this would require some more breadcrumbs and probably another egg). Excellent recipe! =]",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "LIZCHAO74",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/511187\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-07-23T07:53:37.18Z",
|
||||
"reviewBody": "Wonderful chicken recipe! I have made this several times. One night we were craving it and I didn't have any bottled spaghetti sauce. I poured a 14 ounce can of tomato sauce in a microwave bowl added 2t Italian Seasoning and 1t of garlic powder cooked on high for 6 minutes and ended up with a rich thick sauce for the chicken.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "MAGGIE MCGUIRE",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/392086\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2008-06-10T21:54:38.893Z",
|
||||
"reviewBody": "This is gonna be one of those it\u2019s a good recipe when you completely change it reviews. I did originally follow the recipe and the chicken tasted like it had been in breaded in cardboard. It just was not appetizing. However there is a great breaded chicken recipe on this site, garlic chicken. Made this simple and easy and oh so TASTY. I got great reviews. Here is what I did. Took \u00bc cup olive oil with 3 cloves garlic crushed and heated in microwave for 30 sec. Then coated the chicken in the oil and dipped in a mixture of \u00bd Italian seasoned bread crumbs and \u00bd parmesan cheese (double coat if u like thick breading). Cooked in oven at 325 for 20min (on a foil covered cookie sheet to make clean up easy). Set them in a casserole dish on top of about \u00bd a jar of spaghetti sauce for 3 chicken breast. Covered the breast with slices of mozzarella cheese and baked for another 20-25 minutes. Top with parmesan cheese. This turned out really really yummy and smells sooo good while it\u2019s cooking. ",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "ANGEL.9",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/218599\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2006-02-02T19:05:24.607Z",
|
||||
"reviewBody": "Check out \"Tomato Chicken Parmesan\" on this site for a truly fabulous chicken parm recipe. Every time I make that one people say its the best chicken parm they every had. No matter what kind you make though always pound your chicken breasts it will help immensely keeping the chicken tender and moist.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 3
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "MomSavedbyGrace",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/1366670\/"
|
||||
}
|
||||
}
|
||||
],
|
||||
"video": {
|
||||
"@context": "http:\/\/schema.org",
|
||||
"@type": "VideoObject",
|
||||
"name": "Chicken Parmigiana",
|
||||
"description": "Make this quick and easy version of chicken Parmigiana.",
|
||||
"uploadDate": "2012-05-23T22:01:40.476Z",
|
||||
"duration": "PT2M18.43S",
|
||||
"thumbnailUrl": "https:\/\/imagesvc.meredithcorp.io\/v3\/mm\/image?url=https%3A%2F%2Fcf-images.us-east-1.prod.boltdns.net%2Fv1%2Fstatic%2F1033249144001%2F15c9e37d-979a-4c2c-a35d-fc3f436b0047%2F6b7f7749-9989-4707-971e-8578e60c0670%2F160x90%2Fmatch%2Fimage.jpg",
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "Allrecipes",
|
||||
"url": "https:\/\/www.allrecipes.com",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https:\/\/www.allrecipes.com\/img\/logo.png",
|
||||
"width": 209,
|
||||
"height": 60
|
||||
},
|
||||
"sameAs": [
|
||||
"https:\/\/www.facebook.com\/allrecipes",
|
||||
"https:\/\/twitter.com\/Allrecipes",
|
||||
"https:\/\/www.pinterest.com\/allrecipes\/",
|
||||
"https:\/\/www.instagram.com\/allrecipes\/"
|
||||
]
|
||||
},
|
||||
"embedUrl": "https:\/\/players.brightcove.net\/1033249144001\/default_default\/index.html?videoId=1653498713001"
|
||||
},
|
||||
"keywords": "",
|
||||
"tool": [],
|
||||
"url": "https:\/\/www.allrecipes.com\/recipe\/8975\/chicken-parmigiana\/"
|
||||
}
|
Before Width: | Height: | Size: 10 KiB |
|
@ -1,89 +0,0 @@
|
|||
{
|
||||
"@context": "http:\/\/schema.org",
|
||||
"@type": "Recipe",
|
||||
"name": "Skillet Shepherd's Pie",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Joanna Cismaru"
|
||||
},
|
||||
"description": "This Skillet Shepherd's Pie recipe, also known as cottage pie, is loaded with flavorful beef and veggies, topped with fluffy and creamy mashed potatoes, then baked to perfection!",
|
||||
"datePublished": "2019-03-16T20:15:47+00:00",
|
||||
"image": "https:\/\/www.jocooks.com\/wp-content\/uploads\/2016\/12\/skillet-shepherds-pie-1-2-480x270.jpg",
|
||||
"video": {
|
||||
"name": "Skillet Shepherd's Pie",
|
||||
"description": "This skillet shepherd\u2019s pie is loaded with flavorful beef and veggies then topped with fluffy and creamy mashed potatoes, then baked to perfection!",
|
||||
"thumbnailUrl": "https:\/\/content.jwplatform.com\/thumbs\/HGr48vds-720.jpg",
|
||||
"contentUrl": "https:\/\/content.jwplatform.com\/videos\/HGr48vds.mp4",
|
||||
"uploadDate": "2018-03-08T16:13:05.000Z",
|
||||
"@type": "VideoObject"
|
||||
},
|
||||
"recipeYield": 1,
|
||||
"prepTime": "PT0H15M",
|
||||
"cookTime": "PT1H10M",
|
||||
"totalTime": "PT1H25M",
|
||||
"recipeIngredient": [
|
||||
"1 tbsp olive oil",
|
||||
"1 1\/4 lb ground beef (lean)",
|
||||
"1\/2 tsp salt (or to taste)",
|
||||
"1\/2 tsp pepper (or to taste)",
|
||||
"1 large onion (chopped)",
|
||||
"1 clove garlic (minced)",
|
||||
"1\/2 tsp red pepper flakes",
|
||||
"2 tbsp Worcestershire sauce",
|
||||
"1.9 oz onion soup mix (I used Knorr, 55g pkg)",
|
||||
"1 cup beef broth (low sodium)",
|
||||
"2 cups frozen veggies (I used mix of peas, carrots, green beans and corn)",
|
||||
"6 large potatoes (peeled and cut into cubes)",
|
||||
"4 tbsp butter (softened)",
|
||||
"2\/3 cup milk",
|
||||
"1\/4 cup Parmesan cheese",
|
||||
"1\/2 tsp salt (or to taste)",
|
||||
"1\/2 tsp white pepper (or to taste)",
|
||||
"1 tbsp parsley (fresh, for garnish)"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
"Boil the potatoes: Start by first cooking the potatoes in boiling water for about 15 minutes or until fork tender. While the potatoes are cooking, you can prepare the meat mixture.",
|
||||
"Prepare the meat mixture: Heat the oil in a large skillet over medium heat. Add the ground beef to the skillet, season it with the salt and pepper and cook it for abut 5 minutes or until it's no longer pink, breaking it up as you go along.",
|
||||
"Add the onion and garlic and cook for 3 more minutes until the onion softens and becomes translucent. Add the pepper flakes, Worcestershire sauce, onion soup mix, beef broth and stir. Stir in the frozen veggies and cook for a couple more minutes. Set aside.",
|
||||
"Preheat the oven 350 F degrees.",
|
||||
"Prepare the mashed potatoes: Drain the potatoes then add them to a large bowl. Add in the butter and using a potato masher, mash until smooth. Add the milk, Parmesan cheese, salt pepper and mash a bit a more until smooth.",
|
||||
"Finish assembling the shepherd's pie: Spread the potatoes over the meat and smooth with a spoon. Take a fork and rough up the top a bit and garnish with a bit of parsley.",
|
||||
"Bake: Place the skillet on a baking sheet, then place it in the oven and bake for 40 minutes until golden brown on top.",
|
||||
"Garnish with more parsley and pepper and serve warm."
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "4.48",
|
||||
"ratingCount": "505"
|
||||
},
|
||||
"recipeCategory": "Main Course",
|
||||
"recipeCuisine": [
|
||||
"American"
|
||||
],
|
||||
"keywords": "cottage pie,shepherd's pie,skillet shepherd's pie",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "252 kcal",
|
||||
"carbohydrateContent": "14 g",
|
||||
"proteinContent": "19 g",
|
||||
"fatContent": "12 g",
|
||||
"saturatedFatContent": "6 g",
|
||||
"cholesterolContent": "63 mg",
|
||||
"sodiumContent": "1165 mg",
|
||||
"fiberContent": "2 g",
|
||||
"sugarContent": "2 g",
|
||||
"servingSize": "1 serving"
|
||||
},
|
||||
"@id": "https:\/\/www.jocooks.com\/recipes\/skillet-shepherds-pie\/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https:\/\/www.jocooks.com\/recipes\/skillet-shepherds-pie\/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https:\/\/www.jocooks.com\/recipes\/skillet-shepherds-pie\/#webpage",
|
||||
"url": "https:\/\/www.jocooks.com\/recipes\/skillet-shepherds-pie\/",
|
||||
"id": "4485",
|
||||
"dateCreated": "0",
|
||||
"dateModified": "1607461134",
|
||||
"printImage": "false",
|
||||
"imageUrl": "\/nextcloud\/index.php\/apps\/cookbook\/recipes\/4485\/image?size=full",
|
||||
"tool": []
|
||||
}
|
BIN
tests/data/migrations/paprika.zip
Normal file
|
@ -1,63 +0,0 @@
|
|||
{
|
||||
"@context": "http:\/\/schema.org",
|
||||
"@type": "Recipe",
|
||||
"name": "Air Fryer Shrimp",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Anna"
|
||||
},
|
||||
"description": "These Air Fryer Shrimp are plump, juicy and perfectly seasoned! This healthy dish is ready in just 8 minutes and requires pantry staples to make it.",
|
||||
"datePublished": "2020-07-13T16:48:25+00:00",
|
||||
"image": "https:\/\/www.crunchycreamysweet.com\/wp-content\/uploads\/2020\/07\/air-fryer-shrimp-A-480x270.jpg",
|
||||
"recipeYield": 4,
|
||||
"prepTime": "PT0H15M",
|
||||
"cookTime": "PT0H8M",
|
||||
"totalTime": "PT0H23M",
|
||||
"recipeIngredient": [
|
||||
"1 lb shrimp",
|
||||
"2 teaspoons olive oil",
|
||||
"\u00bd teaspoon garlic powder",
|
||||
"\u00bc teaspoon paprika",
|
||||
"\u00bd teaspoon Italian seasoning",
|
||||
"\u00bd teaspoon salt",
|
||||
"\u00bc teaspoon black pepper"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
"Cleaning the shrimp by removing shells and veins. Run under tap water, then pat dry with paper towel.",
|
||||
"Mix oil with seasoning in a small bowl.",
|
||||
"Brush shrimp with seasoning mixture on both sides.",
|
||||
"Arrange shrimp in air fryer basket or rack, in a single layer.",
|
||||
"Cook at 400 degrees F for 8 minutes (no need to turn them).",
|
||||
"Serve."
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "5",
|
||||
"ratingCount": "4"
|
||||
},
|
||||
"recipeCategory": "Main Course",
|
||||
"recipeCuisine": [
|
||||
"American"
|
||||
],
|
||||
"keywords": "air fryer shrimp",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "134 kcal",
|
||||
"carbohydrateContent": "1 g",
|
||||
"proteinContent": "23 g",
|
||||
"fatContent": "4 g",
|
||||
"saturatedFatContent": "1 g",
|
||||
"cholesterolContent": "286 mg",
|
||||
"sodiumContent": "1172 mg",
|
||||
"fiberContent": "1 g",
|
||||
"sugarContent": "1 g",
|
||||
"servingSize": "1 serving"
|
||||
},
|
||||
"@id": "https:\/\/www.crunchycreamysweet.com\/air-fryer-shrimp\/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https:\/\/www.crunchycreamysweet.com\/air-fryer-shrimp\/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https:\/\/www.crunchycreamysweet.com\/air-fryer-shrimp\/#webpage",
|
||||
"tool": [],
|
||||
"url": "https:\/\/www.crunchycreamysweet.com\/air-fryer-shrimp\/"
|
||||
}
|
Before Width: | Height: | Size: 5.7 KiB |
|
@ -1,259 +0,0 @@
|
|||
{
|
||||
"@context": "http:\/\/schema.org",
|
||||
"@type": "Recipe",
|
||||
"mainEntityOfPage": "https:\/\/www.allrecipes.com\/recipe\/8975\/chicken-parmigiana\/",
|
||||
"name": "Chicken Parmigiana",
|
||||
"image": "https:\/\/imagesvc.meredithcorp.io\/v3\/mm\/image?url=https%3A%2F%2Fimages.media-allrecipes.com%2Fuserphotos%2F10037.jpg",
|
||||
"datePublished": "1999-04-27T12:40:19.000Z",
|
||||
"description": "This is a very nice dinner for two. Serve it with your favorite pasta and tossed greens.",
|
||||
"prepTime": "PT0H30M",
|
||||
"cookTime": "PT1H0M",
|
||||
"totalTime": "PT1H30M",
|
||||
"recipeYield": 2,
|
||||
"recipeIngredient": [
|
||||
"1 egg, beaten",
|
||||
"2 ounces dry bread crumbs",
|
||||
"2 skinless, boneless chicken breast halves",
|
||||
"\u00be (16 ounce) jar spaghetti sauce",
|
||||
"2 ounces shredded mozzarella cheese",
|
||||
"\u00bc cup grated Parmesan cheese"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
"Preheat oven to 350 degrees F (175 degrees C). Lightly grease a medium baking sheet.\n",
|
||||
"Pour egg into a small shallow bowl. Place bread crumbs in a separate shallow bowl. Dip chicken into egg, then into the bread crumbs. Place coated chicken on the prepared baking sheet and bake in the preheated oven for 40 minutes, or until no longer pink and juices run clear.\n",
|
||||
"Pour 1\/2 of the spaghetti sauce into a 7x11 inch baking dish. Place chicken over sauce, and cover with remaining sauce. Sprinkle mozzarella and Parmesan cheeses on top and return to the preheated oven for 20 minutes.\n"
|
||||
],
|
||||
"recipeCategory": "World Cuisine Recipes",
|
||||
"recipeCuisine": [],
|
||||
"author": [
|
||||
{
|
||||
"@type": "Person",
|
||||
"name": "Candy"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": 4.580034423407917,
|
||||
"ratingCount": 1743,
|
||||
"itemReviewed": "Chicken Parmigiana",
|
||||
"bestRating": "5",
|
||||
"worstRating": "1"
|
||||
},
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "528.3 calories",
|
||||
"carbohydrateContent": "44.9 g",
|
||||
"cholesterolContent": "184.1 mg",
|
||||
"fatContent": "18.3 g",
|
||||
"fiberContent": "5.6 g",
|
||||
"proteinContent": "43.5 g",
|
||||
"saturatedFatContent": "7.6 g",
|
||||
"servingSize": null,
|
||||
"sodiumContent": "1309.5 mg",
|
||||
"sugarContent": "17.2 g",
|
||||
"transFatContent": null,
|
||||
"unsaturatedFatContent": null
|
||||
},
|
||||
"review": [
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2004-02-10T10:18:54.927Z",
|
||||
"reviewBody": "This is a DELICIOUS basic recipe. I have been doing a similar one for years. I also, prefer adding a few more spices TO THE BREAD CRUMBS,like basil, oregano, garlic powder, salt, fresh cracked pepper and onion powder, and a few TBSP of the parmensan cheese;not only ON IT later. For some reason these spices (added separately) are good, but we don't like with an pre-mix of \"Italian\"spice. It seems to taste a little \"soapy\". Not sure which spice does that to it.? Some suggested to \"double dip\" in bread crumbs;if you do, you should really LIKE a heavy battering. It was too thick for our tastes(esp. since you bake in the sauce; to me,the bottom gets a little mushy, and it just adds extra fat and calories). I also use a cookie cooling \"RACK\" SET ON TOP of a baking sheet, to bake the chicken on instead of just on the cookie sheet pan. It comes out much crisper; letting air get to the BOTTOM of the chicken,also. Also,I wait to spoon the SECOND 1\/2 of the sauce UNTIL SERVING, the chicken will stay crisper,(even with the cheese on top). Obviously, we like the chicken on the crisp side (but we don't want to deep fry).\r\nFor company, put the chicken (with just the cheese baked on top) ON TOP of a small mound of spaghetti and sauce,or any pasta; It makes for a delicious looking presentation. A side salad with some sort of CREAMY dressing seems to compliment the red sauce, and completes the meal wonderfully. We get cravings for this one about 2c a month!",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "somethingdifferentagain?!",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/342976\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2004-01-23T16:37:02.013Z",
|
||||
"reviewBody": "This was an extremely easy, very tasty recipe. As many others suggested, I only put sauce on the bottom of the chicken and then spooned a little over the top when serving. I think the recipe could be improved, though, by (1) pounding the chicken to a uniform thickness and (2) by spicing up the bread crumbs. I used Italian bread crumbs but next time will sprinkle pepper on the chicken before dredging through the crumbs, and I also plan to add more Italian seasoning and maybe a little parmesan to the crumbs. Both these steps, in my opinion, would take this from a really good recipe to an excellent dish!",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "JBAGNALL",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/642772\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2005-11-19T20:22:40.53Z",
|
||||
"reviewBody": "I BRINED my chicken in 4 cups water , 1\/2 cup kosher salt (1\/4 table salt) \u00bd cup sugar for 30 minutes. No need to brine if you are using quick frozen chicken that has been enhanced. Kosher chicken is prebrined. Brining=juicy chicken. Took brined chicken, cut off thin edges, pounded out & shook chicken w\/flour (preflouring allows bread crumbs to stick) in a Ziploc-letting floured chicken sit for 5 min. I heated 6 TBS vegetable oil till it shimmered & then added 2 TBS butter to my pan, reserving half of this mixture for my second batch. Bread crumb mixture: I use \u00bd cup seasoned bread crumbs(same as 2 ounces), \u00bd cup grated parmesan( double what recipe calls for), 1tsp. Mrs. Dash Garlic and Herb, \u00bd tsp. garlic powder, \u00bd tsp, onion powder, \u00bd tsp. Italian seasoning & a pinch of pepper. Took pre-floured chicken, coated it with egg mixture, then dipped in bread crumbs & FRIED the chicken to a medium golden brown. Shook some parmesan on them right away when done frying to absorb any oil. Side-by side I plated plain spaghetti noodles & cutlets, w\/2 TBSP sauce on cutlet & desired amount of sauce on pasta, covered in cheese & baked each individual plate till cheese melted, serving them straight out of the oven. \r\nThe reviews on this were probably the best I have ever gotten, I used to work in an Italian Restaurant owned by NY Italians & have picked up some techniques. My Fettuccine Alfredo used to be my husband favorite dish, after last night he told me he has a new favorite. \r\n",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "KC MARTEL",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/526291\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-10-22T15:32:26.607Z",
|
||||
"reviewBody": "After several Chicken Parm recipes THIS is THE ONE:-) I've finally found one that we all love! It's simple and it's darned good:-) I will definately make this recipe again and again; thanks so much:-)",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "STARCHILD1166",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/736533\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-11-14T16:55:26.39Z",
|
||||
"reviewBody": "This chicken was so easy to make and turned out excellent! Used Best Marinara Sauce Yet (found here as well)instead of regular spaghetti sauce. This added even more flavor.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Alison",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/516223\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-01-23T04:38:19.873Z",
|
||||
"reviewBody": "I REALLY liked this recipe. I made my own spaghetti sauce and used parmesan reggiano. I also skipped dipping the breasts in egg as I thought it was unnecessary and it was. Cooking temp. and time are accurate. Even my fussy fiance liked this. I'll definitely make this again.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "CSANDST1",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/115553\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-08-05T20:26:00.81Z",
|
||||
"reviewBody": "Wow! This was really tasty and simple. Something quick to make when you can't spend too much time figuring out what's for dinner. Also great on a toasted roll\/hero as a sandwich. I varied the recipe a little by adding some parmesan cheese (big cheese lover that I am!), garlic powder, onion powder and some salt into the bread crumbs and then mixing it up before breading the chicken with it. Also added a little salt to the beaten egg to make sure the chicken wouldn't end up bland, but that's just my preference. In response to the one reviewer who wanted thicker breading, what I did was double dip the chicken - coat first with the bread crumbs, then dip into the beaten egg and re-coat with breadcrumbs before actually baking (this would require some more breadcrumbs and probably another egg). Excellent recipe! =]",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "LIZCHAO74",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/511187\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2003-07-23T07:53:37.18Z",
|
||||
"reviewBody": "Wonderful chicken recipe! I have made this several times. One night we were craving it and I didn't have any bottled spaghetti sauce. I poured a 14 ounce can of tomato sauce in a microwave bowl added 2t Italian Seasoning and 1t of garlic powder cooked on high for 6 minutes and ended up with a rich thick sauce for the chicken.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "MAGGIE MCGUIRE",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/392086\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2008-06-10T21:54:38.893Z",
|
||||
"reviewBody": "This is gonna be one of those it\u2019s a good recipe when you completely change it reviews. I did originally follow the recipe and the chicken tasted like it had been in breaded in cardboard. It just was not appetizing. However there is a great breaded chicken recipe on this site, garlic chicken. Made this simple and easy and oh so TASTY. I got great reviews. Here is what I did. Took \u00bc cup olive oil with 3 cloves garlic crushed and heated in microwave for 30 sec. Then coated the chicken in the oil and dipped in a mixture of \u00bd Italian seasoned bread crumbs and \u00bd parmesan cheese (double coat if u like thick breading). Cooked in oven at 325 for 20min (on a foil covered cookie sheet to make clean up easy). Set them in a casserole dish on top of about \u00bd a jar of spaghetti sauce for 3 chicken breast. Covered the breast with slices of mozzarella cheese and baked for another 20-25 minutes. Top with parmesan cheese. This turned out really really yummy and smells sooo good while it\u2019s cooking. ",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "ANGEL.9",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/218599\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2006-02-02T19:05:24.607Z",
|
||||
"reviewBody": "Check out \"Tomato Chicken Parmesan\" on this site for a truly fabulous chicken parm recipe. Every time I make that one people say its the best chicken parm they every had. No matter what kind you make though always pound your chicken breasts it will help immensely keeping the chicken tender and moist.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 3
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "MomSavedbyGrace",
|
||||
"image": null,
|
||||
"sameAs": "https:\/\/www.allrecipes.com\/cook\/1366670\/"
|
||||
}
|
||||
}
|
||||
],
|
||||
"video": {
|
||||
"@context": "http:\/\/schema.org",
|
||||
"@type": "VideoObject",
|
||||
"name": "Chicken Parmigiana",
|
||||
"description": "Make this quick and easy version of chicken Parmigiana.",
|
||||
"uploadDate": "2012-05-23T22:01:40.476Z",
|
||||
"duration": "PT2M18.43S",
|
||||
"thumbnailUrl": "https:\/\/imagesvc.meredithcorp.io\/v3\/mm\/image?url=https%3A%2F%2Fcf-images.us-east-1.prod.boltdns.net%2Fv1%2Fstatic%2F1033249144001%2F15c9e37d-979a-4c2c-a35d-fc3f436b0047%2F6b7f7749-9989-4707-971e-8578e60c0670%2F160x90%2Fmatch%2Fimage.jpg",
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "Allrecipes",
|
||||
"url": "https:\/\/www.allrecipes.com",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https:\/\/www.allrecipes.com\/img\/logo.png",
|
||||
"width": 209,
|
||||
"height": 60
|
||||
},
|
||||
"sameAs": [
|
||||
"https:\/\/www.facebook.com\/allrecipes",
|
||||
"https:\/\/twitter.com\/Allrecipes",
|
||||
"https:\/\/www.pinterest.com\/allrecipes\/",
|
||||
"https:\/\/www.instagram.com\/allrecipes\/"
|
||||
]
|
||||
},
|
||||
"embedUrl": "https:\/\/players.brightcove.net\/1033249144001\/default_default\/index.html?videoId=1653498713001"
|
||||
},
|
||||
"keywords": "",
|
||||
"tool": [],
|
||||
"url": "https:\/\/www.allrecipes.com\/recipe\/8975\/chicken-parmigiana\/"
|
||||
}
|
Before Width: | Height: | Size: 10 KiB |
|
@ -1,89 +0,0 @@
|
|||
{
|
||||
"@context": "http:\/\/schema.org",
|
||||
"@type": "Recipe",
|
||||
"name": "Skillet Shepherd's Pie",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Joanna Cismaru"
|
||||
},
|
||||
"description": "This Skillet Shepherd's Pie recipe, also known as cottage pie, is loaded with flavorful beef and veggies, topped with fluffy and creamy mashed potatoes, then baked to perfection!",
|
||||
"datePublished": "2019-03-16T20:15:47+00:00",
|
||||
"image": "https:\/\/www.jocooks.com\/wp-content\/uploads\/2016\/12\/skillet-shepherds-pie-1-2-480x270.jpg",
|
||||
"video": {
|
||||
"name": "Skillet Shepherd's Pie",
|
||||
"description": "This skillet shepherd\u2019s pie is loaded with flavorful beef and veggies then topped with fluffy and creamy mashed potatoes, then baked to perfection!",
|
||||
"thumbnailUrl": "https:\/\/content.jwplatform.com\/thumbs\/HGr48vds-720.jpg",
|
||||
"contentUrl": "https:\/\/content.jwplatform.com\/videos\/HGr48vds.mp4",
|
||||
"uploadDate": "2018-03-08T16:13:05.000Z",
|
||||
"@type": "VideoObject"
|
||||
},
|
||||
"recipeYield": 1,
|
||||
"prepTime": "PT0H15M",
|
||||
"cookTime": "PT1H10M",
|
||||
"totalTime": "PT1H25M",
|
||||
"recipeIngredient": [
|
||||
"1 tbsp olive oil",
|
||||
"1 1\/4 lb ground beef (lean)",
|
||||
"1\/2 tsp salt (or to taste)",
|
||||
"1\/2 tsp pepper (or to taste)",
|
||||
"1 large onion (chopped)",
|
||||
"1 clove garlic (minced)",
|
||||
"1\/2 tsp red pepper flakes",
|
||||
"2 tbsp Worcestershire sauce",
|
||||
"1.9 oz onion soup mix (I used Knorr, 55g pkg)",
|
||||
"1 cup beef broth (low sodium)",
|
||||
"2 cups frozen veggies (I used mix of peas, carrots, green beans and corn)",
|
||||
"6 large potatoes (peeled and cut into cubes)",
|
||||
"4 tbsp butter (softened)",
|
||||
"2\/3 cup milk",
|
||||
"1\/4 cup Parmesan cheese",
|
||||
"1\/2 tsp salt (or to taste)",
|
||||
"1\/2 tsp white pepper (or to taste)",
|
||||
"1 tbsp parsley (fresh, for garnish)"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
"Boil the potatoes: Start by first cooking the potatoes in boiling water for about 15 minutes or until fork tender. While the potatoes are cooking, you can prepare the meat mixture.",
|
||||
"Prepare the meat mixture: Heat the oil in a large skillet over medium heat. Add the ground beef to the skillet, season it with the salt and pepper and cook it for abut 5 minutes or until it's no longer pink, breaking it up as you go along.",
|
||||
"Add the onion and garlic and cook for 3 more minutes until the onion softens and becomes translucent. Add the pepper flakes, Worcestershire sauce, onion soup mix, beef broth and stir. Stir in the frozen veggies and cook for a couple more minutes. Set aside.",
|
||||
"Preheat the oven 350 F degrees.",
|
||||
"Prepare the mashed potatoes: Drain the potatoes then add them to a large bowl. Add in the butter and using a potato masher, mash until smooth. Add the milk, Parmesan cheese, salt pepper and mash a bit a more until smooth.",
|
||||
"Finish assembling the shepherd's pie: Spread the potatoes over the meat and smooth with a spoon. Take a fork and rough up the top a bit and garnish with a bit of parsley.",
|
||||
"Bake: Place the skillet on a baking sheet, then place it in the oven and bake for 40 minutes until golden brown on top.",
|
||||
"Garnish with more parsley and pepper and serve warm."
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "4.48",
|
||||
"ratingCount": "505"
|
||||
},
|
||||
"recipeCategory": "Main Course",
|
||||
"recipeCuisine": [
|
||||
"American"
|
||||
],
|
||||
"keywords": "cottage pie,shepherd's pie,skillet shepherd's pie",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "252 kcal",
|
||||
"carbohydrateContent": "14 g",
|
||||
"proteinContent": "19 g",
|
||||
"fatContent": "12 g",
|
||||
"saturatedFatContent": "6 g",
|
||||
"cholesterolContent": "63 mg",
|
||||
"sodiumContent": "1165 mg",
|
||||
"fiberContent": "2 g",
|
||||
"sugarContent": "2 g",
|
||||
"servingSize": "1 serving"
|
||||
},
|
||||
"@id": "https:\/\/www.jocooks.com\/recipes\/skillet-shepherds-pie\/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https:\/\/www.jocooks.com\/recipes\/skillet-shepherds-pie\/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https:\/\/www.jocooks.com\/recipes\/skillet-shepherds-pie\/#webpage",
|
||||
"url": "https:\/\/www.jocooks.com\/recipes\/skillet-shepherds-pie\/",
|
||||
"id": "4485",
|
||||
"dateCreated": "0",
|
||||
"dateModified": "1607461134",
|
||||
"printImage": "false",
|
||||
"imageUrl": "\/nextcloud\/index.php\/apps\/cookbook\/recipes\/4485\/image?size=full",
|
||||
"tool": []
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org",
|
||||
"@type": "Recipe",
|
||||
"image": "https://img.chefkoch-cdn.de/rezepte/2235331358009600/bilder/864648/crop-960x540/pizza-knoblauch-champignon-paprika-vegan.jpg",
|
||||
"recipeCategory": "Gem\u00fcse",
|
||||
"recipeIngredient": [
|
||||
"300 g Weizenmehl (Type 550)",
|
||||
"1 Pck. Trockenhefe",
|
||||
"1 TL Salz",
|
||||
"170 ml Wasser",
|
||||
"6 EL \u00d6l (Knoblauch\u00f6l oder Oliven\u00f6l)",
|
||||
"1 EL Tomatenmark",
|
||||
"n. B. Knoblauch , gew\u00fcrfelt",
|
||||
"2 Spitzpaprika oder Gem\u00fcsepaprika, rot",
|
||||
"250 g Champignons",
|
||||
"1 Zwiebel(n)",
|
||||
" Salz und Pfeffer",
|
||||
" Kr\u00e4uter , italienische, frisch oder getrocknet",
|
||||
" Harissa"
|
||||
],
|
||||
"name": "Pizza Knoblauch Champignon Paprika - vegan",
|
||||
"description": "Pizza Knoblauch Champignon Paprika - vegan - f\u00fcr Nicht-Veganer nat\u00fcrlich mit K\u00e4se zu belegen. \u00dcber 51 Bewertungen und f\u00fcr raffiniert befunden. Mit \u25ba Portionsrechner \u25ba Kochbuch \u25ba Video-Tipps!",
|
||||
"recipeInstructions": "Die Zutaten f\u00fcr den Teig verkneten und ca. 40 Minuten an einem warmen Ort gehen lassen. In der Zwischenzeit eine beliebige Anzahl Knoblauchzehen fein w\u00fcrfeln (ich bedecke die Pizza nahezu fl\u00e4chendeckend), die Zwiebel ebenfalls w\u00fcrfeln, Paprika und Champignons klein schneiden. Das \u00d6l mit Tomatenmark, Salz und Pfeffer vermischen. \r\n\r\nDen fertigen Teig ausrollen und auf ein Blech legen (ich benutze eine Pflaumenkuchen-Backform). Die \u00d6lmischung mit einem Backpinsel gleichm\u00e4\u00dfig auf dem Teig verteilen, danach mit dem Knoblauch, den Champignons, der Paprika und den Zwiebeln belegen. \r\n\r\nNun die Pizza mit Salz, Pfeffer, Kr\u00e4utern und Harissa kr\u00e4ftig w\u00fcrzen und bei 250\u00b0C ca. 10 - 15 Minuten backen. Der Teig ist als Grundteig zu betrachten und l\u00e4sst sich nat\u00fcrlich mit allem M\u00f6glichen an Gem\u00fcse belegen.",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "healing21"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "Chefkoch.de"
|
||||
},
|
||||
"datePublished": "2013-01-14",
|
||||
"prepTime": "P0DT0H20M",
|
||||
"cookTime": "P0DT0H15M",
|
||||
"totalTime": "P0DT1H15M",
|
||||
"recipeYield": "2 Portion(en)",
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingCount": 51,
|
||||
"ratingValue": 4.57,
|
||||
"reviewCount": 34,
|
||||
"worstRating": 0,
|
||||
"bestRating": 5
|
||||
},
|
||||
"keywords": [
|
||||
"Gem\u00fcse",
|
||||
"Hauptspeise",
|
||||
"Backen",
|
||||
"Vegetarisch",
|
||||
"einfach",
|
||||
"Vegan",
|
||||
"Pizza",
|
||||
"Pilze"
|
||||
],
|
||||
"reviews": [
|
||||
{
|
||||
"@type": "Review",
|
||||
"reviewBody": " Sehr gutes Basis Rezept!\n\nHab noch Salami, Kochschinken und K\u00e4se dazu gemacht, sonst schmeckt es ja nach nichts. \n\nErgebnis: 1. Klasse! Sehr fein! ",
|
||||
"datePublished": "2020-04-21",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "eierkopp1824"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"reviewBody": "Hallo,\r\nhabe den Teig gut zwei Stunden gehen lassen und dann wie im Rezept angegeben weiter verarbeitet. Da ich noch einige Schinkenw\u00fcrfel und etwas Fetak\u00e4se im K\u00fchlschrank hatte, wurden diese ebenfalls auf dem Belag verteilt. Ich habe die Pizza auf der untersten Schiene im Backofen gebacken. Der Boden ist nach dem Backen sch\u00f6n knusprig. Es hat mir und meinem Mitesser sehr gut geschmeckt.\r\nLG von Sternek\u00f6chin2011",
|
||||
"datePublished": "2020-03-10",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Sternek\u00f6chin2011"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"reviewBody": "Echt f\u00fcr mich die leckerste Pizza auf der Welt! Auch bei meiner Familie kommt sie super an und \u00fcberlebt nicht lange. :)\nDen Belag kann man ja variieren wie man will. ",
|
||||
"datePublished": "2020-02-20",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Leo090800"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"reviewBody": "Beste Pizza, die ich je gegessen habe! Sooo lecker! Habe f\u00fcr den Teig Dinkelvollkornmehl genommen und den Belag noch mit ein paar Chiliflocken verfeinert. ",
|
||||
"datePublished": "2018-04-15",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Sunny_Eyes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"reviewBody": "Der Teig ist super, ebenso wie die Sauce! Habe anstelle von normalem Salz Basilikumsalz in den Teig gegeben, das gibt dem ganzen einen besonderen Geschmack.Statt Paprika und Knobi habe ich K\u00e4se und Rucola hinzuef\u00fcgt, den Salat erst nach dem Backen. Die wird sicherlich nochmal gemacht! Da ich nur eine Pizza gemacht habe, habe ich den restlichen Teig eingefroren. Foto ist unterwegs!",
|
||||
"datePublished": "2018-02-14",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Chiqryn"
|
||||
}
|
||||
}
|
||||
],
|
||||
"url": "https://www.chefkoch.de/rezepte/2235331358009600/Pizza-Knoblauch-Champignon-Paprika-vegan.html"
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org/",
|
||||
"@type": "Recipe",
|
||||
"name": "The Best Homemade Salsa Recipe",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Sommer Collier"
|
||||
},
|
||||
"description": "How To Make Delicious Salsa: Secrets of making the Best Homemade Salsa Recipe! This restaurant style salsa recipe is loaded with flavor, has an amazing texture, and a secret ingredient.",
|
||||
"datePublished": "2020-02-01T00:00:30+00:00",
|
||||
"image": [
|
||||
"https://www.aspicyperspective.com/wp-content/uploads/2019/02/the-best-homemade-salsa-recipe-100.jpg",
|
||||
"https://www.aspicyperspective.com/wp-content/uploads/2019/02/the-best-homemade-salsa-recipe-100-500x500.jpg",
|
||||
"https://www.aspicyperspective.com/wp-content/uploads/2019/02/the-best-homemade-salsa-recipe-100-500x375.jpg",
|
||||
"https://www.aspicyperspective.com/wp-content/uploads/2019/02/the-best-homemade-salsa-recipe-100-480x270.jpg"
|
||||
],
|
||||
"video": {
|
||||
"name": "The Best Homemade Salsa Recipe",
|
||||
"description": "We\u2019re sharing our secrets for making The Best Homemade Salsa Recipe we\u2019ve ever tried. Healthy, fresh, and easy to adjust!",
|
||||
"thumbnailUrl": "https://content.jwplatform.com/thumbs/rPi8NdK6-720.jpg",
|
||||
"contentUrl": "https://content.jwplatform.com/videos/rPi8NdK6.mp4",
|
||||
"uploadDate": "2017-03-22T16:24:09.000Z",
|
||||
"@type": "VideoObject"
|
||||
},
|
||||
"recipeYield": [
|
||||
"20",
|
||||
"20 (5 cups)"
|
||||
],
|
||||
"prepTime": "PT5M",
|
||||
"totalTime": "PT5M",
|
||||
"recipeIngredient": [
|
||||
"4 ripe tomatoes, (cored and quartered)",
|
||||
"1 red onion, (peeled and quartered)",
|
||||
"3 garlic cloves, (peeled)",
|
||||
"3 jalapenos, (stemmed and seeded (you can\u00a0substitute 1-2 habanero or serrano peppers.))",
|
||||
"1/3 cup fresh cilantro",
|
||||
"3 tablespoons fresh lime juice",
|
||||
"2-3 teaspoons ground cumin",
|
||||
"2-3 teaspoons sugar ((optional))",
|
||||
"1 1/2 teaspoons salt",
|
||||
"15 ounces crushed San Marzano tomatoes ((1 can))",
|
||||
"4.5 ounces diced green chiles, (mild, medium, or hot (1 can))"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Place the fresh tomatoes, onion, garlic, peppers, cilantro, lime juice, 2 teaspoons cumin, 2 teaspoons sugar (if using), and salt in a food processor. Pulse until the contents are fine and well blended.",
|
||||
"name": "Place the fresh tomatoes, onion, garlic, peppers, cilantro, lime juice, 2 teaspoons cumin, 2 teaspoons sugar (if using), and salt in a food processor. Pulse until the contents are fine and well blended.",
|
||||
"url": "https://www.aspicyperspective.com/best-homemade-salsa-recipe/#wprm-recipe-61842-step-0-0"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Pour in the crushed tomatoes and green chiles. Puree until mostly smooth. Taste, then add more cumin and sugar if desired. Refrigerate until ready to serve.",
|
||||
"name": "Pour in the crushed tomatoes and green chiles. Puree until mostly smooth. Taste, then add more cumin and sugar if desired. Refrigerate until ready to serve.",
|
||||
"url": "https://www.aspicyperspective.com/best-homemade-salsa-recipe/#wprm-recipe-61842-step-0-1"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "4.98",
|
||||
"ratingCount": "201"
|
||||
},
|
||||
"recipeCategory": [
|
||||
"Appetizer",
|
||||
"Snack"
|
||||
],
|
||||
"recipeCuisine": [
|
||||
"American",
|
||||
"Mexican"
|
||||
],
|
||||
"keywords": "Homemade Salsa, Salsa, The Best Salsa Recipe",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"servingSize": "0.25 cup",
|
||||
"calories": "19 kcal",
|
||||
"carbohydrateContent": "4 g",
|
||||
"sodiumContent": "230 mg",
|
||||
"sugarContent": "2 g"
|
||||
},
|
||||
"@id": "https://www.aspicyperspective.com/best-homemade-salsa-recipe/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https://www.aspicyperspective.com/best-homemade-salsa-recipe/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https://www.aspicyperspective.com/best-homemade-salsa-recipe/#webpage",
|
||||
"url": "https://www.aspicyperspective.com/best-homemade-salsa-recipe/"
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"image": "https://www.cookingforkeeps.com/wp-content/uploads/2013/02/done-1.jpg",
|
||||
"aggregateRating": {
|
||||
"properties": {
|
||||
"ratingValue": "4.0",
|
||||
"ratingCount": "2"
|
||||
},
|
||||
"@type": "AggregateRating"
|
||||
},
|
||||
"name": "Blue Cheese Stuffed Turkey Meatballs with Raspberry Balsamic Glaze",
|
||||
"author": "Nicole-Cooking for Keeps",
|
||||
"recipeYield": "Makes 18-22 meatballs depending on size",
|
||||
"recipeInstructions": [
|
||||
"For the meatballs: Roll the blue cheese in small balls about the diameter of a dime. Freeze for 30 minutes. Preheat oven to 375 degrees. Mix the remaining ingredients together, until just combined. Roll sausage mixture into small balls. Place the blue cheese in the middle, enclosing with meat. Bake on a silt pad until golden brown and cooked through, about 25 min, turning halfway through to ensure even browning.",
|
||||
"For the Dipping Sauce:",
|
||||
"Combine all ingredients together in small sauce pan over medium high heat. Bring to a boil and then reduce heat and simmer about five minutes. Coat meatballs in sauce. Serve."
|
||||
],
|
||||
"@context": "http://schema.org",
|
||||
"@type": "Recipe",
|
||||
"url": "https://www.cookingforkeeps.com/blue-cheese-stuffed-turkey-meatballs-with-raspberry-balsamic-glaze-2/",
|
||||
"recipeIngredient": [
|
||||
"Sausage Bites",
|
||||
"3 oz creamy gorgonzola cheese",
|
||||
"1 lb turkey Italian sausage (schmicas) with fennel seed",
|
||||
"\u00bd cup Italian style bread crumbs",
|
||||
"\u00bd onion grated",
|
||||
"1 egg white",
|
||||
"Salt to taste",
|
||||
"Dipping Sauce:",
|
||||
"\u00bd cup raspberry preserves",
|
||||
"\u215b cup balsamic vinegar",
|
||||
"3 teaspoons Dijon mustard",
|
||||
"Pinch of red pepper",
|
||||
"Pinch of Salt"
|
||||
]
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org",
|
||||
"@type": "Recipe",
|
||||
"articleBody": "Atlanta pastry chef Claudia Martinez\u2019s family has been making what Martinez describes as meaty Venezuelan tamales around the holidays for generations. In the Martinez household, every family member has a task: Claudia\u2019s dad or grandmother always prepares the guiso, the tender shredded chicken and beef stew that comprises the bulk of the filling. One person slicks scoops of vibrant orange achiote-stained masa dough onto banana leaves, then passes them around the table to get filled. Claudia\u2019s grandma adds a spoonful of guiso; Claudia adds olives and capers; her sister adds a few raisins. Finally, each hallaca gets wrapped up in the fragrant leaves and tied with twine like a tiny present, ready to boil for a late Christmas Eve dinner. The Martinez family usually makes 100 at a time; this scaled-down version of their recipe makes just under 20, enough for a big dinner plus leftovers you can freeze for another day. If you find yourself with leftover masa and stew, do as the Martinezes do: Make arepas with guiso and fried eggs for breakfast on Christmas Day. (If you\u2019re in Atlanta in the days leading up to Christmas Eve, pick up hallacas at Caf\u00e9 Claudia, the pop-up Martinez runs out of the Hotel Clermont.)\nBanana leaves give a floral and grassy flavor to the hallacas, you can buy them either fresh or frozen at Latin and Asian markets. You can use parchment paper instead, but the outcome won\u2019t be as complex.",
|
||||
"alternativeHeadline": "The Venezuelan holiday dish that Atlanta pastry chef Claudia Martinez\u2019s family has been making for generations.",
|
||||
"dateModified": "2021-01-02 12:09:30.443000",
|
||||
"datePublished": "2020-12-01 07:00:00",
|
||||
"keywords": [
|
||||
"recipes",
|
||||
"holiday 2020",
|
||||
"new years eve",
|
||||
"olive oil",
|
||||
"beef",
|
||||
"chicken recipes",
|
||||
"kosher salt",
|
||||
"tomato",
|
||||
"garlic",
|
||||
"tomato paste",
|
||||
"onion",
|
||||
"bell pepper",
|
||||
"green onion scallion",
|
||||
"cilantro",
|
||||
"brown sugar",
|
||||
"cornmeal",
|
||||
"capers",
|
||||
"olive",
|
||||
"raisin",
|
||||
"web"
|
||||
],
|
||||
"thumbnailUrl": "https://assets.bonappetit.com/photos/5fb4407993a08c9bf97163f7/1:1/w_1125,h_1125,c_limit/1220-Hallacas.jpg",
|
||||
"publisher": {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"name": "Bon App\u00e9tit",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://www.bonappetit.com/verso/static/bon-appetit/assets/logo-seo.328de564b950e3d5d1fbe3e42f065290ca1d3844.png",
|
||||
"width": "479px",
|
||||
"height": "100px"
|
||||
},
|
||||
"url": "https://www.bonappetit.com"
|
||||
},
|
||||
"isPartOf": {
|
||||
"@type": [
|
||||
"CreativeWork",
|
||||
"Product"
|
||||
],
|
||||
"name": "Bon App\u00e9tit"
|
||||
},
|
||||
"isAccessibleForFree": true,
|
||||
"author": [
|
||||
{
|
||||
"@type": "Person",
|
||||
"name": "Claudia Martinez",
|
||||
"sameAs": "https://bon-appetit.com/contributor/claudia-martinez/"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": 5,
|
||||
"ratingCount": 22
|
||||
},
|
||||
"description": "The Venezuelan holiday dish that Atlanta pastry chef Claudia Martinez\u2019s family has been making for generations.",
|
||||
"image": "hallacas.jpg",
|
||||
"name": "Hallacas",
|
||||
"recipeIngredient": [
|
||||
"1\u00bd cups extra-virgin olive oil",
|
||||
"3 Tbsp. plus 1\u00bd tsp. achiote (annatto) seeds",
|
||||
"2\u00bd lb. boneless beef chuck roast",
|
||||
"2\u00bd lb. skinless, boneless chicken breasts",
|
||||
"1 Tbsp. Diamond Crystal or 1\u00be tsp. Morton kosher salt, plus more",
|
||||
"3 medium tomatoes, coarsely chopped",
|
||||
"3 garlic cloves",
|
||||
"1 6-oz. can tomato paste",
|
||||
"1 medium onion, chopped",
|
||||
"1 large red bell pepper, seeds and ribs removed, coarsely chopped",
|
||||
"1 large green bell pepper, seeds and ribs removed, coarsely chopped",
|
||||
"1 bunch scallions, coarsely chopped",
|
||||
"1 bunch cilantro, coarsely chopped",
|
||||
"\u00bc cup (packed) light brown sugar",
|
||||
"1 1-kg package P.A.N. precooked cornmeal",
|
||||
"2 Tbsp. Diamond Crystal or 1 Tbsp. plus \u00bd tsp. kosher salt",
|
||||
"3 1-lb. packages fresh or frozen, thawed banana or plantain leaves",
|
||||
"\u00bc cup extra-virgin olive oil",
|
||||
"\u00bd cup drained capers",
|
||||
"\u00bd cup pitted green olives",
|
||||
"\u00bd cup raisins"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Cook oil and achiote seeds in a small saucepan over medium-low heat until oil turns deep orange, about 10 minutes. Strain into a heatproof jar and let cool. Measure out \u00bd cup achiote oil for making filling; set remaining 1 cup oil aside for making dough."
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Bring beef, chicken, 1 Tbsp. Diamond Crystal or 1\u00be tsp. Morton kosher salt, and 12 cups water to a boil in a large pot over medium-high heat. Reduce heat to medium-low and let simmer until cooked through, about 30 minutes. Transfer beef and chicken to a cutting board and let sit until cool enough to handle. Pour 8 cups cooking liquid into a heatproof pitcher or large measuring glass; set aside. Discard any extra liquid."
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Cut beef and chicken into \u2153\" cubes; place back into pot (cooking the meat before you chop it means that you can cut the pieces finer and more evenly). Blend tomatoes, garlic, and tomato paste in a blender until smooth; scrape pur\u00e9e into pot with meat. Blend onion, red and green bell peppers, scallions, cilantro, and \u00bd cup reserved cooking liquid in blender until smooth and add to pot. Add brown sugar and \u00bd cup reserved achiote oil. Pour in remaining 7\u00bd cups reserved cooking liquid. Bring to a boil, then reduce heat to medium-low and simmer until meat is tender and liquid is slightly reduced, about 40 minutes. Drain meat in a colander, season lightly with salt, and let cool."
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Meanwhile, mix cornmeal, salt, reserved 1 cup achiote oil, and 8 cups water in a large bowl with your hands until dough is smooth, spreadable, and no large lumps remain, 5\u20137 minutes. Press a sheet of plastic wrap or parchment paper directly onto surface of dough; let rest at least 30 minutes or up to 1 hour."
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Wash and pat banana leaves dry. Carefully remove any center stems with kitchen shears, avoiding breaking through the leaf, then cut into 14x10\" rectangles. Mix oil and 1 cup water in a medium bowl (it needs to be big enough to dip your hands into). This will help to keep the dough from sticking to your hands. Working one at a time, place a banana leaf on a surface so the veins in the leaves run horizontally. Dipping your hands in oil mixture as you work, place \u00be cup dough in center of leaf and spread out with your fingers into a \u215b\"-thick rectangle, leaving a 1\" border near the vertical edges and a space on both horizontal edges. Place \u00be cup guiso into center of dough. Top with 5 capers, 2 olives, and 8 raisins."
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Take top and bottom edges of leaf and bring up toward each other so edges of dough meet and enclose filling. Pull both sides of banana leaf together snugly toward the upper edge of hallaca to seal and fold over toward you to make a tube. Fold remaining 2 side ends toward the center to make a small package."
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Place package, fold side down, on another banana leaf and wrap up again. Wrap once more in a third leaf to hold everything together, then tie closed with kitchen twine. (Make sure package is compact, the leaves are not ripped, and hallaca is not leaking.) Repeat with remaining dough, filling, and banana leaves."
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Place as many hallacas as will fit into a clean large pot, pour in water to cover, and bring to a boil. Reduce heat and simmer, turning hallacas halfway through, until plumped and firm, about 35 minutes. Repeat with remaining hallacas.\nDo ahead: Hallacas can be made 1 week ahead. Let cool, then cover and chill, or freeze up to 3 months. To reheat, cook in a pot of simmering water (make sure hallacas are submerged), partially covered, until warmed through, 10\u201315 minutes if chilled, 25\u201330 minutes if frozen."
|
||||
}
|
||||
],
|
||||
"recipeYield": "Makes about 18",
|
||||
"url": "https://www.bonappetit.com/recipe/hallacas",
|
||||
"slug": "hallacas",
|
||||
"orgURL": "https://www.bonappetit.com/recipe/hallacas",
|
||||
"categories": [],
|
||||
"tags": [],
|
||||
"dateAdded": null,
|
||||
"notes": [],
|
||||
"extras": []
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
"url": "https://www.deliaonline.com/recipes/seasons/what-should-you-be-cooking-in-november/chunky-apple-cake",
|
||||
"author": "Delia Smith",
|
||||
"image": "https://www.deliaonline.com/sites/default/files/quick_media/cakes-chunky-apple-cake.jpg",
|
||||
"name": "Chunky Apple Cake",
|
||||
"description": "Apples are superb in cakes, so in the autumn when there are lots of windfalls around, why not make a few of these and freeze them.",
|
||||
"recipeCuisine": "General",
|
||||
"recipeCategory": [
|
||||
"Apples",
|
||||
"Afternoon Tea",
|
||||
"Cake Recipes",
|
||||
"Autumn",
|
||||
"Life in the Freezer"
|
||||
],
|
||||
"keywords": "Apples, Afternoon Tea, Cake Recipes, Autumn, Life in the Freezer, Delia, Delia Smith",
|
||||
"recipeInstructions": "Begin by sifting the flour, baking powder and spices into a roomy mixing bowl, lifting the sieve quite high to give the flour a good airing as it goes down.\n\nNext chop the apples into small dice (with or without peel, just as you like). Then place them in a bowl and toss them with one tablespoon of the sieved flour mixture. Then add the eggs, butter and sugar to the rest of the flour, and using an electric hand whisk, combine them for about 1 minute until you have a smooth creamy consistency. After that fold in the grated orange zest, mixed peel and diced apple. If the mixture seems a little dry, add a tablespoon of milk. Now spoon the cake mix into the prepared tin and level it off with the back of a spoon.\n\nThen bake near the centre of the oven for about one hour or until the cake feels springy in the centre when lightly pressed with a fingertip and just shows signs of shrinking away from the edge of the tin. Cool in the tin for 10 minutes before turning out onto a wire rack. This looks nice dusted with sifted icing sugar just before serving. Store in an airtight tin.\n\nYou can watch more of Delia's cake recipes being made in our Cookery School Videos on the right.",
|
||||
"recipeIngredient": [
|
||||
"225g self-raising flour",
|
||||
"1 rounded teaspoon baking powder",
|
||||
"1 level teaspoon mixed spice",
|
||||
"\u00bd level teaspoon ground cinnamon",
|
||||
"3 Bramley apples (about 550g)",
|
||||
"2 large eggs, beaten",
|
||||
"75g spreadable butter",
|
||||
"175g light brown soft sugar",
|
||||
"grated zest of 1 large orange",
|
||||
"1 tablespoon chopped mixed peel",
|
||||
"1 tablespoon milk (if needed)",
|
||||
"little icing sugar"
|
||||
],
|
||||
"@context": "http://schema.org",
|
||||
"@type": "Recipe"
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org/",
|
||||
"@type": "Recipe",
|
||||
"name": "Dairy-Free Impossible Pumpkin Pie",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Kare for Kitchen Treaty"
|
||||
},
|
||||
"description": "This crustless pumpkin pie might just be the\u00a0easiest\u00a0you'll ever make. Simply blend the ingredients together, pour into your pie pan, and bake!",
|
||||
"datePublished": "2017-11-10T16:12:06+00:00",
|
||||
"image": [
|
||||
"https://www.kitchentreaty.com/wp-content/uploads/2017/11/dairy-free-impossible-pumpkin-pie-8.jpg"
|
||||
],
|
||||
"recipeYield": [
|
||||
"8"
|
||||
],
|
||||
"prepTime": "PT10M",
|
||||
"cookTime": "PT45M",
|
||||
"totalTime": "PT55M",
|
||||
"recipeIngredient": [
|
||||
"1 (15-ounce) can coconut milk (I recommend full-fat for a richer pie, but lite also works)",
|
||||
"1 cup pumpkin puree",
|
||||
"4 large eggs",
|
||||
"1/2 cup granulated sugar",
|
||||
"1 tablespoon pure vanilla extract",
|
||||
"1/2 cup all-purpose flour (or your favorite cup-for-cup gluten-free flour blend*)",
|
||||
"1 teaspoon baking powder",
|
||||
"1 tablespoon pumpkin pie spice",
|
||||
"1/2 teaspoon fine-grain sea salt or table salt",
|
||||
"Coconut whipped cream (for serving**)"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Preheat oven to 375 degrees Fahrenheit and position rack in the middle of the oven. Spray a 9- or 10-inch pie pan with baking spray or oil the pan with coconut oil or vegan butter.",
|
||||
"name": "Preheat oven to 375 degrees Fahrenheit and position rack in the middle of the oven. Spray a 9- or 10-inch pie pan with baking spray or oil the pan with coconut oil or vegan butter.",
|
||||
"url": "https://www.kitchentreaty.com/dairy-free-impossible-pumpkin-pie/#wprm-recipe-32856-step-0-0"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Add the coconut milk, pumpkin, eggs, sugar, and vanilla to the pitcher of a blender. Blend until combined, about 20 seconds. Add the flour, baking powder, pumpkin pie spice, and salt. Blend again until well-combined, another 20\u00a0seconds.",
|
||||
"name": "Add the coconut milk, pumpkin, eggs, sugar, and vanilla to the pitcher of a blender. Blend until combined, about 20 seconds. Add the flour, baking powder, pumpkin pie spice, and salt. Blend again until well-combined, another 20\u00a0seconds.",
|
||||
"url": "https://www.kitchentreaty.com/dairy-free-impossible-pumpkin-pie/#wprm-recipe-32856-step-0-1"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Pour filling into the pie plate. The mixture will be fairly runny. Carefully transfer to the preheated oven.",
|
||||
"name": "Pour filling into the pie plate. The mixture will be fairly runny. Carefully transfer to the preheated oven.",
|
||||
"url": "https://www.kitchentreaty.com/dairy-free-impossible-pumpkin-pie/#wprm-recipe-32856-step-0-2"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Bake\u00a0until the middle just barely jiggles, 40-50 minutes. I like to check the middle by giving the pie pan a little nudge, and if it seems like it's no longer liquid, I'll pull the pie out and insert a butter knife about halfway between the center and the edge. If the knife comes out relatively clean - no runny pie filling - it's\u00a0done!",
|
||||
"name": "Bake\u00a0until the middle just barely jiggles, 40-50 minutes. I like to check the middle by giving the pie pan a little nudge, and if it seems like it's no longer liquid, I'll pull the pie out and insert a butter knife about halfway between the center and the edge. If the knife comes out relatively clean - no runny pie filling - it's\u00a0done!",
|
||||
"url": "https://www.kitchentreaty.com/dairy-free-impossible-pumpkin-pie/#wprm-recipe-32856-step-0-3"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Place on a cooling rack and let cool, about 1 hour. Transfer to refrigerator to completely\u00a0cool, at least one more hour (or up to 3 days in advance).",
|
||||
"name": "Place on a cooling rack and let cool, about 1 hour. Transfer to refrigerator to completely\u00a0cool, at least one more hour (or up to 3 days in advance).",
|
||||
"url": "https://www.kitchentreaty.com/dairy-free-impossible-pumpkin-pie/#wprm-recipe-32856-step-0-4"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "If desired, top pie with dollops of coconut whipped cream. Or simply cut slices, transfer to a plate, and top\u00a0individual servings with the whipped cream.",
|
||||
"name": "If desired, top pie with dollops of coconut whipped cream. Or simply cut slices, transfer to a plate, and top\u00a0individual servings with the whipped cream.",
|
||||
"url": "https://www.kitchentreaty.com/dairy-free-impossible-pumpkin-pie/#wprm-recipe-32856-step-0-5"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Keeps in the refrigerator for 3-4 days. I suggest covering the completely cooled pie with plastic wrap if not serving right away.",
|
||||
"name": "Keeps in the refrigerator for 3-4 days. I suggest covering the completely cooled pie with plastic wrap if not serving right away.",
|
||||
"url": "https://www.kitchentreaty.com/dairy-free-impossible-pumpkin-pie/#wprm-recipe-32856-step-0-6"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "5",
|
||||
"ratingCount": "4"
|
||||
},
|
||||
"recipeCategory": [
|
||||
"Dessert"
|
||||
],
|
||||
"recipeCuisine": [
|
||||
"American"
|
||||
],
|
||||
"keywords": "pie",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "231 kcal",
|
||||
"sugarContent": "14 g",
|
||||
"sodiumContent": "239 mg",
|
||||
"fatContent": "14 g",
|
||||
"saturatedFatContent": "11 g",
|
||||
"carbohydrateContent": "23 g",
|
||||
"fiberContent": "1 g",
|
||||
"proteinContent": "5 g",
|
||||
"cholesterolContent": "82 mg",
|
||||
"servingSize": "1 serving"
|
||||
},
|
||||
"url": "https://www.kitchentreaty.com/dairy-free-impossible-pumpkin-pie/"
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org/",
|
||||
"@type": "Recipe",
|
||||
"name": "How to Make Instant Pot Spaghetti",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Karlynn Johnston"
|
||||
},
|
||||
"description": "This Instant Pot Spaghetti recipe is literally the best one out there and it's thanks to one ( or two!) secret ingredients!",
|
||||
"datePublished": "2020-09-15T13:00:52+00:00",
|
||||
"image": [
|
||||
"https://www.thekitchenmagpie.com/wp-content/uploads/images/2018/02/instantpotspaghetti.jpg",
|
||||
"https://www.thekitchenmagpie.com/wp-content/uploads/images/2018/02/instantpotspaghetti-500x500.jpg",
|
||||
"https://www.thekitchenmagpie.com/wp-content/uploads/images/2018/02/instantpotspaghetti-500x375.jpg",
|
||||
"https://www.thekitchenmagpie.com/wp-content/uploads/images/2018/02/instantpotspaghetti-480x270.jpg"
|
||||
],
|
||||
"recipeYield": [
|
||||
"4"
|
||||
],
|
||||
"prepTime": "PT15M",
|
||||
"cookTime": "PT7M",
|
||||
"totalTime": "PT22M",
|
||||
"recipeIngredient": [
|
||||
"1 tablespoon olive oil",
|
||||
"1 cup white onion (diced)",
|
||||
"1 tablespoon fresh minced garlic",
|
||||
"1 pound lean ground beef",
|
||||
"2 teaspoons Italian seasoning mix",
|
||||
"one 16 ounce package uncooked white flour spaghetti noodles (cooking time for al dente needs to be 9-10 minutes! )",
|
||||
"one 750 millilitre jar of 4 cheese spaghetti sauce",
|
||||
"one 15 ounce can diced tomatoes",
|
||||
"3 cups weak beef broth (divided)",
|
||||
"1/2 teaspoon salt (( to taste))",
|
||||
"1/2 teaspoon black pepper",
|
||||
"1/2 teaspoon white sugar (to cut the acidity of the tomatoes )"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Press the \"saute\" button on your Instant Pot. Add in the olive oil and heat. Once it's heated, add in the white onion. Saute until the onion is soft and translucent. Add in the garlic and fry for 2-3 minutes.",
|
||||
"name": "Press the \"saute\" button on your Instant Pot. Add in the olive oil and heat. Once it's heated, add in the white onion. Saute until the onion is soft and translucent. Add in the garlic and fry for 2-3 minutes.",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#wprm-recipe-44488-step-0-0",
|
||||
"image": "https://www.thekitchenmagpie.com/wp-content/uploads/images/2018/02/fryinggroundbeefandonionsinaninsantpot.jpg"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Add in the ground beef and fry , stirring constantly, until it's no longer pink. Press the Cancel button to turn off the Instant Pot heating element. Drain the fat (keeping some for flavour if wanted).",
|
||||
"name": "Add in the ground beef and fry , stirring constantly, until it's no longer pink. Press the Cancel button to turn off the Instant Pot heating element. Drain the fat (keeping some for flavour if wanted).",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#wprm-recipe-44488-step-0-1"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Add in 1 cup of the beef broth, mixing it in with the ground beef on the bottom.",
|
||||
"name": "Add in 1 cup of the beef broth, mixing it in with the ground beef on the bottom.",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#wprm-recipe-44488-step-0-2"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Break the spaghetti noodles in half. Place in random, different criss-cross patterns on top of the beef/ beef broth mixture. You are trying to created space between the noodles to try and prevent sticking.",
|
||||
"name": "Break the spaghetti noodles in half. Place in random, different criss-cross patterns on top of the beef/ beef broth mixture. You are trying to created space between the noodles to try and prevent sticking.",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#wprm-recipe-44488-step-0-3",
|
||||
"image": "https://www.thekitchenmagpie.com/wp-content/uploads/images/2018/02/howtobreakspaghettinoodlesfortheinstantpot.jpg"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "In a large bowl or large glass spouted measuring glass, combine the remaining beef broth, tomatoes, 4 cheese sauce, Italian seasoning, salt, pepper and dash of white sugar. ",
|
||||
"name": "In a large bowl or large glass spouted measuring glass, combine the remaining beef broth, tomatoes, 4 cheese sauce, Italian seasoning, salt, pepper and dash of white sugar. ",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#wprm-recipe-44488-step-0-4"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Pout the liquid mixture on top of the pasta, around the sides, making sure you coat everything. Take a wooden spoon and gently push down on the spaghetti noodles, making sure that they are all underneath the liquid.",
|
||||
"name": "Pout the liquid mixture on top of the pasta, around the sides, making sure you coat everything. Take a wooden spoon and gently push down on the spaghetti noodles, making sure that they are all underneath the liquid.",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#wprm-recipe-44488-step-0-5"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Press the Manual Button ( you are going to use high pressure) and set for 7 minutes. Listen to make sure that it seals.",
|
||||
"name": "Press the Manual Button ( you are going to use high pressure) and set for 7 minutes. Listen to make sure that it seals.",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#wprm-recipe-44488-step-0-6"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "When it's done, release the valve manually ( see the link in my suggestions in the post above). Stir the spaghetti, breaking up any noodles that stuck together. Let it sit for a few minutes, soaking up the extra liquid.",
|
||||
"name": "When it's done, release the valve manually ( see the link in my suggestions in the post above). Stir the spaghetti, breaking up any noodles that stuck together. Let it sit for a few minutes, soaking up the extra liquid.",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#wprm-recipe-44488-step-0-7",
|
||||
"image": "https://www.thekitchenmagpie.com/wp-content/uploads/images/2018/02/instantpotspaghetti3.jpg"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "5",
|
||||
"ratingCount": "15"
|
||||
},
|
||||
"recipeCategory": [
|
||||
"supper"
|
||||
],
|
||||
"recipeCuisine": [
|
||||
"American"
|
||||
],
|
||||
"keywords": "Instant Pot Spaghetti",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "222 kcal",
|
||||
"carbohydrateContent": "5 g",
|
||||
"proteinContent": "27 g",
|
||||
"fatContent": "9 g",
|
||||
"saturatedFatContent": "3 g",
|
||||
"cholesterolContent": "70 mg",
|
||||
"sodiumContent": "699 mg",
|
||||
"fiberContent": "1 g",
|
||||
"sugarContent": "2 g",
|
||||
"servingSize": "1 serving"
|
||||
},
|
||||
"@id": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/#webpage",
|
||||
"url": "https://www.thekitchenmagpie.com/how-to-make-instant-pot-spaghetti/"
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org/",
|
||||
"@type": "Recipe",
|
||||
"name": "Instant Pot Chicken and Potatoes",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Tiffany"
|
||||
},
|
||||
"description": "This is hands down the BEST Instant Pot Chicken and Potatoes recipe you'll ever try. Juicy ranch-seasoned chicken breast and parmesan potatoes cooked in 30 minutes in your pressure cooker - it doesn't get easier than this! ",
|
||||
"datePublished": "2018-10-26T07:00:51+00:00",
|
||||
"image": [
|
||||
"https://www.lecremedelacrumb.com/wp-content/uploads/2018/10/instant-pot-chicken-potatoes-2.jpg",
|
||||
"https://www.lecremedelacrumb.com/wp-content/uploads/2018/10/instant-pot-chicken-potatoes-2-500x500.jpg",
|
||||
"https://www.lecremedelacrumb.com/wp-content/uploads/2018/10/instant-pot-chicken-potatoes-2-500x375.jpg",
|
||||
"https://www.lecremedelacrumb.com/wp-content/uploads/2018/10/instant-pot-chicken-potatoes-2-480x270.jpg"
|
||||
],
|
||||
"recipeYield": [
|
||||
"4",
|
||||
"4 people"
|
||||
],
|
||||
"prepTime": "PT10M",
|
||||
"cookTime": "PT15M",
|
||||
"totalTime": "PT40M",
|
||||
"recipeIngredient": [
|
||||
"4 boneless skinless chicken breasts",
|
||||
"2 pounds baby red or gold potatoes",
|
||||
"3 tablespoons olive oil",
|
||||
"1 1/2 teaspoons salt (or to taste)",
|
||||
"1/2 teaspoon pepper (or to taste)",
|
||||
"1 teaspoon garlic powder",
|
||||
"1 teaspoon dried thyme",
|
||||
"1/2 teaspoon dried basil",
|
||||
"1/2 teaspoon dried oregano",
|
||||
"2 tablespoons + 2 teaspoons dry Ranch seasoning (divided)",
|
||||
"1 cup chicken broth",
|
||||
"3 tablespoons grated parmesan cheese"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "In a large bowl toss chicken and potatoes in the olive oil, then season with salt and pepper. Stir together garlic powder, thyme, basil, oregano, and 2 tablespoons of the Ranch seasoning. Sprinkle over the chicken and potatoes, tossing to distribute the ingredients as evenly as possible. ",
|
||||
"name": "In a large bowl toss chicken and potatoes in the olive oil, then season with salt and pepper. Stir together garlic powder, thyme, basil, oregano, and 2 tablespoons of the Ranch seasoning. Sprinkle over the chicken and potatoes, tossing to distribute the ingredients as evenly as possible. ",
|
||||
"url": "https://www.lecremedelacrumb.com/instant-pot-chicken-and-potatoes/#wprm-recipe-22284-step-0-0"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Add chicken broth to the instant pot/pressure cooker, then place chicken in the broth, and top with the potatoes. Place the lid on in the locked position and turn the vent to the sealed position. Set pressure cooker to \"pressure cook\" for 15 minutes.",
|
||||
"name": "Add chicken broth to the instant pot/pressure cooker, then place chicken in the broth, and top with the potatoes. Place the lid on in the locked position and turn the vent to the sealed position. Set pressure cooker to \"pressure cook\" for 15 minutes.",
|
||||
"url": "https://www.lecremedelacrumb.com/instant-pot-chicken-and-potatoes/#wprm-recipe-22284-step-0-1"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Once the cook time is finished, do a \"quick release\" by turning the vent to the venting position. Once float valve has dropped, remove the lid. Drain the pressure cooker or use a slotted spoon to transfer chicken and potatoes to a large platter. ",
|
||||
"name": "Once the cook time is finished, do a \"quick release\" by turning the vent to the venting position. Once float valve has dropped, remove the lid. Drain the pressure cooker or use a slotted spoon to transfer chicken and potatoes to a large platter. ",
|
||||
"url": "https://www.lecremedelacrumb.com/instant-pot-chicken-and-potatoes/#wprm-recipe-22284-step-0-2"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Sprinkle with Ranch seasoning and parmesan cheese and garnish with chopped thyme or parsley if desired before serving. ",
|
||||
"name": "Sprinkle with Ranch seasoning and parmesan cheese and garnish with chopped thyme or parsley if desired before serving. ",
|
||||
"url": "https://www.lecremedelacrumb.com/instant-pot-chicken-and-potatoes/#wprm-recipe-22284-step-0-3"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "4.76",
|
||||
"ratingCount": "225"
|
||||
},
|
||||
"recipeCategory": [
|
||||
"Main Course"
|
||||
],
|
||||
"recipeCuisine": [
|
||||
"American"
|
||||
],
|
||||
"keywords": "Chicken, healthy, instant pot, mashed potatoes, pressure cooker, ranch",
|
||||
"@id": "https://www.lecremedelacrumb.com/instant-pot-chicken-and-potatoes/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https://www.lecremedelacrumb.com/instant-pot-chicken-and-potatoes/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https://www.lecremedelacrumb.com/instant-pot-chicken-and-potatoes/#webpage",
|
||||
"url": "https://www.lecremedelacrumb.com/instant-pot-chicken-and-potatoes/"
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org/",
|
||||
"@type": "Recipe",
|
||||
"name": "How to make Instant Pot Kerala Vegetable Stew",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Dhwani"
|
||||
},
|
||||
"description": "Instant Pot Kerala Vegetable Stew - A complete Comfort and Satisfying food that can be made in a fraction of the time. Veg Stew is Vegetarian / Vegan Instant Pot Recipe with lots of vegetables in coconut milk based hearty sauce that will change your life.",
|
||||
"datePublished": "2019-01-16T19:25:09+00:00",
|
||||
"image": [
|
||||
"https://cdn.cookingcarnival.com/wp-content/uploads/2019/01/Instant-Pot-Kerala-Vegetable-Stew-2.jpg",
|
||||
"https://cdn.cookingcarnival.com/wp-content/uploads/2019/01/Instant-Pot-Kerala-Vegetable-Stew-2-500x500.jpg",
|
||||
"https://cdn.cookingcarnival.com/wp-content/uploads/2019/01/Instant-Pot-Kerala-Vegetable-Stew-2-500x375.jpg",
|
||||
"https://cdn.cookingcarnival.com/wp-content/uploads/2019/01/Instant-Pot-Kerala-Vegetable-Stew-2-480x270.jpg"
|
||||
],
|
||||
"video": {
|
||||
"name": "Instant Pot Kerala Vegetable Stew | Vegan stew recipe | vegetable Stew recipe in instant Pot",
|
||||
"description": "Instant Pot Kerala Vegetable Stew - A complete Comfort and Satisfying food that can be made in a fraction of the time. Veg Stew is Vegetarian / Vegan Instant Pot Recipe with lots of vegetables in coconut milk based hearty sauce that will change your life.\n\nDetailed Recipe of Instant pot Kerela vegetable stew https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/\nOfficial Facebook Page: https://www.facebook.com/cookingcarnival\n\nPinterest: https://www.pinterest.com/cookingcarnival/\n\nTwitter: https://twitter.com/carnivalcooking\n\nGoogle Plus: https://plus.google.com/+Cookingcarnival\n\nInstagram: https://www.instagram.com/cookingcarnival",
|
||||
"uploadDate": "2019-01-17T19:46:14+00:00",
|
||||
"duration": "PT2M17S",
|
||||
"thumbnailUrl": "https://i.ytimg.com/vi/pej98AtiBWE/hqdefault.jpg",
|
||||
"contentUrl": "https://youtu.be/pej98AtiBWE",
|
||||
"embedUrl": "https://www.youtube.com/embed/pej98AtiBWE?feature=oembed",
|
||||
"@type": "VideoObject"
|
||||
},
|
||||
"recipeYield": [
|
||||
"4",
|
||||
"4 people"
|
||||
],
|
||||
"prepTime": "PT10M",
|
||||
"cookTime": "PT10M",
|
||||
"totalTime": "PT20M",
|
||||
"recipeIngredient": [
|
||||
"2 cups - Cauliflower florets",
|
||||
"1 cup - Chopped carrots",
|
||||
"1 1/2 cup - Bell Peppers (chopped)",
|
||||
"2 cups - Potatoes (Chopped)",
|
||||
"3/4 cup - Chopped Onions",
|
||||
"1 cup - Green beans (Chopped)",
|
||||
"1 tsp - Ginger paste",
|
||||
"1/2 tsp - Chili ((adust according to your liking) )",
|
||||
"1 tsp - Garlic paste",
|
||||
"2 - Cardamom Pods (See Notes)",
|
||||
"1 inch - Cinnamon stick",
|
||||
"3 - Cloves",
|
||||
"20 Pieces - Whole Cashew Nuts",
|
||||
"1 cup - Coconut milk (See Notes)",
|
||||
"Salt to taste",
|
||||
"1/2 tsp - White Pepper Powder (see notes)",
|
||||
"2 tbsp - Oil (See Notes)",
|
||||
"2 cups - Water"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Turn on saute button of your IP.",
|
||||
"name": "Turn on saute button of your IP.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-0"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Heat oil in a pot, add cardamom pods, cinnamon stick, and cloves.",
|
||||
"name": "Heat oil in a pot, add cardamom pods, cinnamon stick, and cloves.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-1"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Now add ginger, garlic, chili and onions. Saute for few seconds.",
|
||||
"name": "Now add ginger, garlic, chili and onions. Saute for few seconds.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-2"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Add all the vegetables, salt, white pepper powder and water. Mix well.",
|
||||
"name": "Add all the vegetables, salt, white pepper powder and water. Mix well.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-3"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Cover your Instant pot with locking lid.",
|
||||
"name": "Cover your Instant pot with locking lid.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-4"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Turn off IP.",
|
||||
"name": "Turn off IP.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-5"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Press the manual or pressure cook button. Cook on high pressure for 3 minutes with pressure valve in the sealing position.",
|
||||
"name": "Press the manual or pressure cook button. Cook on high pressure for 3 minutes with pressure valve in the sealing position.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-6"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Meanwhile, take whole cashew and coconut milk in a blender jar and blend them well in to a smooth paste. Keep it aside.",
|
||||
"name": "Meanwhile, take whole cashew and coconut milk in a blender jar and blend them well in to a smooth paste. Keep it aside.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-7"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Once IP beeps and when you see LO:00, turn off your IP and quick release the pressure.",
|
||||
"name": "Once IP beeps and when you see LO:00, turn off your IP and quick release the pressure.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-8"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "10. Open the Instant Pot, add prepared cashew-coconut paste. Stir well.",
|
||||
"name": "10. Open the Instant Pot, add prepared cashew-coconut paste. Stir well.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-9"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "11. Turn on saute button and cook it for 1 to 2 more minutes, until everything well combined.",
|
||||
"name": "11. Turn on saute button and cook it for 1 to 2 more minutes, until everything well combined.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-10"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "12. Switch off the IP.",
|
||||
"name": "12. Switch off the IP.",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-11"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "13. Instant Pot Kerala Vegetable Stew is ready. Enjoy!!",
|
||||
"name": "13. Instant Pot Kerala Vegetable Stew is ready. Enjoy!!",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#wprm-recipe-8126-step-0-12"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "4.88",
|
||||
"ratingCount": "8"
|
||||
},
|
||||
"recipeCategory": [
|
||||
"Main Course",
|
||||
"Soups and Stew"
|
||||
],
|
||||
"recipeCuisine": [
|
||||
"American",
|
||||
"Indian"
|
||||
],
|
||||
"keywords": "Easy vegan instant pot recipe, Instant pot, Vegetable Stew",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"servingSize": "1 person",
|
||||
"calories": "201 kcal",
|
||||
"carbohydrateContent": "24 g",
|
||||
"proteinContent": "4 g",
|
||||
"fatContent": "10 g",
|
||||
"saturatedFatContent": "1 g",
|
||||
"sodiumContent": "56 mg",
|
||||
"fiberContent": "5 g",
|
||||
"sugarContent": "9 g"
|
||||
},
|
||||
"@id": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/#webpage",
|
||||
"url": "https://www.cookingcarnival.com/instant-pot-kerala-vegetable-stew/"
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org/",
|
||||
"@type": "Recipe",
|
||||
"name": "Jalape\u00f1o Popper Dip",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Michelle"
|
||||
},
|
||||
"description": "Jalapeno Popper Dip is creamy, cheesy and has just the perfect amount of kick. Great appetizer for your next party or watching the big game!",
|
||||
"datePublished": "2016-02-22T00:01:37+00:00",
|
||||
"image": [
|
||||
"https://www.browneyedbaker.com/wp-content/uploads/2011/08/jalapeno-popper-dip-6-600.jpg"
|
||||
],
|
||||
"recipeYield": [
|
||||
"10",
|
||||
"10 to 12 servings"
|
||||
],
|
||||
"prepTime": "PT15M",
|
||||
"cookTime": "PT30M",
|
||||
"totalTime": "PT45M",
|
||||
"recipeIngredient": [
|
||||
"16 ounces cream cheese (at room temperature)",
|
||||
"1 cup mayonnaise",
|
||||
"8 pieces of bacon (cooked and chopped)",
|
||||
"6 jalape\u00f1os (seeded and minced (if you can't get fresh, substitute a 4-ounce can diced jalape\u00f1o peppers, drained))",
|
||||
"2 cloves garlic (minced)",
|
||||
"\u00bd teaspoon cumin",
|
||||
"6 ounces cheddar cheese (shredded (about 1\u00bd cups))",
|
||||
"1 cup panko breadcrumbs",
|
||||
"1 cup grated Parmesan cheese",
|
||||
"4 tablespoons unsalted butter, melted"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Preheat oven to 375 degrees F.",
|
||||
"name": "Preheat oven to 375 degrees F.",
|
||||
"url": "https://www.browneyedbaker.com/jalapeno-popper-dip/#wprm-recipe-44993-step-0-0"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Combine the cream cheese, mayonnaise, bacon, jalapenos, garlic, cumin and cheddar cheese in a mixing bowl. Transfer the mixture into 2-quart baking dish.",
|
||||
"name": "Combine the cream cheese, mayonnaise, bacon, jalapenos, garlic, cumin and cheddar cheese in a mixing bowl. Transfer the mixture into 2-quart baking dish.",
|
||||
"url": "https://www.browneyedbaker.com/jalapeno-popper-dip/#wprm-recipe-44993-step-0-1"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Combine the panko breadcrumbs, Parmesan cheese and melted butter in a small bowl, tossing with a fork until the mixture is evenly moistened. Sprinkle evenly over the cream cheese mixture.",
|
||||
"name": "Combine the panko breadcrumbs, Parmesan cheese and melted butter in a small bowl, tossing with a fork until the mixture is evenly moistened. Sprinkle evenly over the cream cheese mixture.",
|
||||
"url": "https://www.browneyedbaker.com/jalapeno-popper-dip/#wprm-recipe-44993-step-0-2"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Bake in the preheated oven for 25 to 30 minutes, until the top is golden brown and the dip is bubbling. Let rest for 5 minutes before serving. Serve with your favorite tortilla chips, crackers, vegetables, etc.",
|
||||
"name": "Bake in the preheated oven for 25 to 30 minutes, until the top is golden brown and the dip is bubbling. Let rest for 5 minutes before serving. Serve with your favorite tortilla chips, crackers, vegetables, etc.",
|
||||
"url": "https://www.browneyedbaker.com/jalapeno-popper-dip/#wprm-recipe-44993-step-0-3"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": "4.34",
|
||||
"ratingCount": "15"
|
||||
},
|
||||
"recipeCategory": [
|
||||
"Appetizer"
|
||||
],
|
||||
"recipeCuisine": [
|
||||
"American"
|
||||
],
|
||||
"keywords": "cheese dip, game day food, party food",
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "560 kcal",
|
||||
"carbohydrateContent": "7 g",
|
||||
"proteinContent": "14 g",
|
||||
"fatContent": "52 g",
|
||||
"saturatedFatContent": "21 g",
|
||||
"cholesterolContent": "109 mg",
|
||||
"sodiumContent": "707 mg",
|
||||
"sugarContent": "2 g",
|
||||
"servingSize": "1 serving"
|
||||
},
|
||||
"@id": "https://www.browneyedbaker.com/jalapeno-popper-dip/#recipe",
|
||||
"isPartOf": {
|
||||
"@id": "https://www.browneyedbaker.com/jalapeno-popper-dip/#article"
|
||||
},
|
||||
"mainEntityOfPage": "https://www.browneyedbaker.com/jalapeno-popper-dip/#webpage",
|
||||
"url": "https://www.browneyedbaker.com/jalapeno-popper-dip/"
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Recipe",
|
||||
"aggregateRating": {
|
||||
"ratingCount": 3,
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Justine Pattison"
|
||||
},
|
||||
"cookTime": "PT10M",
|
||||
"description": "Microwave jacket sweet potatoes make a wonderfully quick and easy meal. Take your pick of these three delicious fillings, or make all of them! The veggie chilli makes enough for four portions, great for lunch tomorrow. The smoked mackerel and pea fillings each make enough for two portions. \r\n\r\nThis recipe was tested using a 900W microwave oven. If your oven has more or fewer watts, you will need to adjust the cooking time.\r\n",
|
||||
"image": [
|
||||
"https://food-images.files.bbci.co.uk/food/recipes/microwave_sweet_potatoes_04783_16x9.jpg"
|
||||
],
|
||||
"keywords": "quick, jacket potato dinners, microwave recipes , quick and cheap dinners, quick delicious lunches, easy family dinners, lunch, student food, Jacket potato, sweet potato, peas, egg free, gluten free, nut free, pregnancy friendly",
|
||||
"name": "Microwave jacket sweet potato ",
|
||||
"prepTime": "PT30M",
|
||||
"recipeCategory": "Main course",
|
||||
"recipeIngredient": [
|
||||
"2 sweet potatoes, washed and dried",
|
||||
"75g/2\u00bdoz smoked mackerel, skinned and roughly mashed with a fork",
|
||||
"3 tbsp half-fat cr\u00e8me fra\u00eeche or soured cream",
|
||||
"2 spring onions, trimmed and thinly sliced",
|
||||
"\u00bd unwaxed lemon, finely grated zest only",
|
||||
"freshly ground black pepper ",
|
||||
"100g/3\u00bdoz frozen peas",
|
||||
"100g/3\u00bdoz feta ",
|
||||
"2 tbsp plain yoghurt",
|
||||
"1 tbsp finely chopped fresh mint",
|
||||
"freshly ground black pepper ",
|
||||
"\u00bd red pepper, deseeded and diced",
|
||||
"400g tin kidney beans in chilli sauce",
|
||||
"198g tin sweetcorn in water",
|
||||
"1 tbsp fresh lime juice",
|
||||
"50g/1\u00beoz mature Cheddar, coarsely grated",
|
||||
"4 tbsp soured cream",
|
||||
"fresh coriander, to garnish",
|
||||
"1 lime, cut into wedges, to serve"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
"Prick the sweet potatoes two or three times with a fork and put on a microwaveable plate. Microwave on high for 5\u20136 minutes for one potato or 7\u20138 minutes for two. Test the potatoes are soft by inserting a skewer through the middle, it should slide in easily. If the potatoes remain a little hard, cook for longer, testing again every 30 seconds. Divide the potatoes between plates, make a cross in the centre and open to fill.",
|
||||
"To make the smoked mackerel filling, mix all the ingredients together and season with lots of black pepper.",
|
||||
"To make the pea and feta filling, microwave the peas on high for 2\u20133 minutes, until thawed and just warm. Mash them with a fork, until well broken up, then mix in the feta, yoghurt and mint. Season with lots of black pepper.",
|
||||
"To make the veggie chilli filling, put the red pepper in a large microwavable bowl and cook on high for 1\u00bd\u20132 minutes, until soft. Add the beans and sweetcorn in its water, stir well and microwave on high for 4\u20135 minutes, until hot. Stir in the lime juice and mix well. Spoon into the cooked sweet potatoes and top with the cheese. Microwave for 1\u20132 minutes, until the cheese melts. Top with the soured cream, coriander and lime wedges. "
|
||||
],
|
||||
"recipeYield": "Serves 2",
|
||||
"suitableForDiet": [
|
||||
"http://schema.org/GlutenFreeDiet"
|
||||
],
|
||||
"url": "https://www.bbc.co.uk/food/recipes/microwave_sweet_potatoes_04783"
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
{
|
||||
"@context": "http://schema.org",
|
||||
"@type": "Recipe",
|
||||
"mainEntityOfPage": "http://www.eatingwell.com/recipe/249961/moroccan-skirt-steak-with-roasted-pepper-couscous/",
|
||||
"name": "Moroccan Skirt Steak with Roasted Pepper Couscous",
|
||||
"image": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://imagesvc.meredithcorp.io/v3/mm/image?url=https%3A%2F%2Fstatic.onecms.io%2Fwp-content%2Fuploads%2Fsites%2F44%2F2019%2F08%2F26231251%2F3757257.jpg",
|
||||
"width": 960,
|
||||
"height": 960
|
||||
},
|
||||
"datePublished": "2016-06-03T04:27:31.000Z",
|
||||
"description": "Thin cuts of beef, such as skirt steak or sirloin steak, cook very quickly when seared in a hot skillet--just right for a busy weeknight. We love how the spicy Moroccan flavors on the steak complement the sweet, roasted pepper-studded couscous. Serve with: Arugula salad and a glass of Pinot Noir.",
|
||||
"prepTime": null,
|
||||
"cookTime": null,
|
||||
"totalTime": "P0DT0H35M",
|
||||
"recipeIngredient": [
|
||||
"2 medium bell peppers",
|
||||
"1 teaspoon ground cumin",
|
||||
"1 teaspoon ground coriander",
|
||||
"\u00be teaspoon salt",
|
||||
"\u00bd teaspoon ground turmeric",
|
||||
"\u00bd teaspoon ground cinnamon",
|
||||
"\u00bd teaspoon freshly ground pepper",
|
||||
"1 whole lemon, plus more lemon wedges for garnish",
|
||||
"1 tablespoon 1 teaspoon plus 1 tablespoon extra-virgin olive oil, divided",
|
||||
"\u2154 cup whole-wheat couscous",
|
||||
"1 pound 1 pound skirt steak (see Note) or sirloin steak, 3/4 to 1 inch thick, trimmed",
|
||||
"2 tablespoons chopped green olives"
|
||||
],
|
||||
"recipeInstructions": [
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Position rack in upper third of oven; preheat broiler.\n"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Place bell peppers on a baking sheet and roast under the broiler, turning every 5 minutes, until charred and softened, 10 to 15 minutes. Transfer to a clean cutting board; when cool enough to handle, chop the peppers into bite-size pieces.\n"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Meanwhile, combine cumin, coriander, salt, turmeric, cinnamon and pepper in a small bowl. Grate 1/2 teaspoon zest from the lemon. Juice the lemon into a 1-cup measure and add enough water to make 1 cup. Pour into a small saucepan and add the lemon zest, 1 teaspoon of the spice mixture and 1 teaspoon olive oil. Bring to a boil. Stir in couscous, cover, remove from heat and let stand.\n"
|
||||
},
|
||||
{
|
||||
"@type": "HowToStep",
|
||||
"text": "Heat the remaining 1 tablespoon oil in a large skillet (preferably cast-iron) over medium heat until shimmering (but not smoking). Rub the remaining spice mixture on both sides of steak. Cook the steak 2 to 3 minutes per side for medium-rare. Let rest on the cutting board for 5 minutes. Stir olives and the peppers into the couscous. Thinly slice the steak and serve with the couscous and lemon wedges, if desired.\n"
|
||||
}
|
||||
],
|
||||
"recipeCategory": [
|
||||
"Healthy Recipes",
|
||||
"Healthy Ingredient Recipes",
|
||||
"Healthy Meat & Poultry Recipes",
|
||||
"Healthy Beef Recipes",
|
||||
"Healthy Steak Recipes",
|
||||
"Healthy New York Strip Steak Recipes"
|
||||
],
|
||||
"recipeCuisine": [],
|
||||
"author": [
|
||||
{
|
||||
"@type": "Person",
|
||||
"name": "EatingWell Test Kitchen"
|
||||
}
|
||||
],
|
||||
"aggregateRating": {
|
||||
"@type": "AggregateRating",
|
||||
"ratingValue": 4.538461538461538,
|
||||
"ratingCount": 13,
|
||||
"itemReviewed": "Moroccan Skirt Steak with Roasted Pepper Couscous",
|
||||
"bestRating": "5",
|
||||
"worstRating": "1"
|
||||
},
|
||||
"nutrition": {
|
||||
"@type": "NutritionInformation",
|
||||
"calories": "453.7 calories",
|
||||
"carbohydrateContent": "36 g",
|
||||
"cholesterolContent": "96.4 mg",
|
||||
"fatContent": "18.4 g",
|
||||
"fiberContent": "6.5 g",
|
||||
"proteinContent": "36.4 g",
|
||||
"saturatedFatContent": "5.1 g",
|
||||
"servingSize": null,
|
||||
"sodiumContent": "663.3 mg",
|
||||
"sugarContent": null,
|
||||
"transFatContent": null,
|
||||
"unsaturatedFatContent": null
|
||||
},
|
||||
"review": [
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2011-10-30T21:53:57Z",
|
||||
"reviewBody": "Wow! This steak was fabulous. Full of flavor even my kids liked it. The spices for the steak rub get added to the cous cous. Along with the sweet roasted peppers it was so delicious.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "shari_martinez@sbcglobal.net",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/18308949/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2011-10-30T02:40:11Z",
|
||||
"reviewBody": "Not as well received as I had hoped The leftovers were good as a steak salad with honey-mustard seasoning although Kaja did not like the seasoned meat that way. I ate some couscous on my salad too. Leftover steak is unheard of at our house yet there it was. Offerred the kids a choice of unspiced steak (three takers) and Rice-a-Roni (four takers) Austin & I liked the steak Pros: Easy I liked it Cons: Nobody liked the couscous except me",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 3
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Ellen",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/19797391/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2011-10-30T03:02:54Z",
|
||||
"reviewBody": "tasty and easy weeknight meal Initially I was a little leery of using cinnamon to season the meat but it actually turned out very good. The seasoning had a tasty and light flavor. I used sirloin because the skirt steak at the store looked very fatty. The couscous (although I didn't add the olives because I'm not a huge fan) was also very good and I enjoyed the sweetness of the bell pepper. I used the lemon garnish to squeeze over the couscous and meat and think it made it. I would definitely make this again! Pros: Tasty and easy weeknight meal",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 4
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Kat Y",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/2343563/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2011-10-30T17:25:23Z",
|
||||
"reviewBody": "This was really good. It was definitely a change from what we're used to but in a good way. I had to use skillet steak because I couldn't find any skirt steak but it worked just fine. I also used the grill for the peppers and steak because my broiler is a bit questionable. Other than that I made it as stated and my husband and I really enjoyed it. A great out of the ordinary quick meal.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "EatingWell User",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/eatingwelluser/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2011-10-30T03:41:53Z",
|
||||
"reviewBody": "I love this recipe so much that I schedule it my meal planning as often as possible. The flavors with this cut of meat are just wonderful. I can't eat grains so I pair it with fennel. Perfect!",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "EatingWell User",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/eatingwelluser/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2013-02-20T17:33:48Z",
|
||||
"reviewBody": "Great starting point! I like this one a lot but I would recommend the version of it on funnytummycafe.com. I've not been really adventurous with new flavors but this I will repeat! Pros: Wonderful flavors in the rub Cons: The couscous was TOO lemony",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 3
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "EatingWell User",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/eatingwelluser/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2011-10-30T15:06:11Z",
|
||||
"reviewBody": "I made this with chicken instead of steak and it was great! My husband has not liked couscous in the past but he really liked this version. Will definitely make again!",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "EatingWell User",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/eatingwelluser/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2011-10-30T12:15:53Z",
|
||||
"reviewBody": "WOW! Blew me away this was a great meal! Tons of flavor really quick and very filling! I served brown rice instead of couscous because that's what I had on hand. The husband never knew the difference! I can always tell when something is a real winner with him because he goes back for seconds (we're both on diets). I used one red and one green bell pepper and served a spring mix salad with tomato and feta on the side. Big bravo to the EatingWell kitchen! This will definitely be made again in my house!",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "EatingWell User",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/eatingwelluser/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Review",
|
||||
"datePublished": "2011-10-30T15:12:50Z",
|
||||
"reviewBody": "Quick & easy to prepare with mild spiced flavor. The rub produces a great crust on the steak. I felt the lemon flavor dominated the cous cous though to be fair I did seem to have a particularly juicy lemon so that may be why. My husband and I both thought that the leftover steak would be superb sliced thinly in a sandwich with a mint/yogurt dressing.",
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"worstRating": "1",
|
||||
"bestRating": "5",
|
||||
"ratingValue": 5
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "EatingWell User",
|
||||
"image": null,
|
||||
"sameAs": "https://www.allrecipes.com/cook/eatingwelluser/"
|
||||
}
|
||||
}
|
||||
],
|
||||
"url": "http://www.eatingwell.com/recipe/249961/moroccan-skirt-steak-with-roasted-pepper-couscous/"
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from mealie.schema.group.group_migration import SupportedMigrations
|
||||
from tests import data as test_data
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
class Routes:
|
||||
base = "/api/groups/migrations"
|
||||
|
||||
def report(item_id: str) -> str:
|
||||
return f"/api/groups/reports/{item_id}"
|
||||
|
||||
|
||||
@dataclass
|
||||
class MigrationTestData:
|
||||
typ: SupportedMigrations
|
||||
archive: Path
|
||||
|
||||
|
||||
test_cases = [
|
||||
MigrationTestData(typ=SupportedMigrations.nextcloud, archive=test_data.migrations_nextcloud),
|
||||
MigrationTestData(typ=SupportedMigrations.paprika, archive=test_data.migrations_paprika),
|
||||
MigrationTestData(typ=SupportedMigrations.chowdown, archive=test_data.migrations_chowdown),
|
||||
MigrationTestData(typ=SupportedMigrations.mealie_alpha, archive=test_data.migrations_mealie),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mig", test_cases)
|
||||
def test_recipe_migration(api_client: TestClient, unique_user: TestUser, mig: MigrationTestData) -> None:
|
||||
payload = {
|
||||
"migration_type": mig.typ.value,
|
||||
}
|
||||
|
||||
file_payload = {
|
||||
"archive": mig.archive.read_bytes(),
|
||||
}
|
||||
|
||||
response = api_client.post(Routes.base, data=payload, files=file_payload, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
report_id = response.json()["id"]
|
||||
|
||||
# Validate Results
|
||||
response = api_client.get(Routes.report(report_id), headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
for item in response.json()["entries"]:
|
||||
assert item["success"]
|
|
@ -1,49 +0,0 @@
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from tests.test_config import TEST_CHOWDOWN_DIR, TEST_NEXTCLOUD_DIR
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
class Routes:
|
||||
base = "/api/groups/migrations"
|
||||
|
||||
@staticmethod
|
||||
def report(item_id: str) -> str:
|
||||
return f"/api/groups/reports/{item_id}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"m_type, zip_path",
|
||||
[
|
||||
("nextcloud", TEST_NEXTCLOUD_DIR.joinpath("nextcloud.zip")),
|
||||
("chowdown", TEST_CHOWDOWN_DIR.joinpath("test_chowdown-gh-pages.zip")),
|
||||
],
|
||||
)
|
||||
def test_migration_nextcloud(api_client: TestClient, zip_path: Path, m_type: str, unique_user: TestUser):
|
||||
payload = {
|
||||
"archive": zip_path.read_bytes(),
|
||||
}
|
||||
|
||||
data = {
|
||||
"migration_type": m_type,
|
||||
}
|
||||
|
||||
response = api_client.post(Routes.base, data=data, files=payload, headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
id = response.json()["id"]
|
||||
|
||||
response = api_client.get(Routes.report(id), headers=unique_user.token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
report = response.json()
|
||||
|
||||
assert report.get("status") == "success"
|
||||
|
||||
for entry in report.get("entries"):
|
||||
assert entry.get("success") is True
|
|
@ -1,17 +0,0 @@
|
|||
from pathlib import Path
|
||||
|
||||
CWD = Path(__file__).parent
|
||||
|
||||
|
||||
TEST_DIR = CWD
|
||||
TEST_DATA = CWD.joinpath("data")
|
||||
|
||||
# Scraper
|
||||
TEST_RAW_HTML = TEST_DATA.joinpath("scraper", "html-raw")
|
||||
TEST_RAW_RECIPES = TEST_DATA.joinpath("scraper", "recipes-raw")
|
||||
|
||||
# Migrations
|
||||
TEST_CHOWDOWN_DIR = TEST_DATA.joinpath("migrations", "chowdown")
|
||||
TEST_NEXTCLOUD_DIR = TEST_DATA.joinpath("migrations", "nextcloud")
|
||||
|
||||
TEST_HTML_DIR = TEST_DATA.joinpath("html")
|
|
@ -1,12 +1,13 @@
|
|||
import json
|
||||
import re
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from mealie.services.scraper import cleaner
|
||||
from mealie.services.scraper.scraper_strategies import RecipeScraperOpenGraph
|
||||
from tests.test_config import TEST_RAW_HTML, TEST_RAW_RECIPES
|
||||
from tests import data as test_data
|
||||
|
||||
# https://github.com/django/django/blob/stable/1.3.x/django/core/validators.py#L45
|
||||
url_validation_regex = re.compile(
|
||||
|
@ -19,29 +20,28 @@ url_validation_regex = re.compile(
|
|||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
test_cleaner_data = [
|
||||
(test_data.json_best_homemade_salsa_recipe, 2),
|
||||
(test_data.json_blue_cheese_stuffed_turkey_meatballs_with_raspberry_balsamic_glaze_2, 3),
|
||||
(test_data.json_bon_appetit, 8),
|
||||
(test_data.json_chunky_apple_cake, 4),
|
||||
(test_data.json_dairy_free_impossible_pumpkin_pie, 7),
|
||||
(test_data.json_how_to_make_instant_pot_spaghetti, 8),
|
||||
(test_data.json_instant_pot_chicken_and_potatoes, 4),
|
||||
(test_data.json_instant_pot_kerala_vegetable_stew, 13),
|
||||
(test_data.json_jalapeno_popper_dip, 4),
|
||||
(test_data.json_microwave_sweet_potatoes_04783, 4),
|
||||
(test_data.json_moroccan_skirt_steak_with_roasted_pepper_couscous, 4),
|
||||
(test_data.json_pizza_knoblauch_champignon_paprika_vegan_html, 3),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"json_file,num_steps",
|
||||
[
|
||||
("best-homemade-salsa-recipe.json", 2),
|
||||
(
|
||||
"blue-cheese-stuffed-turkey-meatballs-with-raspberry-balsamic-glaze-2.json",
|
||||
3,
|
||||
),
|
||||
("bon_appetit.json", 8),
|
||||
("chunky-apple-cake.json", 4),
|
||||
("dairy-free-impossible-pumpkin-pie.json", 7),
|
||||
("how-to-make-instant-pot-spaghetti.json", 8),
|
||||
("instant-pot-chicken-and-potatoes.json", 4),
|
||||
("instant-pot-kerala-vegetable-stew.json", 13),
|
||||
("jalapeno-popper-dip.json", 4),
|
||||
("microwave_sweet_potatoes_04783.json", 4),
|
||||
("moroccan-skirt-steak-with-roasted-pepper-couscous.json", 4),
|
||||
("Pizza-Knoblauch-Champignon-Paprika-vegan.html.json", 3),
|
||||
],
|
||||
test_cleaner_data,
|
||||
)
|
||||
def test_cleaner_clean(json_file, num_steps):
|
||||
recipe_data = cleaner.clean(json.load(open(TEST_RAW_RECIPES.joinpath(json_file))))
|
||||
def test_cleaner_clean(json_file: Path, num_steps):
|
||||
recipe_data = cleaner.clean(json.loads(json_file.read_text()))
|
||||
assert len(recipe_data["recipeInstructions"]) == num_steps
|
||||
|
||||
|
||||
|
@ -98,7 +98,7 @@ def test_cleaner_instructions(instructions):
|
|||
|
||||
|
||||
def test_html_with_recipe_data():
|
||||
path = TEST_RAW_HTML.joinpath("healthy_pasta_bake_60759.html")
|
||||
path = test_data.html_healthy_pasta_bake_60759
|
||||
url = "https://www.bbc.co.uk/food/recipes/healthy_pasta_bake_60759"
|
||||
|
||||
open_graph_strategy = RecipeScraperOpenGraph(url)
|
||||
|
@ -120,7 +120,7 @@ def test_html_with_recipe_data():
|
|||
("PT3H", "3 Hours"),
|
||||
("P1DT1H1M1S", "1 day 1 Hour 1 Minute 1 Second"),
|
||||
("P1DT1H1M1.53S", "1 day 1 Hour 1 Minute 1 Second"),
|
||||
("PT-3H", None),
|
||||
("PT-3H", "PT-3H"),
|
||||
("PT", "none"),
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
# import shutil
|
||||
# from pathlib import Path
|
||||
|
||||
# import pytest
|
||||
# from mealie.core.config import app_dirs
|
||||
# from mealie.schema.recipe import Recipe
|
||||
# from tests.test_config import TEST_NEXTCLOUD_DIR
|
||||
|
||||
# CWD = Path(__file__).parent
|
||||
# TEST_NEXTCLOUD_DIR
|
||||
# TEMP_NEXTCLOUD = app_dirs.TEMP_DIR.joinpath("nextcloud")
|
||||
|
||||
|
||||
# @pytest.mark.parametrize(
|
||||
# "file_name,final_path",
|
||||
# [("nextcloud.zip", TEMP_NEXTCLOUD)],
|
||||
# )
|
||||
# def test_zip_extraction(file_name: str, final_path: Path):
|
||||
# prep()
|
||||
# zip = TEST_NEXTCLOUD_DIR.joinpath(file_name)
|
||||
# dir = process_selection(zip)
|
||||
|
||||
# assert dir == final_path
|
||||
# cleanup()
|
||||
# assert dir.exists() is False
|
||||
|
||||
|
||||
# @pytest.mark.parametrize(
|
||||
# "recipe_dir",
|
||||
# [
|
||||
# TEST_NEXTCLOUD_DIR.joinpath("Air Fryer Shrimp"),
|
||||
# TEST_NEXTCLOUD_DIR.joinpath("Chicken Parmigiana"),
|
||||
# TEST_NEXTCLOUD_DIR.joinpath("Skillet Shepherd's Pie"),
|
||||
# ],
|
||||
# )
|
||||
# def test_nextcloud_migration(recipe_dir: Path):
|
||||
# recipe = import_recipes(recipe_dir)
|
||||
# assert isinstance(recipe, Recipe)
|
||||
# shutil.rmtree(app_dirs.IMG_DIR.joinpath(recipe.image), ignore_errors=True)
|
|
@ -1,7 +1,6 @@
|
|||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from tests.test_config import TEST_HTML_DIR
|
||||
from tests import data as test_data
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -11,10 +10,7 @@ class RecipeSiteTestCase:
|
|||
expected_slug: str
|
||||
num_ingredients: int
|
||||
num_steps: int
|
||||
|
||||
@property
|
||||
def html_file(self) -> Path:
|
||||
return TEST_HTML_DIR / self.html
|
||||
html_file: str
|
||||
|
||||
|
||||
def get_recipe_test_cases():
|
||||
|
@ -22,6 +18,7 @@ def get_recipe_test_cases():
|
|||
RecipeSiteTestCase(
|
||||
url="https://www.seriouseats.com/taiwanese-three-cup-chicken-san-bei-gi-recipe",
|
||||
html="taiwanese-three-cup-chicken-san-bei-gi-recipe.html",
|
||||
html_file=test_data.html_taiwanese_three_cup_chicken_san_bei_gi_recipe,
|
||||
expected_slug="taiwanese-three-cup-chicken-san-bei-ji-recipe",
|
||||
num_ingredients=10,
|
||||
num_steps=3,
|
||||
|
@ -29,6 +26,7 @@ def get_recipe_test_cases():
|
|||
RecipeSiteTestCase(
|
||||
url="https://www.rezeptwelt.de/backen-herzhaft-rezepte/schinken-kaese-waffeln-ohne-viel-schnickschnack/4j0bkiig-94d4d-106529-cfcd2-is97x2ml",
|
||||
html="schinken-kase-waffeln-ohne-viel-schnickschnack.html",
|
||||
html_file=test_data.html_schinken_kase_waffeln_ohne_viel_schnickschnack,
|
||||
expected_slug="schinken-kase-waffeln-ohne-viel-schnickschnack",
|
||||
num_ingredients=7,
|
||||
num_steps=1, # Malformed JSON Data, can't parse steps just get one string
|
||||
|
@ -36,6 +34,7 @@ def get_recipe_test_cases():
|
|||
RecipeSiteTestCase(
|
||||
url="https://cookpad.com/us/recipes/5544853-sous-vide-smoked-beef-ribs",
|
||||
html="sous-vide-smoked-beef-ribs.html",
|
||||
html_file=test_data.html_sous_vide_smoked_beef_ribs,
|
||||
expected_slug="sous-vide-smoked-beef-ribs",
|
||||
num_ingredients=7,
|
||||
num_steps=12,
|
||||
|
@ -43,6 +42,7 @@ def get_recipe_test_cases():
|
|||
RecipeSiteTestCase(
|
||||
url="https://www.greatbritishchefs.com/recipes/jam-roly-poly-recipe",
|
||||
html="jam-roly-poly-with-custard.html",
|
||||
html_file=test_data.html_jam_roly_poly_with_custard,
|
||||
expected_slug="jam-roly-poly-with-custard",
|
||||
num_ingredients=13,
|
||||
num_steps=9,
|
||||
|
@ -50,6 +50,7 @@ def get_recipe_test_cases():
|
|||
RecipeSiteTestCase(
|
||||
url="https://recipes.anovaculinary.com/recipe/sous-vide-shrimp",
|
||||
html="sous-vide-shrimp.html",
|
||||
html_file=test_data.html_sous_vide_shrimp,
|
||||
expected_slug="sous-vide-shrimp",
|
||||
num_ingredients=5,
|
||||
num_steps=0,
|
||||
|
@ -57,6 +58,7 @@ def get_recipe_test_cases():
|
|||
RecipeSiteTestCase(
|
||||
url="https://www.bonappetit.com/recipe/detroit-style-pepperoni-pizza",
|
||||
html="detroit-style-pepperoni-pizza.html",
|
||||
html_file=test_data.html_detroit_style_pepperoni_pizza,
|
||||
expected_slug="detroit-style-pepperoni-pizza",
|
||||
num_ingredients=8,
|
||||
num_steps=5,
|
||||
|
|