Skip to content

Commit

Permalink
refactor main function
Browse files Browse the repository at this point in the history
  • Loading branch information
seethroughdev committed May 2, 2023
1 parent a56d1f6 commit 36618a7
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 131 deletions.
33 changes: 33 additions & 0 deletions constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,36 @@ export const PLUGIN_NAME = "Recipe Grabber";

export const CMD_OPEN_MODAL = "cmd-open-modal";
export const CMD_INSERT_RECIPE = "cmd-insert-recipe";

/* ---------------------------- DEFAULT TEMPLATE ---------------------------- */

export const DEFAULT_TEMPLATE = (url?: string) => `
---
date: Apr 28th, 2023 @11:41am
tags: recipe
created: {{datePublished}}
url: ${url}
---
# {{name}}
{{description}}
{{#if image}}
![{{name}}]({{image.url}})
{{/if}}
## Ingredients
{{#each recipeIngredient}}
- {{this}}
{{/each}}
## Instructions
{{#each recipeInstructions}}
- {{this.text}}
{{/each}}
-----
## Notes
`;
63 changes: 60 additions & 3 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Editor, MarkdownView, Plugin } from "obsidian";
import { Editor, MarkdownView, Plugin, Notice, requestUrl } from "obsidian";
import * as cheerio from "cheerio";
import * as c from "./constants";
import * as settings from "./settings";
import { Recipe } from "schema-dts";
import { LoadRecipeModal } from "./modal-load-recipe";
import * as handlebars from "handlebars";

export default class RecipeGrabber extends Plugin {
settings: settings.PluginSettings;
Expand All @@ -11,15 +14,15 @@ export default class RecipeGrabber extends Plugin {

// This creates an icon in the left ribbon.
this.addRibbonIcon("dice", c.PLUGIN_NAME, (evt: MouseEvent) => {
new LoadRecipeModal(this.app).open();
new LoadRecipeModal(this.app, this.getRecipes).open();
});

// This adds a simple command that can be triggered anywhere
this.addCommand({
id: c.CMD_OPEN_MODAL,
name: "Grab Recipe",
callback: () => {
new LoadRecipeModal(this.app).open();
new LoadRecipeModal(this.app, this.getRecipes).open();
},
});

Expand Down Expand Up @@ -61,4 +64,58 @@ export default class RecipeGrabber extends Plugin {
async saveSettings() {
await this.saveData(this.settings);
}

getRecipes = async (url: string) => {
const markdown = handlebars.compile(c.DEFAULT_TEMPLATE(url));
const recipes = await this.fetchRecipes(url);
recipes.forEach((recipe) => {
console.log(markdown(recipe));
});
};

async fetchRecipes(
url = "https://cooking.nytimes.com/recipes/1013116-simple-barbecue-sauce"
): Promise<Recipe[]> {
new Notice(`Fetching: ${url}`);
let response;

try {
response = await requestUrl({
url,
method: "GET",
headers: {
"Content-Type": "text/html",
},
});
} catch (err) {
return err;
}

const $ = cheerio.load(response.text);

const recipes: Recipe[] = [];

$('script[type="application/ld+json"]').each((i, el) => {
const content = $(el).text();
if (!content) return;
const json = JSON.parse(content);

// make sure its a recipe, this could be in an array or not
const _type = json?.["@type"];
if (
(Array.isArray(_type) && !_type.includes("Recipe")) ||
(typeof _type === "string" && _type !== "Recipe")
) {
return;
}

if (Array.isArray(json)) {
recipes.push(...json);
} else {
recipes.push(json);
}
});

return recipes;
}
}
110 changes: 4 additions & 106 deletions modal-load-recipe.ts
Original file line number Diff line number Diff line change
@@ -1,116 +1,14 @@
import {
App,
Editor,
MarkdownView,
Modal,
Notice,
Plugin,
PluginSettingTab,
Setting,
requestUrl,
} from "obsidian";
import * as cheerio from "cheerio";
import { CheerioAPI } from "cheerio";
import { Recipe } from "schema-dts";
import * as handlebars from "handlebars";
import { App, Modal, Setting } from "obsidian";

export class LoadRecipeModal extends Modal {
result: string;
template = (url: string) => `
---
date: Apr 28th, 2023 @11:41am
tags: recipe
created: {{datePublished}}
url: ${url}
---
onSubmit: (url: string) => void;

# {{name}}
{{description}}
{{#if image}}
![{{name}}]({{image.url}})
{{/if}}
## Ingredients
{{#each recipeIngredient}}
- {{this}}
{{/each}}
## Instructions
{{#each recipeInstructions}}
- {{this.text}}
{{/each}}
-----
## Notes
`;

constructor(app: App) {
constructor(app: App, onSubmit: (url: string) => void) {
super(app);
this.onSubmit = onSubmit;
}

getHtml = async (url: string) => {
new Notice(`Fetching: ${url}`);

try {
const resp = await requestUrl({
url,
method: "GET",
headers: {
"Content-Type": "text/html",
},
});

return resp.text;
} catch (err) {
return err;
}
};

get$ = (html: string): CheerioAPI => {
return cheerio.load(html);
};

getMarkdown = (recipe: Recipe, url: string): string | undefined => {
const _type = recipe?.["@type"];
// some sites are using the wrong type, @type as an array
if (
(Array.isArray(_type) && !_type.includes("Recipe")) ||
(typeof _type === "string" && _type !== "Recipe")
) {
return;
}

const html = handlebars.compile(this.template(url));
// execute the compiled template and print the output to the console
return html(recipe);
};

onSubmit = async (
result = "https://www.allrecipes.com/recipe/223042/chicken-parmesan/"
) => {
const html = await this.getHtml(result);
const $ = this.get$(html);

let markdown = "";
let recipe: Recipe;

$('script[type="application/ld+json"]').each((i, el) => {
const html = $(el).html();
if (!html) return;
recipe = JSON.parse(html);
if (Array.isArray(recipe)) {
recipe.forEach((j) =>
markdown.concat(this.getMarkdown(j, result) || "")
);
} else {
markdown = this.getMarkdown(recipe, result) || "";
}
});
};

onOpen() {
const { contentEl } = this;

Expand Down
37 changes: 15 additions & 22 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7"
]
},
"include": [
"**/*.ts"
]
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"lib": ["DOM", "ES5", "ES6", "ES7"]
},
"include": ["**/*.ts"]
}

0 comments on commit 36618a7

Please sign in to comment.