Skip to content

An opinionated library for stream-parsing Mela's recipe files.

License

Notifications You must be signed in to change notification settings

jphastings/mela-recipes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mela recipes

An opinionated library for stream-parsing Mela's recipe files.

Includes customisations that define a convention for the ID of recipes derived from books. See ISBN extension for examples.

Usage

As a CLI tool

The pre-compiled binaries are available on Github. You can also install rapidly with Homebrew on Linux and macOS:

brew install jphastings/tools/mela-standardize

Then standardizing a mela recipe file is as simple as:

$ mela-standardize recipe1.melarecipe lots.melarecipes /output/path
Saved 'Some recipe' to '/output/path/some-book/some-recipe.melarecipe'
Saved 'A title' to '/output/path/example.com/a-title.melarecipe'

As a library

Go Reference

// import github.com/jphastings/mela-recipes

The simple Open function is quickest for interacting with .melarecipe and .melarecipes files:

recipes, err := mela.Open("fixtures/a+b.melarecipes")
if err != nil {
  log.Fatalf("A filesystem error: %v\n", err)
}

for i, r := range recipes {
  fmt.Printf("Recipe #%d title: %s\n", i, r.Title)
}

// Output:
// Recipe #0 title: B title
// Recipe #1 title: A title

Note: the order of the recipes is defined on the structure of the underlying zip file, which isn't necessarily alphabetical, or the sort order of the recipes when exported.

ISBNs can be set & parsed with the SetBook and Book methods:

recipes, err := mela.Open("fixtures/a.melarecipe")
if err != nil {
  log.Fatalf("A filesystem error: %v\n", err)
}

r := recipes[0]

// Note: Setting the book details creates a new object with a URN based on a standardised form ISBN-13.
setErr := r.SetBook("123456789X", mela.MustParsePages("42"), 2)
if setErr != nil {
  log.Fatalf("Invalid Book details given: %v\n", err)
}

fmt.Println("ID:", r.ID)
fmt.Println("ISBN:", r.Book().ISBN13)
fmt.Println("Page numbers:", r.Book().Pages)
fmt.Println("Recipe number:", r.Book().RecipeNumber)


// Output:
// ID: urn:isbn:9781234567897#pages=42&recipe=2
// ISBN: 9781234567897
// Page numbers: 42
// Recipe number: 2

You can standardize the Recipe file with a call to Standardize(). This performs three standardizations:

  • Pulls an ISBN, page & recipe numbers from the Notes field, if present in forms similar to _9781234512345, p.123-125, 2nd_. This would represent the book with ISBN 9781234512345, on pages 123 to 125, starting as the 2nd recipe on that first page (see ISBN Extension for more). Changes the recipe's ID to reference this book.
  • Converts any images to be maximum 512x512px, and in (jpegli encoded) JPEG format.
  • (If network access is enabled, and for books with an ISBN) retrieves the book title from the OpenLibrary and sets the 'link' field of the recipe to be the title of the book.

Extensions

This library includes backwards-compatible extensions to the Mela file format.

ISBN Extension

For recipes that have been scanned or imported from books, the id field of the recipe can be set to an ISBN URN with optional page and recipe-number-on-page references. This is invisible to users of .melarecipe/.melarecipes files, but provides useful information for cataloguing.

For example, the second recipe on page 42 of the book with ISBN-13 9781234567897 (which would be ISBN-10 123456789X) would have an ID of urn:isbn:9781234567897#pages=42&recipe=1.

Any .melarecipe that has an id which is a URN meeting the RFC-3187 spec will be interpreted as having come from a book.

If that URN includes a valid pages f-component (see RFC-8141§2.3), then the recipe will be interpreted as being imported from from the page or pages labelled with the specific page numbers.

If the URN also includes a valid recipe f-component, then the recipe will be interpreted as coming from the Nth recipe on the first page referenced in pages. 0 represents "not explicitly specified, presumed the first recipe", 1 explicitly declares this recipe as the first one on the page, 2 explicitly as the second and so on. (Neatly resolving the awkward difference between humans and machines on zero-indexing).

Examples

  • The first recipe on a single page: #pages=42 or, explicitly, #pages=42&recipe=1
  • The second recipe on a single page: #pages=42&recipe=2
  • (The first recipe on) a range of contiguous pages: #pages=42-45
  • (The first recipe on) a set of non-contiguous pages: #pages=42,44,46-49
  • (The first recipe on) a set of pages that use non-numeric numbering: #pages=v-vii,x-xii
  • (The first recipe on) a page with a number that uses hyphens: #pages=3%2D2

The pages referenced should be listed in the order they appear in the book. For example, #pages=42-41 and #pages=42,41 would both be incorrect unless the page labelled "41" comes immediately after the page labelled "42" in the direction the book is read).

ABNF notation
pages_f     = contig *( "," contig )
contig      = page-num [ "-" page-num ]
page-num    = 1*( ALPHA / DIGIT / pct-encoded )
pct-encoded = "%" HEXDIG HEXDIG

recipe_f    = 1*DIGIT

(Using RFC5234 syntax.)