Class: Abqari::Folio

Inherits:
Object
  • Object
show all
Defined in:
lib/abqari/folio.rb

Overview

Folio integration. Folio (foliobooks.app) is a publishing/storefront app that exposes a public read-only JSON API for embedding book metadata on author websites. This class fetches that data at build time and stashes it in site.data keyed by slug, so layouts can render books / bundles / series without hitting Folio at runtime — and the visitor never makes a request to Folio either.

API endpoints used:

GET /api/v1/authors/:slug/publications.json
GET /api/v1/authors/:slug/bundles.json
GET /api/v1/authors/:slug/series.json

Cache-first design (matches the Jekyll plugin in apps/memoirs):

1. Fresh build, network OK     → 200 → write cache → use it
2. Subsequent build, no change → 304 → use cache
3. Folio briefly unreachable   → use cache, log warning
4. First build, no network     → empty data; layouts fall back to front matter

Cache files live in vendor/folio/ (gitignored) so each CI runner rebuilds its own cache and there's no version-control churn.

Constant Summary collapse

OPEN_TIMEOUT =
5
READ_TIMEOUT =
10
MAX_RESPONSE_BYTES =

8 MB is enormously generous for Folio's JSON shape — a prolific author with hundreds of titles plus full metadata still fits well under 1 MB. The cap exists so a compromised or misconfigured upstream can't exhaust the CI runner's memory.

8 * 1024 * 1024
USER_AGENT =
"abqari-folio-fetcher/#{Abqari::VERSION}"

Instance Method Summary collapse

Constructor Details

#initialize(site) ⇒ Folio

Returns a new instance of Folio.



41
42
43
44
# File 'lib/abqari/folio.rb', line 41

def initialize(site)
  @site = site
  @cfg  = site.config['folio'] || {}
end

Instance Method Details

#author_slugObject



54
55
56
# File 'lib/abqari/folio.rb', line 54

def author_slug
  @cfg['author_slug']
end

#base_urlObject



50
51
52
# File 'lib/abqari/folio.rb', line 50

def base_url
  @cfg['base_url']
end

#cache_dirObject



62
63
64
65
66
# File 'lib/abqari/folio.rb', line 62

def cache_dir
  # Folio cache is site-specific (different sites pull different
  # publications), so it lives under the site root.
  File.join(@site.site_root, 'vendor', 'folio')
end

#configObject



58
59
60
# File 'lib/abqari/folio.rb', line 58

def config
  @cfg
end

#enabled?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/abqari/folio.rb', line 46

def enabled?
  base_url && author_slug
end

#fetchObject

Fetches publications + bundles, derives series, populates site.data. Called from Site#build before page rendering so layouts can read site.data etc. when they render.

Slug filtering. An author may have multiple imprints under one Folio account (e.g. fiction + non-fiction) but want a given site to show only some. Configure either of:

folio:
include_slugs: [memoirs-of-an-assassin, the-russia-assignment]
exclude_slugs: [some-other-book]

include_slugs (when set) wins — only those publications survive, and only the bundles/series that reference them are kept. Otherwise exclude_slugs removes the listed publications. Both default to empty (all publications kept) so existing sites are unaffected.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/abqari/folio.rb', line 84

def fetch
  return unless enabled?

  FileUtils.mkdir_p(cache_dir)

  pubs    = filter_publications(fetch_endpoint('publications'))
  bundles = filter_bundles(fetch_endpoint('bundles'), pubs)
  series  = filter_series(fetch_endpoint('series'), pubs)

  @site.data['folio_publications'] = index_by_slug(pubs)
  @site.data['folio_bundles']      = index_by_slug(bundles)
  @site.data['folio_series']       = index_by_slug(series)

  pubs_count    = @site.data['folio_publications'].size
  bundles_count = @site.data['folio_bundles'].size
  series_count  = @site.data['folio_series'].size
  Log.info "Folio: loaded #{pubs_count} publication(s), #{bundles_count} bundle(s), #{series_count} series"
end