("l" "Links (it)" entry (file+headline "~/org/refile.org" "Links")
"** %c\n\n %u\n %i"
:empty-lines 1)
-
- ))
+ ("C" "Cookbook" entry (file+headline "~/org/kitchen.org" "[[http://allrecipes.com][AllRecipes.com]]")
+ "%(org-chef-get-recipe-from-url)"
+ :empty-lines 1)))
#+END_SRC
--- /dev/null
+;;; org-chef-all-recipes.el --- org-chef allrecipes fetching. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; Functions for fetching information from allrecipes.com.
+
+;;; Code:
+
+
+(require 'org-chef-utils)
+(require 'dom)
+
+
+(defun org-chef-all-recipes-extract-name (dom)
+ "Get the name of a recipe from an allrecipes DOM."
+ (dom-text (car (dom-by-class dom "^recipe-summary__h1$"))))
+
+
+(defun org-chef-all-recipes-extract-ingredients (dom)
+ "Get the ingredients for a recipe from an allrecipes DOM."
+ (mapcar 'dom-text (dom-elements dom 'itemprop "^ingredients$")))
+
+
+(defun org-chef-all-recipes-extract-servings (dom)
+ "Get the number of servings for a recipe from an allrecipes DOM."
+ (dom-attr (car (dom-by-id dom "metaRecipeServings")) 'content))
+
+
+(defun org-chef-all-recipes-extract-prep-time (dom)
+ "Get the amount of prep-time for a recipe from an allrecipes DOM."
+ (dom-texts (car (dom-elements dom 'itemprop "^prepTime$"))))
+
+
+(defun org-chef-all-recipes-extract-cook-time (dom)
+ "Get the amount of cook-time for a recipe from an allrecipes DOM."
+ (dom-texts (car (dom-elements dom 'itemprop "^cookTime$"))))
+
+
+(defun org-chef-all-recipes-extract-ready-in (dom)
+ "Get the total amount of time for a recipe from an allrecipes DOM."
+ (dom-texts (car (dom-elements dom 'itemprop "^totalTime$"))))
+
+
+(defun org-chef-all-recipes-extract-directions (dom)
+ "Get the directions for a recipe from an allrecipes DOM."
+ (org-chef-remove-empty-strings (mapcar 'dom-text (dom-by-class dom "^recipe-directions__list--item$"))))
+
+
+(defun org-chef-all-recipes-fetch (url)
+ "Given an allrecipes.com URL, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions
+- source-url"
+ (with-current-buffer (url-retrieve-synchronously url)
+ (let ((dom (libxml-parse-html-region (point-min) (point-max))))
+
+ `((name . ,(org-chef-all-recipes-extract-name dom))
+ (ingredients . ,(org-chef-all-recipes-extract-ingredients dom))
+ (servings . ,(org-chef-all-recipes-extract-servings dom))
+ (prep-time . ,(org-chef-all-recipes-extract-prep-time dom))
+ (cook-time . ,(org-chef-all-recipes-extract-cook-time dom))
+ (ready-in . ,(org-chef-all-recipes-extract-ready-in dom))
+ (directions . ,(org-chef-all-recipes-extract-directions dom))
+ (source-url . ,url)))))
+
+
+(provide 'org-chef-all-recipes)
+;;; org-chef-all-recipes.el ends here
--- /dev/null
+;;; org-chef-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+\f
+;;;### (autoloads nil nil ("org-chef-all-recipes.el" "org-chef-budget-bytes.el"
+;;;;;; "org-chef-cultures-for-health.el" "org-chef-genius-kitchen.el"
+;;;;;; "org-chef-martha-stewart.el" "org-chef-pkg.el" "org-chef-serious-eats.el"
+;;;;;; "org-chef-simply-recipes.el" "org-chef-utils.el" "org-chef.el")
+;;;;;; (23201 17073 680606 28000))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; org-chef-autoloads.el ends here
--- /dev/null
+;;; org-chef-budget-bytes.el --- org-chef budgetbytes fetching. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; Functions for fetching information from budgetbytes.com.
+
+;;; Code:
+
+
+(require 'org-chef-utils)
+(require 'dom)
+
+
+(defun org-chef-budget-bytes-extract-name (dom)
+ "Get the name of a recipe from an budgetbytes DOM."
+ (dom-text (car (dom-by-class dom "^wprm-recipe-name$"))))
+
+
+(defun org-chef-budget-bytes-ingredient-to-string (dom)
+ (let* ((amount (string-trim (dom-text (car (dom-by-class dom "wprm-recipe-ingredient-amount")))))
+ (unit (string-trim (dom-text (car (dom-by-class dom "wprm-recipe-ingredient-unit")))))
+ (name (string-trim (dom-text (car (dom-by-class dom "wprm-recipe-ingredient-name"))))))
+ (format "%s %s %s" amount unit name)))
+
+
+(defun org-chef-budget-bytes-extract-ingredients (dom)
+ "Get the ingredients for a recipe from an budgetbytes DOM."
+ (mapcar #'(lambda (n) (org-chef-budget-bytes-ingredient-to-string n))
+ (dom-by-class dom "^wprm-recipe-ingredient$")))
+
+
+(defun org-chef-budget-bytes-extract-servings (dom)
+ "Get the number of servings for a recipe from an budgetbytes DOM."
+ (dom-text (car (dom-by-class dom "wprm-recipe-servings$"))))
+
+
+(defun org-chef-budget-bytes-time-to-string (dom)
+ (let* ((hours (string-trim (dom-text (car (dom-by-class dom "hours$")))))
+ (minutes (string-trim (dom-text (car (dom-by-class dom "minutes$")))))
+ (hour-string (if (/= (length hours) 0) (format "%s hours " hours) ""))
+ (minute-string (if (/= (length minutes) 0) (format "%s minutes" minutes) "")))
+ (string-trim (concat hour-string minute-string))))
+
+
+(defun org-chef-budget-bytes-extract-prep-time (dom)
+ "Get the amount of prep-time for a recipe from an budgetbytes DOM."
+ (org-chef-budget-bytes-time-to-string (car (dom-by-class dom "wprm-recipe-prep-time-container"))))
+
+
+(defun org-chef-budget-bytes-extract-cook-time (dom)
+ "Get the amount of cook-time for a recipe from an budgetbytes DOM."
+ (org-chef-budget-bytes-time-to-string (car (dom-by-class dom "wprm-recipe-cook-time-container"))))
+
+
+(defun org-chef-budget-bytes-extract-ready-in (dom)
+ "Get the total amount of time for a recipe from an budgetbytes DOM."
+ (org-chef-budget-bytes-time-to-string (car (dom-by-class dom "wprm-recipe-total-time-container"))))
+
+
+(defun org-chef-budget-bytes-extract-directions (dom)
+ "Get the directions for a recipe from an budgetbytes DOM."
+ (mapcar #'(lambda (n) (string-trim (dom-texts (dom-children n))))
+ (dom-by-class dom "wprm-recipe-instruction-text")))
+
+
+(defun org-chef-budget-bytes-fetch (url)
+ "Given an budgetbytes.com URL, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions
+- source-url"
+ (with-current-buffer (url-retrieve-synchronously url)
+ (let ((dom (libxml-parse-html-region (point-min) (point-max))))
+
+ `((name . ,(org-chef-budget-bytes-extract-name dom))
+ (ingredients . ,(org-chef-budget-bytes-extract-ingredients dom))
+ (servings . ,(org-chef-budget-bytes-extract-servings dom))
+ (prep-time . ,(org-chef-budget-bytes-extract-prep-time dom))
+ (cook-time . ,(org-chef-budget-bytes-extract-cook-time dom))
+ (ready-in . ,(org-chef-budget-bytes-extract-ready-in dom))
+ (directions . ,(org-chef-budget-bytes-extract-directions dom))
+ (source-url . ,url)))))
+
+
+(provide 'org-chef-budget-bytes)
+;;; org-chef-budget-bytes.el ends here
--- /dev/null
+;;; org-chef-cultures-for-health.el --- Functions for fetching recipes from culturesforhealth.com. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; Functions for fetching information from culturesforhealth.com.
+
+;;; Code:
+
+
+(require 'org-chef-utils)
+(require 'dom)
+
+
+(defun org-chef-cultures-for-health-extract-name (dom)
+ "Get the name of a recipe from an culturesforhealth DOM."
+ (dom-text (car (dom-elements dom 'itemprop "^name$"))))
+
+
+(defun org-chef-cultures-for-health-extract-ingredients (dom)
+ "Get the ingredients for a recipe from an culturesforhealth DOM."
+ (mapcar 'dom-texts (dom-elements dom 'itemprop "^ingredients$")))
+
+
+(defun org-chef-cultures-for-health-extract-directions (dom)
+ "Get the directions for a recipe from an culturesforhealth DOM."
+ (mapcar #'dom-texts (org-chef-dom-children (cadr (org-chef-dom-children (car (dom-elements dom 'itemprop "^recipeInstructions$")))))))
+
+
+(defun org-chef-cultures-for-health-from-dom (dom)
+ "Given a culturesforhealth.com DOM, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions"
+ `((ingredients . ,(org-chef-cultures-for-health-extract-ingredients dom))
+ (name . ,(org-chef-cultures-for-health-extract-name dom)
+ )
+ (servings . nil)
+ (prep-time . nil)
+ (cook-time . nil)
+ (ready-in . nil)
+ (directions . ,(org-chef-cultures-for-health-extract-directions dom))))
+
+
+(defun org-chef-cultures-for-health-fetch (url)
+ "Given a culturesforhealth.com URL, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions
+- source-url"
+ (with-current-buffer (url-retrieve-synchronously url)
+ (let ((dom (libxml-parse-html-region (point-min) (point-max))))
+ (cons `(source-url . ,url) (org-chef-cultures-for-health-from-dom dom)))))
+
+
+(provide 'org-chef-cultures-for-health)
+;;; org-chef-cultures-for-health.el ends here
--- /dev/null
+;;; org-chef-genius-kitchen.el --- Functions for fetching recipes from geniuskitchen.com. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; Functions for fetching information from geniuskitchen.com.
+
+;;; Code:
+
+
+(require 'org-chef-utils)
+(require 'dom)
+
+
+(defun org-chef-genius-kitchen-extract-name (dom)
+ "Get the name of a recipe from an geniuskitchen DOM."
+ (dom-text (caddr
+ (seq-filter (lambda (x) (not (stringp x)))
+ (dom-children (car (dom-by-class dom "^recipe-header")))))))
+
+
+(defun org-chef-genius-kitchen-extract-ingredients (dom)
+ "Get the ingredients for a recipe from an geniuskitchen DOM."
+ (mapcar #'dom-texts (dom-elements dom 'data-ingredient ".*")))
+
+
+(defun org-chef-genius-kitchen-extract-servings (dom)
+ "Get the number of servings for a recipe from an geniuskitchen DOM."
+ (dom-text (car (dom-by-class (car (dom-by-class dom "^servings$")) "count"))))
+
+
+(defun org-chef-genius-kitchen-extract-ready-in (dom)
+ "Get the total amount of time for a recipe from an geniuskitchen DOM."
+ (string-trim (dom-text (car (dom-by-class dom "time")))))
+
+
+(defun org-chef-genius-kitchen-extract-directions (dom)
+ "Get the directions for a recipe from an geniuskitchen DOM."
+ (let ((directions-list (dom-by-tag (car (dom-by-class dom "directions-inner")) 'li)))
+ (org-chef-remove-empty-strings
+ (mapcar #'(lambda (n) (string-trim (dom-text n))) directions-list))))
+
+
+(defun org-chef-genius-kitchen-fetch (url)
+ "Given a geniuskitchen.com URL, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions
+- source-url"
+ (with-current-buffer (url-retrieve-synchronously url)
+ (let ((dom (libxml-parse-html-region (point-min) (point-max))))
+ `((name . ,(org-chef-genius-kitchen-extract-name dom))
+ (ingredients . ,(org-chef-genius-kitchen-extract-ingredients dom))
+ (servings . ,(org-chef-genius-kitchen-extract-servings dom))
+ (prep-time . nil)
+ (cook-time . nil)
+ (ready-in . ,(org-chef-genius-kitchen-extract-ready-in dom))
+ (directions . ,(org-chef-genius-kitchen-extract-directions dom))
+ (source-url . ,url)))))
+
+
+(provide 'org-chef-genius-kitchen)
+;;; org-chef-genius-kitchen.el ends here
--- /dev/null
+;;; org-chef-martha-stewart.el --- org-chef marthastewart fetching. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; Functions for fetching information from marthastewart.com.
+
+;;; Code:
+
+
+(require 'org-chef-utils)
+(require 'dom)
+
+
+(defun org-chef-martha-stewart-extract-name (dom)
+ "Get the name of a recipe from an marthastewart DOM."
+ (string-trim (dom-text (car (dom-by-class dom "^page-title$")))))
+
+
+(defun org-chef-martha-stewart-extract-ingredients (dom)
+ "Get the ingredients for a recipe from an marthastewart DOM."
+ (mapcar #'(lambda (n) (string-trim (dom-text n)))
+ (dom-by-class dom "^component-text$")))
+
+
+(defun org-chef-martha-stewart-extract-servings (dom)
+ "Get the number of servings for a recipe from an marthastewart DOM."
+ (string-trim (dom-text (car (dom-by-class dom "servings-data$")))))
+
+
+(defun org-chef-martha-stewart-extract-prep-time (dom)
+ "Get the amount of prep-time for a recipe from an marthastewart DOM."
+ (string-trim (dom-text (car (dom-by-class dom "prep-time-data$")))))
+
+
+(defun org-chef-martha-stewart-extract-cook-time (dom)
+ "Get the amount of cook-time for a recipe from an marthastewart DOM."
+ nil)
+
+
+(defun org-chef-martha-stewart-extract-ready-in (dom)
+ "Get the total amount of time for a recipe from an marthastewart DOM."
+ (string-trim (dom-text (car (dom-by-class dom "total-time-data$")))))
+
+
+(defun org-chef-martha-stewart-extract-directions (dom)
+ "Get the directions for a recipe from an marthastewart DOM."
+ (mapcar #'(lambda (n) (string-trim (dom-texts (dom-children n))))
+ (dom-by-class dom "^directions-item-text$")))
+
+
+(defun org-chef-martha-stewart-fetch (url)
+ "Given an marthastewart.com URL, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions
+- source-url"
+ (with-current-buffer (url-retrieve-synchronously url)
+ (let ((dom (libxml-parse-html-region (point-min) (point-max))))
+
+ `((name . ,(org-chef-martha-stewart-extract-name dom))
+ (ingredients . ,(org-chef-martha-stewart-extract-ingredients dom))
+ (servings . ,(org-chef-martha-stewart-extract-servings dom))
+ (prep-time . ,(org-chef-martha-stewart-extract-prep-time dom))
+ (cook-time . ,(org-chef-martha-stewart-extract-cook-time dom))
+ (ready-in . ,(org-chef-martha-stewart-extract-ready-in dom))
+ (directions . ,(org-chef-martha-stewart-extract-directions dom))
+ (source-url . ,url)))))
+
+
+(provide 'org-chef-martha-stewart)
+;;; org-chef-martha-stewart.el ends here
--- /dev/null
+(define-package "org-chef" "20180304.1104" "Cookbook and recipe management with org-mode."
+ '((org "0")
+ (emacs "24"))
+ :url "https://github.com/Chobbes/org-chef" :keywords
+ '("convenience" "abbrev" "outlines" "org" "food" "recipes" "cooking"))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; org-chef-serious-eats.el --- org-chef seriouseats fetching. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; Functions for fetching information from seriouseats.com.
+
+;;; Code:
+
+
+(require 'org-chef-utils)
+(require 'dom)
+
+
+(defun org-chef-serious-eats-extract-name (dom)
+ "Get the name of a recipe from an seriouseats DOM."
+ (dom-text (car (dom-elements dom 'itemprop "^name$"))))
+
+
+(defun org-chef-serious-eats-extract-ingredients (dom)
+ "Get the ingredients for a recipe from an seriouseats DOM."
+ (mapcar 'dom-texts (dom-elements dom 'itemprop "^ingredients$")))
+
+
+(defun org-chef-serious-eats-extract-servings (dom)
+ "Get the number of servings for a recipe from an seriouseats DOM."
+ (dom-text (car (dom-elements dom 'itemprop "^recipeYield$"))))
+
+
+(defun org-chef-serious-eats-extract-prep-time (dom)
+ "Get the amount of prep-time for a recipe from an seriouseats DOM."
+ (dom-text (car (dom-by-class
+ (cadr
+ (org-chef-dom-children
+ (car (dom-by-class dom "^recipe-about$"))))
+ "info"))))
+
+
+(defun org-chef-serious-eats-extract-cook-time (dom)
+ "Get the amount of cook-time for a recipe from an seriouseats DOM."
+ nil)
+
+
+(defun org-chef-serious-eats-extract-ready-in (dom)
+ "Get the total amount of time for a recipe from an seriouseats DOM."
+ (dom-text (car (dom-by-class
+ (caddr
+ (org-chef-dom-children
+ (car (dom-by-class dom "^recipe-about$"))))
+ "info"))))
+
+
+(defun org-chef-serious-eats-extract-directions (dom)
+ "Get the directions for a recipe from an seriouseats DOM."
+ (mapcar #'(lambda (n) (string-trim (dom-texts (dom-children n))))
+ (dom-by-class dom "^recipe-procedure-text$")))
+
+
+(defun org-chef-serious-eats-fetch (url)
+ "Given an seriouseats.com URL, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions
+- source-url"
+ (with-current-buffer (url-retrieve-synchronously url)
+ (let ((dom (libxml-parse-html-region (point-min) (point-max))))
+
+ `((name . ,(org-chef-serious-eats-extract-name dom))
+ (ingredients . ,(org-chef-serious-eats-extract-ingredients dom))
+ (servings . ,(org-chef-serious-eats-extract-servings dom))
+ (prep-time . ,(org-chef-serious-eats-extract-prep-time dom))
+ (cook-time . ,(org-chef-serious-eats-extract-cook-time dom))
+ (ready-in . ,(org-chef-serious-eats-extract-ready-in dom))
+ (directions . ,(org-chef-serious-eats-extract-directions dom))
+ (source-url . ,url)))))
+
+
+(provide 'org-chef-serious-eats)
+;;; org-chef-serious-eats.el ends here
--- /dev/null
+;;; org-chef-simply-recipes.el --- Functions for fetching recipes from simplyrecipes.com. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; Functions for fetching information from simplyrecipes.com.
+
+;;; Code:
+
+
+(require 'org-chef-utils)
+(require 'dom)
+
+
+(defun org-chef-simply-recipes-extract-name (dom)
+ "Get the name of a recipe from an simplyrecipes DOM."
+ (dom-text (car (dom-by-class dom "entry-title"))))
+
+
+(defun org-chef-simply-recipes-extract-ingredients (dom)
+ "Get the ingredients for a recipe from an simplyrecipes DOM."
+ (mapcar 'dom-text (dom-by-class dom "^ingredient$")))
+
+
+(defun org-chef-simply-recipes-extract-servings (dom)
+ "Get the number of servings for a recipe from an simplyrecipes DOM."
+ (let ((servings (dom-text (car (dom-by-class dom "^yield*")))))
+ (when servings
+ (substring servings 7))))
+
+
+(defun org-chef-simply-recipes-extract-prep-time (dom)
+ "Get the amount of prep-time for a recipe from an simplyrecipes DOM."
+ (dom-text (car (dom-by-class dom "preptime"))))
+
+
+(defun org-chef-simply-recipes-extract-cook-time (dom)
+ "Get the amount of cook-time for a recipe from an simplyrecipes DOM."
+ (let ((cook-time (dom-by-class dom "cooktime"))
+ (other-time (dom-by-class dom "othertime")))
+ (dom-text (car (if (null cook-time) other-time cook-time)))))
+
+
+(defun org-chef-simply-recipes-extract-directions (dom)
+ "Get the directions for a recipe from an simplyrecipes DOM."
+ (mapcar #'dom-text (seq-filter (lambda (x) (not (stringp x)))
+ (dom-children (car (dom-elements dom 'itemprop "^recipeInstructions$"))))))
+
+
+(defun org-chef-simply-recipes-from-dom (dom)
+ "Given a simplyrecipes.com DOM, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions"
+ (let* ((prep-time (org-chef-simply-recipes-extract-prep-time dom))
+ (cook-time (org-chef-simply-recipes-extract-cook-time dom)))
+
+ `((ingredients . ,(org-chef-simply-recipes-extract-ingredients dom))
+ (name . ,(org-chef-simply-recipes-extract-name dom)
+ )
+ (servings . ,(org-chef-simply-recipes-extract-servings dom))
+ (prep-time . ,prep-time)
+ (cook-time . ,cook-time)
+ (ready-in . nil)
+ (directions . ,(org-chef-simply-recipes-extract-directions dom)))))
+
+
+(defun org-chef-simply-recipes-fetch (url)
+ "Given a simplyrecipes.com URL, retrieve the recipe information.
+
+This returns an alist with the following keys:
+
+- name
+- ingredients
+- servings
+- prep-time
+- cook-time
+- ready-in
+- directions
+- source-url"
+ (with-current-buffer (url-retrieve-synchronously url)
+ (let ((dom (libxml-parse-html-region (point-min) (point-max))))
+ (cons `(source-url . ,url) (org-chef-simply-recipes-from-dom dom)))))
+
+
+(provide 'org-chef-simply-recipes)
+;;; org-chef-simply-recipes.el ends here
--- /dev/null
+;;; org-chef-utils.el --- Utilities for org-chef. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; Utilitiy functions for org-chef.
+
+;;; Code:
+
+(require 'cl-macs)
+
+(defun org-chef-remove-empty-strings (lst)
+ "Filter out any empty strings in a list of strings (LST)."
+ (seq-filter (lambda (x) (/= (length x) 0)) lst))
+
+
+(defun org-chef-dom-children (dom)
+ "Get the child nodes of the DOM, remove strings."
+ (seq-filter (lambda (x) (not (stringp x)))
+ (dom-children dom)))
+
+
+(defun org-chef-insert-org-list (lst &optional bullet)
+ "Insert LST as an ‘org-mode’ plain list.
+
+The optional argument BULLET specifies which type of bullet point
+should be used."
+ (mapcar (lambda (x) (progn (insert (format "%s" x))
+ (org-cycle)
+ (org-ctrl-c-minus)
+ (if bullet (org-cycle-list-bullet bullet))
+ (org-return)))
+ lst))
+
+
+(provide 'org-chef-utils)
+;;; org-chef-utils.el ends here
--- /dev/null
+;;; org-chef.el --- Cookbook and recipe management with org-mode. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Calvin Beck
+
+;; Author: Calvin Beck <hobbesNOSPAMualberta.ca>
+;; URL: https://github.com/Chobbes/org-chef
+;; Created: 2018
+;; Version: 0.1.3
+;; Keywords: convenience, abbrev, outlines, org, food, recipes, cooking
+;; Package-Requires: ((org "0") (emacs "24"))
+
+;; Copyright 2018 Calvin Beck
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; org-chef is a package for managing recipes in org-mode. One of the
+;; main features is that it can automatically extract recipes from
+;; websites like allrecipes.com
+
+;;; Code:
+
+
+(require 'org-chef-utils)
+(require 'org-chef-all-recipes)
+(require 'org-chef-genius-kitchen)
+(require 'org-chef-simply-recipes)
+(require 'org-chef-martha-stewart)
+(require 'org-chef-budget-bytes)
+(require 'org-chef-cultures-for-health)
+(require 'org-chef-serious-eats)
+
+
+(defun org-chef-recipe-insert-org (recipe)
+ "Insert a RECIPE as an ‘org-mode’ heading."
+ (org-insert-heading)
+ (insert (cdr (assoc 'name recipe)))
+ (org-return)
+ (org-set-property "source-url" (cdr (assoc 'source-url recipe)))
+ (org-set-property "servings" (cdr (assoc 'servings recipe)))
+ (org-set-property "prep-time" (format "%s" (cdr (assoc 'prep-time recipe))))
+ (org-set-property "cook-time" (format "%s" (cdr (assoc 'cook-time recipe))))
+ (org-set-property "ready-in" (format "%s" (cdr (assoc 'ready-in recipe))))
+ (org-insert-subheading t)
+ (insert "Ingredients")
+ (org-return)
+ (org-return)
+ (org-chef-insert-org-list (cdr (assoc 'ingredients recipe)))
+ (org-return)
+ (org-return)
+ (org-insert-heading)
+ (insert "Directions")
+ (org-return)
+ (org-return)
+ (org-chef-insert-org-list (cdr (assoc 'directions recipe)) "1."))
+
+
+(defun org-chef-recipe-org-string (recipe)
+ "Get an ‘org-mode’ heading string for a RECIPE."
+ (with-temp-buffer (org-mode)
+ (org-chef-recipe-insert-org recipe)
+ (buffer-string)))
+
+(defun org-chef-match-url (BASE URL)
+ "Match URL against a BASE url."
+ (not (null (string-match-p (regexp-quote BASE) URL))))
+
+
+(defun org-chef-fetch-recipe (URL)
+ "Look up a recipe at a URL."
+ (cond
+ ((org-chef-match-url "allrecipes.com" URL) (org-chef-all-recipes-fetch URL))
+ ((org-chef-match-url "geniuskitchen.com" URL) (org-chef-genius-kitchen-fetch URL))
+ ((org-chef-match-url "simplyrecipes.com" URL) (org-chef-simply-recipes-fetch URL))
+ ((org-chef-match-url "marthastewart.com" URL) (org-chef-martha-stewart-fetch URL))
+ ((org-chef-match-url "budgetbytes.com" URL) (org-chef-budget-bytes-fetch URL))
+ ((org-chef-match-url "culturesforhealth.com" URL) (org-chef-cultures-for-health-fetch URL))
+ ((org-chef-match-url "seriouseats.com" URL) (org-chef-serious-eats-fetch URL))))
+
+
+(defun org-chef-insert-recipe ()
+ "Prompt for a recipe URL, and then insert the recipe at point."
+ (interactive)
+ (let ((URL (read-string "Recipe URL: ")))
+ (org-chef-recipe-insert-org (org-chef-fetch-recipe (read-string "Recipe URL: ")))))
+
+
+(defun org-chef-get-recipe-from-url ()
+ "Prompt for a recipe URL, and return the ‘org-mode’ string."
+ (let ((URL (read-string "Recipe URL: ")))
+ (org-chef-recipe-org-string (org-chef-fetch-recipe URL))))
+
+
+(provide 'org-chef)
+;;; org-chef.el ends here
--- /dev/null
+org-chef is a package for managing recipes in org-mode. One of the
+main features is that it can automatically extract recipes from
+websites like allrecipes.com