# The project config

> The four blocks of a config, where to find every option, and how it is validated.

A project's `config` has four blocks:

```yaml
sourceMedia:          # optional — where the media comes from; the input folder when left out
  '@type': S3FolderSource
transcription:        # required — what is spoken, and who transcribes it
  '@type': Speechmatics
  language: en
translations:         # optional — one entry per target language
  - language: es
    engine: { '@type': Gemini }
    ttsOptions:       # optional — dub this language
      provider: { '@type': Deepdub, voice: auto }
outputs:              # required — where the results go, and the files to produce for every input
  - '@type': S3FolderOutput
    items:
      - '@type': VideoFile
        ext: mp4
        nameTemplate: '${name}.es.${ext}'
        useOriginalTracks: true
        dubTracks:
          - { language: es, title: Spanish }
```

- **[Inputs](/vod-express/concepts/inputs)**: The input folder, an RSS feed or a Media RSS feed.
- **[Transcription](/vod-express/configuration/transcription)**: Speech recognition engines and their options.
- **[Translation](/vod-express/configuration/translation)**: Gemini, OpenAI, DeepL, Google and more; glossaries and prompts.
- **[Dubbing](/vod-express/configuration/dubbing)**: Voices, voice cloning, clean dub or voice-over.
- **[Outputs](/vod-express/configuration/outputs)**: The output folder and output feeds; videos, audio files, subtitle files and their tracks.

These pages explain how the pieces fit together, with the fields that matter most. **Every** field,
with its type, default and allowed values, is in the [Config reference](/vod-express/configuration/reference),
generated from the build's schema.

## Polymorphic objects: `@type`

Sources, engines, voices, destinations and output files come in several kinds, told apart by
`@type`: `"@type": "Speechmatics"` selects the Speechmatics recognizer and its own set of options.
Each kind accepts only its own fields.

## Language codes

Languages are BCP 47 codes such as `en`, `es`, `pt-BR` or `zh-Hant`. [Languages](/vod-express/configuration/languages)
lists every code with the engines that transcribe and translate it, and so does
`GET /enums/languages`:

```bash
curl -s -H "$AUTH" $API/enums/languages | jq '.data[] | select(.code == "es")'
```

```json
{
  "code": "es",
  "name": "Spanish",
  "transcriptionEngines": ["Speechmatics", "Soniox"],
  "translationEngines": ["Google", "DeepL", "OpenAI", "Nova", "Gemini"]
}
```

## Defaults you can rely on

You may leave out:

- **`sourceMedia`**: the project reads its input folder, and the stored config says
  `{"@type": "S3FolderSource"}`;
- **`transcription.@type`**: the first engine that transcribes the language is used;
- **a translation's `engine`**: the recommended engine for that target language is used;
- **any option with a default** in the schema.

The engines chosen for you are stored in the project and shown when you read it back, so the
config you read is the config that runs.

The project's folders and feed addresses are the API's to choose: the `path` of `S3FolderSource`
and `S3FolderOutput`, and `path`, `mediaPath` and `mediaUrl` of a feed output, are not part of the
config, and are refused if sent. `storage` on the project says where the folders are.

## Builds and the schema

Processing runs on a versioned **build**. Each build publishes the JSON Schema of the config it
accepts. A new project gets your account's default build (`GET /whoami` →
`vodExpress.defaultBuildVersion`) and keeps it until you change `buildVersion`, so a new build never
changes how an existing project behaves.

| Call | Returns |
|---|---|
| `GET /build-versions` | Every build you can choose, newest first (by version, then build date), and your default. |
| `GET /schema?buildVersion=…` | The JSON Schema (draft-07) of `config` for a build; your default when omitted. |
| `GET /enums/source-types` | Where media can come from (`sourceMedia.@type`), with titles. |
| `GET /enums/destination-types` | Where results can go (`outputs[].@type`). |
| `GET /enums/transcription-types` | The transcription engines (`transcription.@type`). |
| `GET /enums/translation-engines` | The translation engines. |
| `GET /enums/tts-engines` | The dubbing voice providers. |
| `GET /enums/output-types` | The kinds of output file (`outputs[].items[].@type`). |
| `GET /enums/languages` | Languages and the engines for each. |

The schema carries a title, a description, the type, the allowed values and the default of every
field; the [Config reference](/vod-express/configuration/reference) is the default build's, as a page. Load
the schema into your editor or form builder to validate configs before you send them:

```bash
curl -s -H "$AUTH" $API/schema > vod-config.schema.json
```

## JSON or YAML

The API reads either. Send YAML with `Content-Type: application/yaml`, and read a project's config
as YAML with `Accept: application/yaml`:

```bash
curl -s -H "$AUTH" -H 'Accept: application/yaml' $API/projects/$PROJECT/config
```

## Validation

Every create and change is checked in full, and every problem is reported at once, keyed by
JSON pointer into the request:

```json 422
{
  "message": "No translation has ttsOptions, so there is no dub to add: use useOriginalTracks for the input’s audio. (and 2 more errors)",
  "errors": {
    "/config/outputs/0/items/0/dubTracks/0/language": [
      "No translation has ttsOptions, so there is no dub to add: use useOriginalTracks for the input’s audio."
    ],
    "/config/outputs/0/items/0/nameTemplate": [
      "The name template must contain ${name}, or every input would write the same file."
    ],
    "/config/translations/0/language": ["Language 'xx' is not supported by engine 'DeepL'"]
  }
}
```

First the config is checked against the build's schema: types, required fields, allowed values
and unknown fields. Then come the rules a schema cannot express:

- the transcription engine transcribes the source language, and each translation engine translates
  into its target language;
- a dub track is a language that is **dubbed** (has `ttsOptions`);
- an audio file holds exactly one audio track: the input's audio (`useOriginalTracks`), which an
  MP3 or WAV file cannot take, or one dub track;
- a subtitle track or file is the transcription language or a translation language;
- every `nameTemplate` contains `${name}`, uses only the variables its output kind has, and renders
  a name no other item of the same destination renders;
- there is at most one `S3FolderOutput`, and every destination lists at least one item;
- a feed output needs the feed source of its kind (`RssOutput` an `RssSource`, `MrssOutput` an
  `MrssSource`), has one language per feed (the transcription language or a translation language)
  and exactly one video or audio file among its items;
- a feed source's `url` is an `https://` address on a public host, and the feed has items the
  project can download;
- a dub's `locale`, when given, belongs to its language.
