Configuration
earmark.toml lives inside the library and marks the folder it sits in as one. earmark config opens it in $EDITOR; earmark config --show prints every value in effect and where it came from.
Every setting is a default. A command-line flag always wins.
There is no library key and there never will be: the library is the folder this file sits in.
Top-level settings
| Key | Type | Default | Accepts | Read by |
|---|---|---|---|---|
voice |
string | "af_heart" |
any name from earmark voices |
audio, publish |
speed |
number | 1.0 |
0.5 to 2.0 |
audio, publish |
lang |
string | "en-us" |
a language code | audio, publish |
profile |
string | "article" |
article, paper, book |
text, audio, publish |
model |
string | "full" |
full, fp16, int8 |
audio, publish |
engine |
string | "kokoro" |
kokoro, say |
audio, publish, voices |
bitrate |
string | "64k" |
any ffmpeg bitrate | audio, publish |
sample_rate |
integer | 44100 |
a positive whole number | audio, publish |
after_publish |
string | none | a shell command | publish |
voice = "af_bella"
speed = 1.1
profile = "paper"after_publish
One line of shell, run inside the library once the feed is written. Only needed if your library is not already a folder that syncs to the web.
after_publish = "git add -A && git commit -m 'earmark' && git push"It is a config key rather than a plugin system on purpose: it covers every host without earmark knowing the name of one. Recipes: Host a library.
[feed]
| Key | Type | Default | Means |
|---|---|---|---|
base_url |
string | none | the public URL the library folder is served at |
title |
string | "earmark" |
podcast title |
author |
string | none | podcast author |
description |
string | none | show description |
link |
string | none | a website for the show |
language |
string | none | RSS language code, e.g. en-us |
category |
string | none | iTunes category |
cover |
string | none | a file in this folder; earmark normalizes it |
image |
string | none | a URL to artwork hosted elsewhere; passed through |
[feed]
base_url = "https://filedn.com/XXXX/earmark"
title = "John's Reading Pile"
author = "John Helveston"
description = "Things I meant to read."
cover = "cover.jpg"base_url must start with http:// or https://. Publishing without it stops with a message telling you to run earmark config.
cover and image are not interchangeable: image disables the cover pipeline rather than racing it.
[replace]
Fix a mispronunciation once instead of every time. Matched on word boundaries, longest key first.
[replace]
BEV = "battery electric vehicle"
NIMBY = "nimby"Keep [feed] last
TOML puts a key you add at the bottom of a file into whichever table came before it. An unknown key under [feed] warns loudly; an extra entry under [replace] would look exactly like a word you wanted respoken, and would be silently accepted.
So [feed] is the last table in the file the template writes, and it is worth keeping it there.
Warnings and errors
Loading a config never fails, because a broken file must stay inspectable with earmark config --show. Problems are sorted into two kinds.
Warnings print to stderr and the offending key is ignored:
| Warning | Cause |
|---|---|
unknown section [x] ignored |
a table that is not [feed] or [replace] |
unknown setting 'k' ignored |
a top-level key not in the table above |
unknown setting 'feed.k' ignored |
a key not in the [feed] table above |
[replace] must be a table of strings; ignored |
[replace] is not a table |
Errors stop the command that was about to use the settings, reported as earmark: config problem in <path>: with one line per problem:
| Error | Cause |
|---|---|
speed = … is not a number |
non-numeric speed |
speed = … is not between 0.5 and 2.0 |
out of range |
profile = … is not one of article, paper, book |
unknown profile |
model = … is not one of full, fp16, int8 |
unknown model |
engine = … is not one of kokoro, say |
unknown engine |
voice / lang / bitrate = … is not a non-empty string |
wrong type or empty |
sample_rate = … is not a positive whole number |
wrong type or < 1 |
after_publish = … is not a shell command string |
wrong type |
feed.base_url is not a URL string |
wrong type |
feed.base_url = … must start with http:// or https:// |
wrong scheme |
not valid TOML: … |
the file does not parse |
The file init writes
# earmark configuration
#
# This file marks the folder it lives in as an earmark library. Everything
# earmark makes -- markdown in text/, MP3s, feed.xml -- lands beside it.
#
# Every setting here is a default for every new episode. A setting on one
# entry in sources.yml, or a command-line flag, wins over it.
# The voice for every episode. Hear them all on the Settings page:
# https://earmark-dev.github.io/earmark/settings/
voice = "af_heart"
speed = 1.0 # 0.5 to 2.0
lang = "en-us" # en-gb for a British voice (one that starts with b)
# profile = "article" # article | paper | book
# model = "full" # full | fp16 | int8
# engine = "kokoro" # kokoro | say
# bitrate = "64k"
# sample_rate = 44100
# Run this after every publish, from inside the library. Only needed if your
# library is not already a folder that syncs to the web -- a git push, say.
# after_publish = "git add -A && git commit -m 'earmark' && git push"
# Fix a mispronunciation once instead of every time. Matched on word
# boundaries, longest key first.
[replace]
# BEV = "battery electric vehicle"
# [feed] is last on purpose. TOML puts a key you add at the bottom of the file
# into whichever table came before it, and an unknown key here warns, while an
# extra entry under [replace] would look like a word you wanted respoken.
[feed]
base_url = ""
title = "earmark"
# author = "Your Name"
# description = "Things I meant to read."
# cover = "cover.jpg" # a file in this folder; square PNG or JPEG
# image = "https://..." # or artwork already hosted somewhere; this winssources.yml
The library’s reading list, written by earmark init beside earmark.toml and read by earmark publish when it is given no SOURCE. It is a YAML list. Each entry is one of:
- https://example.com/some-article # a URL
- files/a-paper.pdf # a file, relative to the library
- source: https://example.com/long-read # a mapping, for overrides
title: A better title
voice: bf_emma
profile: paperA mapping takes source plus any of title, author, date, voice, speed, lang and profile, which mean what the flags of the same name mean. An entry’s settings beat the config; the config beats the defaults.
| Problem | Treated as |
|---|---|
| an unknown key in an entry | a warning; the key is ignored |
the same source twice |
an error |
| a file entry that does not exist | an error |
an entry with no source |
an error |
| the file is not valid YAML, or is not a list | an error |
Any error stops the sync before it changes anything, because syncing to a list read only in part would remove the episodes of the entries it could not read. A file of nothing but comments is an empty list, not an error.
What is not in the library
Three things are deliberately stored outside it, because they must not sync to a public folder:
- the 354 MB Kokoro model
- the per-chunk synthesis cache
- a one-line pointer naming your default library
earmark config --show prints where each of them actually is.