mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -07:00
fuzzy search
This commit is contained in:
parent
dc8894c62d
commit
0e59b13394
21 changed files with 350 additions and 221 deletions
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"python.formatting.provider": "black",
|
"python.formatting.provider": "black",
|
||||||
"python.pythonPath": "/home/hayden/projects/mealie/.venv/bin/python3",
|
"python.pythonPath": "/home/hayden/Projects/mealie/.venv/bin/python3",
|
||||||
"python.linting.pylintEnabled": true,
|
"python.linting.pylintEnabled": true,
|
||||||
"python.linting.enabled": true,
|
"python.linting.enabled": true,
|
||||||
"python.autoComplete.extraPaths": ["mealie", "mealie/mealie"],
|
"python.autoComplete.extraPaths": ["mealie", "mealie/mealie"],
|
||||||
|
|
5
frontend/package-lock.json
generated
5
frontend/package-lock.json
generated
|
@ -5663,6 +5663,11 @@
|
||||||
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
|
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"fuse.js": {
|
||||||
|
"version": "6.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.4.6.tgz",
|
||||||
|
"integrity": "sha512-/gYxR/0VpXmWSfZOIPS3rWwU8SHgsRTwWuXhyb2O6s7aRuVtHtxCkR33bNYu3wyLyNx/Wpv0vU7FZy8Vj53VNw=="
|
||||||
|
},
|
||||||
"gensync": {
|
"gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/gensync/download/gensync-1.0.0-beta.2.tgz?cache=0&sync_timestamp=1603829621482&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgensync%2Fdownload%2Fgensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npm.taobao.org/gensync/download/gensync-1.0.0-beta.2.tgz?cache=0&sync_timestamp=1603829621482&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgensync%2Fdownload%2Fgensync-1.0.0-beta.2.tgz",
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"core-js": "^3.8.2",
|
"core-js": "^3.8.2",
|
||||||
|
"fuse.js": "^6.4.6",
|
||||||
"qs": "^6.9.4",
|
"qs": "^6.9.4",
|
||||||
"v-jsoneditor": "^1.4.2",
|
"v-jsoneditor": "^1.4.2",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
<v-app>
|
<v-app>
|
||||||
<v-app-bar dense app color="primary" dark class="d-print-none">
|
<v-app-bar dense app color="primary" dark class="d-print-none">
|
||||||
<v-btn @click="$router.push('/')" icon class="d-flex align-center">
|
<v-btn @click="$router.push('/')" icon class="d-flex align-center">
|
||||||
<v-icon size="40">
|
<v-icon size="40"> mdi-silverware-variant </v-icon>
|
||||||
mdi-silverware-variant
|
|
||||||
</v-icon>
|
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<div btn class="pl-2">
|
<div btn class="pl-2">
|
||||||
<v-toolbar-title @click="$router.push('/')">Mealie</v-toolbar-title>
|
<v-toolbar-title @click="$router.push('/')">Mealie</v-toolbar-title>
|
||||||
|
@ -12,7 +10,7 @@
|
||||||
|
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
|
|
||||||
<v-btn icon @click="toggleSearch">
|
<v-btn icon @click="$router.push('/search')">
|
||||||
<v-icon>mdi-magnify</v-icon>
|
<v-icon>mdi-magnify</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
|
@ -22,10 +20,6 @@
|
||||||
<v-container>
|
<v-container>
|
||||||
<AddRecipeFab />
|
<AddRecipeFab />
|
||||||
<SnackBar />
|
<SnackBar />
|
||||||
<v-expand-transition>
|
|
||||||
<SearchHeader v-show="search" />
|
|
||||||
</v-expand-transition>
|
|
||||||
|
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</v-container>
|
</v-container>
|
||||||
</v-main>
|
</v-main>
|
||||||
|
@ -34,7 +28,6 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Menu from "./components/UI/Menu";
|
import Menu from "./components/UI/Menu";
|
||||||
import SearchHeader from "./components/UI/SearchHeader";
|
|
||||||
import AddRecipeFab from "./components/UI/AddRecipeFab";
|
import AddRecipeFab from "./components/UI/AddRecipeFab";
|
||||||
import SnackBar from "./components/UI/SnackBar";
|
import SnackBar from "./components/UI/SnackBar";
|
||||||
import Vuetify from "./plugins/vuetify";
|
import Vuetify from "./plugins/vuetify";
|
||||||
|
@ -44,14 +37,13 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
Menu,
|
Menu,
|
||||||
AddRecipeFab,
|
AddRecipeFab,
|
||||||
SearchHeader,
|
SnackBar,
|
||||||
SnackBar
|
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
$route() {
|
$route() {
|
||||||
this.search = false;
|
this.search = false;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -62,7 +54,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
search: false
|
search: false,
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
|
@ -90,8 +82,8 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.search = true;
|
this.search = true;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
100
frontend/src/components/UI/SearchBar.vue
Normal file
100
frontend/src/components/UI/SearchBar.vue
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-text-field
|
||||||
|
label="Search"
|
||||||
|
v-model="search"
|
||||||
|
solo
|
||||||
|
></v-text-field>
|
||||||
|
<v-card v-if="search && showResults">
|
||||||
|
<v-hover
|
||||||
|
square
|
||||||
|
v-for="(item, index) in result.slice(0, 5)"
|
||||||
|
:key="index"
|
||||||
|
v-slot="{ hover }"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
class="color-transition"
|
||||||
|
@click="$router.push(`/recipe/${item.item.slug}`)"
|
||||||
|
:color="hover ? highlightColor : null"
|
||||||
|
>
|
||||||
|
<v-row dense no-gutters>
|
||||||
|
<v-col cols="12" md="2" sm="6">
|
||||||
|
<v-img
|
||||||
|
:src="getImage(item.item.image)"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
rounded
|
||||||
|
>
|
||||||
|
</v-img>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="10" sm="6">
|
||||||
|
<v-card-title> {{ item.item.name }}</v-card-title>
|
||||||
|
<v-card-text> {{ item.item.description }}</v-card-text></v-col
|
||||||
|
>
|
||||||
|
</v-row>
|
||||||
|
</v-card>
|
||||||
|
</v-hover>
|
||||||
|
</v-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Fuse from "fuse.js";
|
||||||
|
import utils from "../../utils";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
showResults: {
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
search: "",
|
||||||
|
result: [],
|
||||||
|
isDark: false,
|
||||||
|
options: {
|
||||||
|
shouldSort: true,
|
||||||
|
threshold: 0.6,
|
||||||
|
location: 0,
|
||||||
|
distance: 100,
|
||||||
|
maxPatternLength: 32,
|
||||||
|
minMatchCharLength: 1,
|
||||||
|
keys: ["name", "slug"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.isDark = this.$store.getters.getIsDark;
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
data() {
|
||||||
|
return this.$store.getters.getRecentRecipes;
|
||||||
|
},
|
||||||
|
fuse() {
|
||||||
|
return new Fuse(this.data, this.options);
|
||||||
|
},
|
||||||
|
highlightColor() {
|
||||||
|
return this.isDark ? "primary lighten-5" : "primary lighten-5";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
search() {
|
||||||
|
if (this.search.trim() === "") this.result = this.list;
|
||||||
|
else this.result = this.fuse.search(this.search.trim());
|
||||||
|
this.$emit("results", this.result);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getImage(image) {
|
||||||
|
return utils.getImageURL(image);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.color-transition {
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
</style>
|
57
frontend/src/pages/SearchPage.vue
Normal file
57
frontend/src/pages/SearchPage.vue
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-row justify="center">
|
||||||
|
<v-col cols="1"> </v-col>
|
||||||
|
<v-col>
|
||||||
|
<SearchBar @results="updateResults" />
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="2">
|
||||||
|
<v-btn icon>
|
||||||
|
<v-icon large> mdi-filter </v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
<v-row v-if="searchResults">
|
||||||
|
<v-col
|
||||||
|
:sm="6"
|
||||||
|
:md="6"
|
||||||
|
:lg="4"
|
||||||
|
:xl="3"
|
||||||
|
v-for="item in searchResults.slice(0, 10)"
|
||||||
|
:key="item.item.name"
|
||||||
|
>
|
||||||
|
<RecipeCard
|
||||||
|
:name="item.item.name"
|
||||||
|
:description="item.item.description"
|
||||||
|
:slug="item.item.slug"
|
||||||
|
:rating="item.item.rating"
|
||||||
|
:image="item.item.image"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SearchBar from "../components/UI/SearchBar";
|
||||||
|
import RecipeCard from "../components/UI/RecipeCard";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SearchBar,
|
||||||
|
RecipeCard,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
searchResults: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateResults(results) {
|
||||||
|
this.searchResults = results;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
|
@ -1,5 +1,6 @@
|
||||||
import HomePage from "./pages/HomePage";
|
import HomePage from "./pages/HomePage";
|
||||||
import Page404 from "./pages/404Page";
|
import Page404 from "./pages/404Page";
|
||||||
|
import SearchPage from "./pages/SearchPage";
|
||||||
import RecipePage from "./pages/RecipePage";
|
import RecipePage from "./pages/RecipePage";
|
||||||
import RecipeNewPage from "./pages/RecipeNewPage";
|
import RecipeNewPage from "./pages/RecipeNewPage";
|
||||||
import SettingsPage from "./pages/SettingsPage";
|
import SettingsPage from "./pages/SettingsPage";
|
||||||
|
@ -10,6 +11,7 @@ import api from "./api";
|
||||||
export const routes = [
|
export const routes = [
|
||||||
{ path: "/", component: HomePage },
|
{ path: "/", component: HomePage },
|
||||||
{ path: "/mealie", component: HomePage },
|
{ path: "/mealie", component: HomePage },
|
||||||
|
{ path: "/search", component: SearchPage },
|
||||||
{ path: "/recipe/:recipe", component: RecipePage },
|
{ path: "/recipe/:recipe", component: RecipePage },
|
||||||
{ path: "/new/", component: RecipeNewPage },
|
{ path: "/new/", component: RecipeNewPage },
|
||||||
{ path: "/settings/site", component: SettingsPage },
|
{ path: "/settings/site", component: SettingsPage },
|
||||||
|
|
|
@ -17,6 +17,7 @@ function inDarkMode(payload) {
|
||||||
const state = {
|
const state = {
|
||||||
activeTheme: {},
|
activeTheme: {},
|
||||||
darkMode: "system",
|
darkMode: "system",
|
||||||
|
isDark: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
|
@ -30,6 +31,7 @@ const mutations = {
|
||||||
|
|
||||||
if (isDark !== null) {
|
if (isDark !== null) {
|
||||||
Vuetify.framework.theme.dark = isDark;
|
Vuetify.framework.theme.dark = isDark;
|
||||||
|
state.isDark = isDark;
|
||||||
state.darkMode = payload;
|
state.darkMode = payload;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -60,6 +62,7 @@ const actions = {
|
||||||
const getters = {
|
const getters = {
|
||||||
getActiveTheme: (state) => state.activeTheme,
|
getActiveTheme: (state) => state.activeTheme,
|
||||||
getDarkMode: (state) => state.darkMode,
|
getDarkMode: (state) => state.darkMode,
|
||||||
|
getIsDark: (state) => state.isDark,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -94,11 +94,11 @@ class BaseDocument:
|
||||||
else:
|
else:
|
||||||
return db_entry
|
return db_entry
|
||||||
|
|
||||||
def save_new(self, document: dict) -> str:
|
def save_new(self, document: dict) -> dict:
|
||||||
if USE_MONGO:
|
if USE_MONGO:
|
||||||
new_document = self.document(**document)
|
new_document = self.document(**document)
|
||||||
new_document.save()
|
new_document.save()
|
||||||
return new_document
|
return BaseDocument._unpack_mongo(new_document)
|
||||||
elif USE_TINYDB:
|
elif USE_TINYDB:
|
||||||
return self.store.save(document)
|
return self.store.save(document)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ class StoreBase:
|
||||||
|
|
||||||
if data != []:
|
if data != []:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"Cannot Save, Primary Key: {self.primary_key} already exists"
|
f"Cannot Save, Primary Key: {document[self.primary_key]} already exists"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.store.insert(document)
|
self.store.insert(document)
|
||||||
|
|
|
@ -2,7 +2,6 @@ import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from unsync import unsync
|
|
||||||
|
|
||||||
CWD = Path(__file__).parent
|
CWD = Path(__file__).parent
|
||||||
IMG_DIR = CWD.parent.joinpath("data", "img")
|
IMG_DIR = CWD.parent.joinpath("data", "img")
|
||||||
|
|
|
@ -47,7 +47,7 @@ else:
|
||||||
|
|
||||||
|
|
||||||
# DATABASE ENV
|
# DATABASE ENV
|
||||||
DATABASE_TYPE = os.getenv("db_type", "tinydb") # mongo, tinydb
|
DATABASE_TYPE = os.getenv("db_type", "mongo") # mongo, tinydb
|
||||||
if DATABASE_TYPE == "tinydb":
|
if DATABASE_TYPE == "tinydb":
|
||||||
USE_TINYDB = True
|
USE_TINYDB = True
|
||||||
USE_MONGO = False
|
USE_MONGO = False
|
||||||
|
@ -58,7 +58,7 @@ elif DATABASE_TYPE == "mongo":
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"Unable to determine database type. Acceptible options are 'mongo' or 'sqlite' "
|
"Unable to determine database type. Acceptible options are 'mongo' or 'tinydb' "
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mongo Database
|
# Mongo Database
|
||||||
|
|
80
poetry.lock
generated
80
poetry.lock
generated
|
@ -1,80 +0,0 @@
|
||||||
[[package]]
|
|
||||||
name = "fastapi"
|
|
||||||
version = "0.63.0"
|
|
||||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pydantic = ">=1.0.0,<2.0.0"
|
|
||||||
starlette = "0.13.6"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
all = ["requests (>=2.24.0,<3.0.0)", "aiofiles (>=0.5.0,<0.6.0)", "jinja2 (>=2.11.2,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<2.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "graphene (>=2.1.8,<3.0.0)", "ujson (>=3.0.0,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.14.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)"]
|
|
||||||
dev = ["python-jose[cryptography] (>=3.1.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.14.0)", "graphene (>=2.1.8,<3.0.0)"]
|
|
||||||
doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=6.1.4,<7.0.0)", "markdown-include (>=0.5.1,<0.6.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.2.0)", "typer-cli (>=0.0.9,<0.0.10)", "pyyaml (>=5.3.1,<6.0.0)"]
|
|
||||||
test = ["pytest (==5.4.3)", "pytest-cov (==2.10.0)", "pytest-asyncio (>=0.14.0,<0.15.0)", "mypy (==0.790)", "flake8 (>=3.8.3,<4.0.0)", "black (==20.8b1)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.15.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.4.0)", "orjson (>=3.2.1,<4.0.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "aiofiles (>=0.5.0,<0.6.0)", "flask (>=1.1.2,<2.0.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pydantic"
|
|
||||||
version = "1.7.3"
|
|
||||||
description = "Data validation and settings management using python 3.6 type hinting"
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
|
||||||
email = ["email-validator (>=1.0.3)"]
|
|
||||||
typing_extensions = ["typing-extensions (>=3.7.2)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "starlette"
|
|
||||||
version = "0.13.6"
|
|
||||||
description = "The little ASGI library that shines."
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "ujson"]
|
|
||||||
|
|
||||||
[metadata]
|
|
||||||
lock-version = "1.1"
|
|
||||||
python-versions = "^3.8"
|
|
||||||
content-hash = "fd85f1208985afed8ec0a1322873546cc1c1eb44f0f443225647806e9f6eead0"
|
|
||||||
|
|
||||||
[metadata.files]
|
|
||||||
fastapi = [
|
|
||||||
{file = "fastapi-0.63.0-py3-none-any.whl", hash = "sha256:98d8ea9591d8512fdadf255d2a8fa56515cdd8624dca4af369da73727409508e"},
|
|
||||||
{file = "fastapi-0.63.0.tar.gz", hash = "sha256:63c4592f5ef3edf30afa9a44fa7c6b7ccb20e0d3f68cd9eba07b44d552058dcb"},
|
|
||||||
]
|
|
||||||
pydantic = [
|
|
||||||
{file = "pydantic-1.7.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c59ea046aea25be14dc22d69c97bee629e6d48d2b2ecb724d7fe8806bf5f61cd"},
|
|
||||||
{file = "pydantic-1.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a4143c8d0c456a093387b96e0f5ee941a950992904d88bc816b4f0e72c9a0009"},
|
|
||||||
{file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d8df4b9090b595511906fa48deda47af04e7d092318bfb291f4d45dfb6bb2127"},
|
|
||||||
{file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:514b473d264671a5c672dfb28bdfe1bf1afd390f6b206aa2ec9fed7fc592c48e"},
|
|
||||||
{file = "pydantic-1.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:dba5c1f0a3aeea5083e75db9660935da90216f8a81b6d68e67f54e135ed5eb23"},
|
|
||||||
{file = "pydantic-1.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59e45f3b694b05a69032a0d603c32d453a23f0de80844fb14d55ab0c6c78ff2f"},
|
|
||||||
{file = "pydantic-1.7.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5b24e8a572e4b4c18f614004dda8c9f2c07328cb5b6e314d6e1bbd536cb1a6c1"},
|
|
||||||
{file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:b2b054d095b6431cdda2f852a6d2f0fdec77686b305c57961b4c5dd6d863bf3c"},
|
|
||||||
{file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:025bf13ce27990acc059d0c5be46f416fc9b293f45363b3d19855165fee1874f"},
|
|
||||||
{file = "pydantic-1.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6e3874aa7e8babd37b40c4504e3a94cc2023696ced5a0500949f3347664ff8e2"},
|
|
||||||
{file = "pydantic-1.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e682f6442ebe4e50cb5e1cfde7dda6766fb586631c3e5569f6aa1951fd1a76ef"},
|
|
||||||
{file = "pydantic-1.7.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:185e18134bec5ef43351149fe34fda4758e53d05bb8ea4d5928f0720997b79ef"},
|
|
||||||
{file = "pydantic-1.7.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:f5b06f5099e163295b8ff5b1b71132ecf5866cc6e7f586d78d7d3fd6e8084608"},
|
|
||||||
{file = "pydantic-1.7.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:24ca47365be2a5a3cc3f4a26dcc755bcdc9f0036f55dcedbd55663662ba145ec"},
|
|
||||||
{file = "pydantic-1.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:d1fe3f0df8ac0f3a9792666c69a7cd70530f329036426d06b4f899c025aca74e"},
|
|
||||||
{file = "pydantic-1.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f6864844b039805add62ebe8a8c676286340ba0c6d043ae5dea24114b82a319e"},
|
|
||||||
{file = "pydantic-1.7.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ecb54491f98544c12c66ff3d15e701612fc388161fd455242447083350904730"},
|
|
||||||
{file = "pydantic-1.7.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ffd180ebd5dd2a9ac0da4e8b995c9c99e7c74c31f985ba090ee01d681b1c4b95"},
|
|
||||||
{file = "pydantic-1.7.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8d72e814c7821125b16f1553124d12faba88e85405b0864328899aceaad7282b"},
|
|
||||||
{file = "pydantic-1.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:475f2fa134cf272d6631072554f845d0630907fce053926ff634cc6bc45bf1af"},
|
|
||||||
{file = "pydantic-1.7.3-py3-none-any.whl", hash = "sha256:38be427ea01a78206bcaf9a56f835784afcba9e5b88fbdce33bbbfbcd7841229"},
|
|
||||||
{file = "pydantic-1.7.3.tar.gz", hash = "sha256:213125b7e9e64713d16d988d10997dabc6a1f73f3991e1ff8e35ebb1409c7dc9"},
|
|
||||||
]
|
|
||||||
starlette = [
|
|
||||||
{file = "starlette-0.13.6-py3-none-any.whl", hash = "sha256:bd2ffe5e37fb75d014728511f8e68ebf2c80b0fa3d04ca1479f4dc752ae31ac9"},
|
|
||||||
{file = "starlette-0.13.6.tar.gz", hash = "sha256:ebe8ee08d9be96a3c9f31b2cb2a24dbdf845247b745664bd8a3f9bd0c977fdbc"},
|
|
||||||
]
|
|
|
@ -1,2 +0,0 @@
|
||||||
[virtualenvs]
|
|
||||||
in-project = true
|
|
116
pyproject.toml
116
pyproject.toml
|
@ -1,116 +0,0 @@
|
||||||
[tool.poetry]
|
|
||||||
name = "mealie"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Recipe Manager"
|
|
||||||
authors = ["Hayden <hay-kot@pm.me>"]
|
|
||||||
license = "MIT"
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
python = "^3.8"
|
|
||||||
fastapi = "0.61.1"
|
|
||||||
aiofiles = "0.5.0"
|
|
||||||
aniso8601 = "7.0.0"
|
|
||||||
appdirs = "1.4.4"
|
|
||||||
APScheduler = "3.6.3"
|
|
||||||
astroid = "2.4.2"
|
|
||||||
async-exit-stack = "1.0.1"
|
|
||||||
async_generator = "1.10"
|
|
||||||
attrs = "20.3.0"
|
|
||||||
beautifulsoup4 = "4.9.1"
|
|
||||||
black = "20.8b1"
|
|
||||||
certifi = "2020.6.20"
|
|
||||||
chardet = "3.0.4"
|
|
||||||
click = "7.1.2"
|
|
||||||
colorama = "0.4.3"
|
|
||||||
decorator = "4.4.2"
|
|
||||||
dnspython = "2.0.0"
|
|
||||||
email-validator = "1.1.1"
|
|
||||||
extruct = "0.10.0"
|
|
||||||
fastapi-login = "1.5.1"
|
|
||||||
future = "0.18.2"
|
|
||||||
gitdb = "4.0.5"
|
|
||||||
GitPython = "3.1.11"
|
|
||||||
graphene = "2.1.8"
|
|
||||||
graphql-core = "2.3.2"
|
|
||||||
graphql-relay = "2.0.1"
|
|
||||||
h11 = "0.9.0"
|
|
||||||
html-text = "0.5.2"
|
|
||||||
html5lib = "1.1"
|
|
||||||
httptools = "0.1.1"
|
|
||||||
idna = "2.10"
|
|
||||||
iniconfig = "1.1.1"
|
|
||||||
isodate = "0.6.0"
|
|
||||||
isort = "5.4.2"
|
|
||||||
itsdangerous = "1.1.0"
|
|
||||||
Jinja2 = "2.11.2"
|
|
||||||
joblib = "1.0.0"
|
|
||||||
jstyleson = "0.0.2"
|
|
||||||
lazy-object-proxy = "1.4.3"
|
|
||||||
livereload = "2.6.3"
|
|
||||||
lunr = "0.5.8"
|
|
||||||
lxml = "4.6.2"
|
|
||||||
Markdown = "3.3.3"
|
|
||||||
MarkupSafe = "1.1.1"
|
|
||||||
mccabe = "0.6.1"
|
|
||||||
mf2py = "1.1.2"
|
|
||||||
mkdocs = "1.1.2"
|
|
||||||
mkdocs-material = "6.1.7"
|
|
||||||
mkdocs-material-extensions = "1.0.1"
|
|
||||||
mongoengine = "0.21.0"
|
|
||||||
mypy-extensions = "0.4.3"
|
|
||||||
nltk = "3.5"
|
|
||||||
packaging = "20.8"
|
|
||||||
passlib = "1.7.4"
|
|
||||||
pathspec = "0.8.0"
|
|
||||||
pdfkit = "0.6.1"
|
|
||||||
pip-chill = "1.0.0"
|
|
||||||
pluggy = "0.13.1"
|
|
||||||
promise = "2.3"
|
|
||||||
py = "1.10.0"
|
|
||||||
pydantic = "1.6.1"
|
|
||||||
Pygments = "2.7.3"
|
|
||||||
PyJWT = "1.7.1"
|
|
||||||
pylint = "2.6.0"
|
|
||||||
pymdown-extensions = "8.0.1"
|
|
||||||
pymongo = "3.11.1"
|
|
||||||
pyparsing = "2.4.7"
|
|
||||||
pytest = "6.2.1"
|
|
||||||
python-dateutil = "2.8.1"
|
|
||||||
python-dotenv = "0.15.0"
|
|
||||||
python-multipart = "0.0.5"
|
|
||||||
python-slugify = "4.0.1"
|
|
||||||
pytz = "2020.4"
|
|
||||||
PyYAML = "5.3.1"
|
|
||||||
rdflib = "4.2.2"
|
|
||||||
rdflib-jsonld = "0.5.0"
|
|
||||||
regex = "2020.7.14"
|
|
||||||
requests = "2.24.0"
|
|
||||||
Rx = "1.6.1"
|
|
||||||
scrape-schema-recipe = "0.1.1"
|
|
||||||
six = "1.15.0"
|
|
||||||
smmap = "3.0.4"
|
|
||||||
soupsieve = "2.0.1"
|
|
||||||
SQLAlchemy = "1.3.22"
|
|
||||||
starlette = "0.13.6"
|
|
||||||
text-unidecode = "1.3"
|
|
||||||
toml = "0.10.1"
|
|
||||||
tornado = "6.1"
|
|
||||||
tqdm = "4.54.1"
|
|
||||||
typed-ast = "1.4.1"
|
|
||||||
typing-extensions = "3.7.4.3"
|
|
||||||
tzlocal = "2.1"
|
|
||||||
ujson = "3.1.0"
|
|
||||||
urllib3 = "1.25.10"
|
|
||||||
uvicorn = "0.11.8"
|
|
||||||
uvloop = "0.14.0"
|
|
||||||
validators = "0.18.0"
|
|
||||||
w3lib = "1.22.0"
|
|
||||||
webencodings = "0.5.1"
|
|
||||||
websockets = "8.1"
|
|
||||||
wrapt = "1.12.1"
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["poetry-core>=1.0.0"]
|
|
||||||
build-backend = "poetry.core.masonry.api"
|
|
168
scratch.json
Normal file
168
scratch.json
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Pizzettes",
|
||||||
|
"slug": "pizzettes",
|
||||||
|
"image": "pizzettes.jpg",
|
||||||
|
"description": "Not to be confused with wafer-thin waffled pizzelles, this rich brownie-like cookie packed with warm spices is exactly the opposite.",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Detroit-Style Pepperoni Pizza",
|
||||||
|
"slug": "detroit-style-pepperoni-pizza",
|
||||||
|
"image": "detroit-style-pepperoni-pizza.jpg",
|
||||||
|
"description": "So you want to make pizza, but it’s your first time. This Detroit-style pizza from Bryan Ford, which uses a half-batch of his Master Dough, is perfect for beginners because you don’t have to shape the dough or wrangle a hot pizza stone. If you don’t have a Detroit pizza pan (its deep sides and black anodized aluminum help achieve a crust that’s fluffy on the inside but crisp all around), that’s okay: Use a 13x9\" baking pan or two 8x8\" baking pans.",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 3
|
||||||
|
},
|
||||||
|
"refIndex": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Marranitos Enfiestados",
|
||||||
|
"slug": "marranitos-enfiestados",
|
||||||
|
"image": "marranitos-enfiestados.jpg",
|
||||||
|
"description": "Rick Martinez’s take on the popular Mexican pig-shaped cookie goes all out with a ginger-spiced dough and tons of sprinkles.",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 4
|
||||||
|
},
|
||||||
|
"refIndex": 23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Roasted Okra",
|
||||||
|
"slug": "roasted-okra",
|
||||||
|
"image": "roasted-okra.jpg",
|
||||||
|
"description": "I love me some okra, but prep is usually enough to avoid making it. This simple dish requires only a single cut per pod and a dash of seasoning- that's it.",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Pork Steaks",
|
||||||
|
"slug": "pork-steaks",
|
||||||
|
"image": "pork-steaks.jpg",
|
||||||
|
"description": "Pork is called \"the other white meat\", but this sous vide technique is so dang good I'm gonna graduate it up to \"THE white meat\".",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 29
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Roasted Brussels Sprouts",
|
||||||
|
"slug": "roasted-brussels-sprouts",
|
||||||
|
"image": "roasted-brussels-sprouts.jpg",
|
||||||
|
"description": "A lot of places are doing dang good brussels lately, but none can touch [Salty Sow](http://saltysow.com/). They serve them fried, topped with pecorino and golden raisins. Yes, please.\nWe started trying to emulate it, but it's such a versatile dish, you can make it however you want. Consider this a loose guide.",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 34
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Buttery Kimchi Chicken",
|
||||||
|
"slug": "buttery-kimchi-chicken",
|
||||||
|
"image": "buttery-kimchi-chicken.jpg",
|
||||||
|
"description": "This spicy and sweet, slightly nutty, and creamy stew from developer Sunny Lee is worth the tending (and time) it requires over the stove.",
|
||||||
|
"dateAdded": 1610323200000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Tequila, Beer, and Citrus Cocktail",
|
||||||
|
"slug": "tequila-beer-and-citrus-cocktail",
|
||||||
|
"image": "tequila-beer-and-citrus-cocktail.jpg",
|
||||||
|
"description": "The holiday cocktail that takes you straight to the beach (and isn’t that where you want to be anyway?). ",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 35
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Pasta With Mushrooms and Cashew Cream",
|
||||||
|
"slug": "pasta-with-mushrooms-and-cashew-cream",
|
||||||
|
"image": "pasta-with-mushrooms-and-cashew-cream.jpg",
|
||||||
|
"description": "Might you mistake this vegan cream for actual alfredo sauce? Maybe. Maybe not. It’s delicious either way.",
|
||||||
|
"dateAdded": 1610323200000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "New York Strip",
|
||||||
|
"slug": "new-york-strip",
|
||||||
|
"image": "new-york-strip.jpg",
|
||||||
|
"description": "Cooking a steak in a water bath is the ultimate, both in terms of flavor and laziness. Dial in a precise temperature, then go take a nap.",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Green Spaghetti",
|
||||||
|
"slug": "green-spaghetti",
|
||||||
|
"image": "green-spaghetti.jpg",
|
||||||
|
"description": "We saw this on Jamie Oliver's TV show and made it that night. He calls for **cavolo nero** as the greens, but dinosaur kale or spinach or any dark leafy green will do. The bigger the green, the easier it is to fish out of the boiling water, so keep that in mind.\nStart to finish this whole recipe takes about 10 minutes, but it's pretty rapid fire once you get stated. Have plates and an appetite standing by.",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 37
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "One Minute Muffin",
|
||||||
|
"slug": "one-minute-muffin",
|
||||||
|
"image": "one-minute-muffin.jpg",
|
||||||
|
"description": "This flax muffin is quick, vertsatile (just mix in other goodies), and only makes one at a time, so you've got no huge tray to tempt you. Custom muffins every morning!",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Bon Appétit's Perfect Pizza",
|
||||||
|
"slug": "bon-appetit-s-perfect-pizza",
|
||||||
|
"image": "bon-appetit-s-perfect-pizza.jpg",
|
||||||
|
"description": "With the amount of love, time, and research that went into making what constitutes the “perfect” pizza, you’ll definitely want to share. Welcome to the best-ever excuse to invite people over for a pizza party.",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 3
|
||||||
|
},
|
||||||
|
"refIndex": 39
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Green Chile Stew",
|
||||||
|
"slug": "green-chile-stew",
|
||||||
|
"image": "green-chile-stew.jpg",
|
||||||
|
"description": "This is a simple one, consisting of a pre-made soup mix and whatever you've got around the kitchen (or campsite). Feel free to sub/swap/switch anything in the ingredient list— anything's fair game!",
|
||||||
|
"dateAdded": 1610409600000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 27
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": {
|
||||||
|
"name": "Marinated Tofu With Brussels Sprouts and Farro",
|
||||||
|
"slug": "marinated-tofu-with-brussels-sprouts-and-farro",
|
||||||
|
"image": "marinated-tofu-with-brussels-sprouts-and-farro.jpg",
|
||||||
|
"description": "The soul of this recipe comes from the ginger and tamari marinade that gives a sweet and savory winter coat to the crispy tofu. ",
|
||||||
|
"dateAdded": 1610323200000,
|
||||||
|
"rating": 0
|
||||||
|
},
|
||||||
|
"refIndex": 6
|
||||||
|
}
|
||||||
|
]
|
||||||
|
Pasta With Mushrooms and Cashe...
|
Loading…
Add table
Add a link
Reference in a new issue