Configuration¶
For Japanese-release endpoints, catalog snapshots and split APKs, see Japanese release.
nnnotes has no built-in keys, server addresses or data paths. Every setting comes from one of three sources, and a command that needs a setting nobody gave stops before it does any work.
Sources and precedence¶
Lowest to highest:
- TOML file.
--config <file>; else the file named by the environment variableNNNOTES_CONFIG; elsennnotes.tomlin the working directory, when present; else the per-user file, when present:%APPDATA%\nnnotes\nnnotes.tomlon Windows,$XDG_CONFIG_HOME/nnnotes/nnnotes.tomlelsewhere (~/.configwhenXDG_CONFIG_HOMEis unset). A file named by--configorNNNOTES_CONFIGmust exist.nnnotes config pathlists the files in this order and the one that is read. - Environment variables
NNNOTES_<SECTION>_<KEY>: the setting's dotted name upper-cased, with dots, dashes and other non-alphanumeric characters as underscores (bundle.key→NNNOTES_BUNDLE_KEY,servers.tw.cdn→NNNOTES_SERVERS_TW_CDN,bundle.nonce_seed→NNNOTES_BUNDLE_NONCE_SEED). - Command-line flags, for the settings that have one (table below).
An empty value ("", [], an empty environment variable, an empty flag) counts as unset, so a lower source still
applies. The template nnnotes.example.toml ships with the package and lists
every setting with an empty value; nnnotes config init writes it (below). nnnotes.toml and *.local.toml are in
.gitignore; do not commit a filled-in copy.
Writing the config file¶
nnnotes config init [--user | --file F] [--set SECTION.KEY=VALUE ...] [--no-input] [--force]
nnnotes config set SECTION.KEY VALUE [--user | --file F]
nnnotes config unset SECTION.KEY [--user | --file F]
nnnotes config check [--json]
nnnotes config path [--json]
config initwrites the template to./nnnotes.toml(the file--configorNNNOTES_CONFIGnames, when one does;--user: the per-user file;--file: that file). An existing file is kept unless--force.- In a terminal, with no
--setand no--no-input, it asks for each setting in turn. Enter leaves a setting empty, the four keys are read without echo, and a malformed value is asked again. It asks for the region names first, and writes one[servers.<region>]table per region. - Otherwise it asks nothing: the
--setvalues are written (a list comma-separated, a path made absolute) and the other settings stay empty. A--setvalue-is read from standard input, once. config setsets one value in the file the commands read (--user/--file: that file, made from the template when it does not exist). The other lines and the comments stay as they are; a new region gets the template's region table. VALUE-reads the value from standard input, without echo for the keys in a terminal.config unsetempties one value. Both check the value's format first and name only the setting when it is malformed.config checklists every setting: where it comes from (file,env,flagor-) and its status:ok,unset,invalid(with the reason),not found(a path that does not exist), orunknown(a key of the file or anNNNOTES_variable that names no setting). It exits with status 1 when a setting is invalid, not found or unknown.--jsonprints the report asnnnotes.config-check/1:file,settings(name, environment variable, flag, kind, whether it is a key, description, origin, status, reason) andproblems.config pathlists the config file candidates in lookup order and the one that is read;--jsonprintsnnnotes.config-path/1.
No config command prints a setting's value. The config files these commands write are readable by their owner only
(mode 600 where the file system has modes).
The global flags go before or after the command name:
nnnotes --config ~/nnnotes.toml --cache /data/nnnotes-cache bundle pull <key>
NNNOTES_PATHS_MASTER=/data/master nnnotes export episode 10462 -o episode.json
--player is the exception: it is an option of site build. site build also has --site-region (with
--all-regions), which chooses the regions the site serves; the global --region sets [catalog] region:
nnnotes --region tw site build -o out/site --all # the one region [catalog] region = tw
nnnotes site build -o out/site --all --site-region tw --site-region kr # a site for two regions
Paths¶
Relative paths in the TOML file are relative to the file's directory; relative paths from the environment or the
command line are relative to the working directory. ~ is expanded. [paths] catalog, apk and master must
exist when they are given.
Settings¶
| Setting | Environment variable | Flag | Format |
|---|---|---|---|
[bundle] key |
NNNOTES_BUNDLE_KEY |
— | AES-128 key of the asset bundle encryption: 16 bytes as 32 hex digits |
[bundle] nonce_seed |
NNNOTES_BUNDLE_NONCE_SEED |
— | seed of the per-bundle nonce, hex (any length) |
[master] key |
NNNOTES_MASTER_KEY |
— | Rijndael-256 key of the master data files: 32 bytes as 64 hex digits |
[master] iv |
NNNOTES_MASTER_IV |
— | Rijndael-256 CBC initialization vector: 32 bytes as 64 hex digits |
[catalog] region |
NNNOTES_CATALOG_REGION |
--region |
name of one [servers.<region>] table |
[catalog] language |
NNNOTES_CATALOG_LANGUAGE |
--language |
catalog language: the <language> of catalog_<version>_<language>.bin: ja, en, zh-Hant, zh-Hans or ko; also the client language of export live, export story and site build (the text field, fonts and line spacing of their UI) and of the model labels of site build --live2d |
[catalog] version |
NNNOTES_CATALOG_VERSION |
--catalog-version |
optional international resource version; unset: query the configured region API, or use legacy main when no API is configured; JP uses its own discovery |
[servers.<region>] name |
NNNOTES_SERVERS_<REGION>_NAME |
— | label of the region in catalog browse (default: the region name) |
[servers.<region>] provider |
NNNOTES_SERVERS_<REGION>_PROVIDER |
— | international or jp; empty selects jp for the region named jp, international otherwise |
[servers.<region>] client_version |
NNNOTES_SERVERS_<REGION>_CLIENT_VERSION |
— | per-region API client version; overrides [client] version, then falls back to the region's APK versionName |
[servers.<region>] apk |
NNNOTES_SERVERS_<REGION>_APK |
--apk |
per-region APK, APKS/XAPK or directory with base.apk; adjacent splits of base.apk are read automatically; the flag overrides it |
[servers.<region>] catalog |
NNNOTES_SERVERS_<REGION>_CATALOG |
--catalog |
per-region catalog file; JP needs the matching <file>.source.json; the flag overrides it |
[servers.<region>] catalog_version |
NNNOTES_SERVERS_<REGION>_CATALOG_VERSION |
--catalog-version |
per-region international version pin; overrides [catalog] version, but not the command-line flag |
[servers.<region>] cdn |
NNNOTES_SERVERS_<REGION>_CDN |
— | CDN base URL of the region (a trailing / is ignored) |
[servers.<region>] languages |
NNNOTES_SERVERS_<REGION>_LANGUAGES |
— | catalog languages catalog browse lists: a TOML array of strings; comma-separated in the environment |
[servers.<region>] api |
NNNOTES_SERVERS_<REGION>_API |
— | API root of the region: https://host[:port] (TLS, port 443 by default), host[:port], or http://host[:port] for a plain-text local server; no path |
[servers.<region>] master |
NNNOTES_SERVERS_<REGION>_MASTER |
— | decoded master data directory of the region (default: [paths] master) |
[bootstrap] api |
NNNOTES_BOOTSTRAP_API |
— | API root that serves the server list (nnnotes servers), same format |
[client] version |
NNNOTES_CLIENT_VERSION |
— | client version sent to the game's API, e.g. 1.0.1; unset: the versionName of [paths] apk |
[paths] catalog |
NNNOTES_PATHS_CATALOG |
--catalog |
a catalog .bin file to read instead of discovering/downloading a catalog; explicit files stay usable offline |
[paths] cache |
NNNOTES_PATHS_CACHE |
--cache |
cache directory (created when missing) |
[paths] store |
NNNOTES_PATHS_STORE |
--store |
store directory of the asset export (assets.md); unset: <[paths] cache>/store |
[paths] master |
NNNOTES_PATHS_MASTER |
--master |
decoded master data directory, one <Table>.json per table; the flag overrides [servers.<region>] master |
[paths] apk |
NNNOTES_PATHS_APK |
--apk |
the game's base.apk (the story export reads the CRI Lips library from it, or from split_config.arm64_v8a.apk next to it) |
[paths] ffmpeg |
NNNOTES_PATHS_FFMPEG |
--ffmpeg |
ffmpeg executable; unset: ffmpeg on PATH |
[paths] vgmstream |
NNNOTES_PATHS_VGMSTREAM |
--vgmstream |
vgmstream-cli executable; unset: vgmstream-cli on PATH |
[paths] node |
NNNOTES_PATHS_NODE |
--node |
Node.js executable; unset: node on PATH |
[paths] player |
NNNOTES_PATHS_PLAYER |
--player (of site build) |
ournotes-player checkout (built) or installed package |
[paths] fonts.<language> |
NNNOTES_PATHS_FONTS_<LANGUAGE> (e.g. NNNOTES_PATHS_FONTS_ZH_HANT) |
--font <language>=PATH (of site build) |
font file (OpenType or TrueType) the story text of a language is drawn with (--fonts open); also read for the other story languages whose game fonts fall back to that language's font |
[paths] fonts.emoji |
NNNOTES_PATHS_FONTS_EMOJI |
--font emoji=PATH (of site build) |
colour emoji font (PNG bitmap glyphs: CBDT or sbix) the stories' emoji sprites are drawn from (--fonts open); Noto Color Emoji (SIL Open Font License 1.1) is the tested font. Optional: without it the sprites keep their layout with empty glyphs, listed in ui/fonts.json coverage.sprites.missing |
[export] link |
NNNOTES_EXPORT_LINK |
--link (of export assets) |
how export assets makes the layout files from the store: auto (unset), clone, hard or copy (assets.md) |
Hex values are case-insensitive; a 0x prefix and surrounding whitespace are ignored. All values are TOML strings
except languages (array of strings).
Regions: catalog browse serves every region that has a [servers.<region>] table or an NNNOTES_SERVERS_<REGION>_CDN
variable (the region name is then the lower-cased <REGION>), and site build --site-region / --all-regions builds one site
for several of them. The other commands use the one region named by [catalog] region. Add one [servers.<name>]
table per region.
Master data per region: a command that reads master data for region <r> takes the directory of the --master flag,
else [servers.<r>] master, else [paths] master. International catalog selection uses resource_version, not
the master version or a change to the CDN root. catalog_main is a separate catalog that may remain old.
When the region has an API root, catalog-based commands query Version before selecting a download; discovery
failure stops rather than treating main as current. Without an API or version pin, the old main/offline behavior
is retained. JP's version/hash directory and authentication remain unchanged.
For repeatable builds, pin the resource version belonging to your master snapshot:
nnnotes --region tw --catalog-version 1.0.0.201 site build -o site --story 10948
nnnotes --region tw --catalog-version 1.0.0.201 export live2d MODEL_ID -o out/model
Alternatively set NNNOTES_SERVERS_TW_CATALOG_VERSION in the build environment; workers inherit this pin.
--catalog-version selects a remote resource release; --stored-catalog LABEL|SHA of export assets and store
plan selects a catalog version of the store. To inspect the historical main catalog, explicitly pin main.
Versioned caches are isolated by CDN root and resource version; a cached pin needs the CDN setting to identify
its directory but performs no API/catalog download. A missing versioned file never falls back to main.
What each command needs¶
"Catalog" below means: [paths] cache; either [paths] catalog or [catalog] language (the catalog is then
downloaded into the cache on first use); and, for what must be downloaded, [catalog] region and that region's
cdn, [bundle] key and nonce_seed. [paths] apk is optional for the catalog: when it is set, the APK's own catalog and bundles are merged
in, and bundles that ship inside the APK can only be read with it.
"Master data" means the decoded master data directory of the region: the --master flag, else
[servers.<region>] master of [catalog] region, else [paths] master.
--fonts game (export story, export live, site build) also needs the optional fonts dependencies (pip install 'nnnotes[fonts]'),
and so does site build --story / --all-stories with either font source (it generates the TextMesh Pro font assets of the
story text); it is not a setting.
| Command | Settings |
|---|---|
catalog keys |
[paths] cache; [paths] catalog, or [catalog] language (plus region and cdn while the catalog is not in the cache); no bundle key |
catalog browse |
[paths] cache, [bundle] key + nonce_seed, and per region cdn + languages (name optional) |
bundle pull |
catalog |
master decode |
[master] key + iv |
master download |
[catalog] region and that region's cdn; --latest also that region's api and the client version |
master version |
[catalog] region and that region's api; the client version: [client] version or [paths] apk |
servers |
[bootstrap] api; the client version: [client] version or [paths] apk |
export episode |
catalog, master data |
export story |
catalog, [catalog] language, master data, [paths] apk, ffmpeg (audio and videos), vgmstream (not with --no-audio) |
export live2d |
catalog, [paths] apk |
export spot |
catalog, master data, [paths] apk |
export room |
catalog |
export shader |
catalog; --apk-bundle also [paths] apk |
export audio |
catalog, [paths] apk, vgmstream, ffmpeg (not for --format wav) |
apk hca-key |
[paths] apk |
apk settings |
[paths] apk |
export live |
catalog, [catalog] language, master data, [paths] apk, vgmstream, ffmpeg |
site build --pair / --all |
as export live, plus [paths] player, node; with --site-region / --all-regions each region's [servers.<region>] table (its cdn for what must be downloaded) and master data ([servers.<region>] master; [paths] master for at most one region) |
site build --live2d / --all-live2d |
catalog (bundles from the CDN of the site's first region), [paths] apk, [paths] player; not node; master data only for the model names (optional: without it models.json has no names) |
site build --player-only / --reingest-json |
[paths] player |
music-data |
catalog, [master] key + iv (not with --decoded-master); --master-files also [catalog] region; --apk-master also [paths] apk; --decoded-master also [catalog] region and master data with its MasterManifest.json; [paths] apk (optional otherwise) for the client version |
export assets, store plan |
the store ([paths] store or [paths] cache); catalog (bundles are fetched into the cache); [paths] apk for the bundles inside the APK (without it they are reported as source.absent); master data for --views; with --stored-catalog a catalog version of the store instead of the current catalog |
store run |
the store; [paths] cache for inputs located in the cache; --fetch also what fetching needs (region, cdn, bundle key, [paths] apk) |
catalog versions / import / diff, store verify |
the store; import reads the APK's catalog from [paths] apk when it is set |
catalog fetch |
the store, [catalog] region and language, that region's cdn; its api (optional) for the resource version label |
The region, its cdn, [bundle] key and nonce_seed are read only when a file must be downloaded: when the
catalog and every bundle a command needs are in the cache, none of them is needed. A download that needs a missing
one stops the command with one line naming the file and the setting (see Errors).
Errors¶
A missing or malformed setting stops the command with exit status 2 and one line on standard error. The line names the setting, its environment variable and its flag where there is one; it never contains a value:
nnnotes: setting catalog.region is not set: give it as `region` in the [catalog] table of the config file, the environment variable NNNOTES_CATALOG_REGION or --region
nnnotes: <name>.bundle is not in the cache: setting bundle.key is not set: give it as `key` in the [bundle] table of the config file, the environment variable NNNOTES_BUNDLE_KEY
nnnotes: setting bundle.key: must be 16 bytes (32 hex digits)
nnnotes: setting paths.apk: file <path> not found
nnnotes: ffmpeg not found on PATH: give its path as `ffmpeg` in the [paths] table of the config file, the environment variable NNNOTES_PATHS_FFMPEG or --ffmpeg
When no config file is read, the line of an unset setting ends with (no config file was found: \nnnotes config
init` writes one to fill in). An unreadable config file (not found, invalid TOML) is reported the same way. Command-line usage errors also exit
with status 2: a missing-o`, or a key or id the data does not have (a key not in the catalog, an episode, spot or
music id without its master data row, a Live2D model the catalog does not have), which the error line names:
nnnotes export episode: error: episode 99999: no MasterAdv row with this id
nnnotes bundle pull: error: not a key of the catalog: Live/MusicScore/9999/9999_03
Setting values are never printed, logged or put into an error message, and the repr of the settings and key
objects shows no values.
A failed call to the game's API (master version, master download --latest, servers) exits with status 1 and
one line naming the method, the setting and the gRPC status, plus the game's error code when the server sent one;
it never contains the address:
nnnotes: game API call Version to [servers.tw] api failed: UNAVAILABLE (server unreachable)
Where the values come from¶
- Keys, nonce seed, CDN base, region and language: properties of the game client you own. nnnotes does not include them and does not derive them.
- API roots: the region's API root and the bootstrap API root from your own client. With
[bootstrap] apiset,nnnotes servers --show-hostsprints every region's CDN and API roots from the server list; a root field there can hold several alternatives separated by|, and any one of them can be used ascdn/api. - Client version: the version of your game client (
versionNameof itsbase.apk). The game's API rejects a version older than the one it accepts (game error code CLIENT_UPDATE_REQUIRED). [paths] apk: thebase.apkof your own installation of the game.apk settings,export story,export liveandsite buildread MonoBehaviours of its boot data with type trees that ship with nnnotes, one set per Unity version (currently game version 1.0.1, Unity 6000.3.12f1). With an APK whose classes do not match them, these commands stop with exit status 2 and a line naming the class, the game version and the Unity version.[paths] master: the output directory ofnnnotes master decode, run on master data files fromnnnotes master download --latest(or--version <version>) or on the game client's own files.[servers.<region>] masterthe same for one region:nnnotes --region <region> master download --latest -o <dir>, thennnnotes master decode <dir> -o <region dir>(the regions serve different master data versions).music-data --decoded-masteralso reads theMasterManifest.jsonof the decoded files there (copy it from the download directory; a published master data snapshot may carry it).- CRI HCA keycode: not a setting.
export audio,export story,export liveandsite buildread it from the APK's boot data;nnnotes apk hca-keyshows whether one was found and can write it as a.hcakeyfile for vgmstream. - Tools: vgmstream (
vgmstream-cli), FFmpeg and, forsite build, Node.js 20+ with a built ournotes-player.