.asx Schema Reference — Complete Field and Step Documentation
Complete technical reference for the Anisurge .asx extension schema version 1 — top-level fields, pipeline steps (http.get, extract.regex, json.parse, json.get, map.videos, try), variable templating, and index.json format.
.asx Schema Reference — Version 1
Schema version 1 · Engine ANISURGE · Single UTF-8 JSON file with .asx extension
Top-Level Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
schemaVersion | integer | Yes | — | Must be 1. Determines parsing rules. |
id | string | Yes | — | Unique pack identifier. Pattern: [a-z0-9-]+. Must match the folder name in the catalog. |
name | string | Yes | — | Human-readable display name shown in the Extensions list and install dialog. |
version | string | Yes | — | Display version, e.g. "1.2.0". Shown in UI but not used for update detection. |
versionCode | integer | Yes | — | Monotonic integer for update detection. Must increase on every change. Max: 2,147,483,647. |
language | string | No | "all" | Language code for content filtering. |
nsfw | boolean | No | false | Marks the pack for adult content. Shows warning labels in the app. |
description | string | No | — | Short description (1-3 sentences) displayed in catalog cards. |
author | string | No | — | Creator name, handle, or organization. |
homepage | string | No | — | Project website or source code URL. |
iconUrl | string | No | — | HTTPS URL to a 48×48 PNG icon. Displayed in install dialog and catalog cards. |
minAppVersionCode | integer | No | 0 | Minimum app build number required. Prevents installation on incompatible app versions. |
capabilities | object | No | {} | Feature capability flags. See Capabilities. |
defaults.headers | object | No | {} | Default HTTP headers applied to all http.get steps. Merged, step-level headers take precedence. |
pipeline.resolve | array | Yes | — | Non-empty array of step objects. Must end with a map.videos step. |
Capabilities Object
{
"capabilities": {
"subDub": true,
"resolveBy": ["anilistId", "malId"]
}
}| Field | Type | Default | Description |
|---|---|---|---|
subDub | boolean | false | If true, the app shows a Sub/Dub toggle. The {{lang}} variable is set to sub or dub accordingly. |
resolveBy | string[] | ["anilistId"] | Which identifier(s) the pipeline can use. Supported: anilistId, malId. |
Default Headers
{
"defaults": {
"headers": {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "*/*"
}
}
}Step-level headers are merged on top of defaults.headers. Both are optional.
Pipeline Steps
http.get — HTTP GET Request
Fetches a remote URL and stores the response body as a string variable.
{
"step": "http.get",
"url": "https://example.com/api/{{anilistId}}",
"headers": { "Referer": "https://example.com/" },
"saveAs": "pageHtml",
"optional": false
}Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
step | string | Yes | — | Must be "http.get". |
url | string | Yes | — | Request URL. Supports {{variable}} template substitution from context and previous step results. |
headers | object | No | {} | Per-request HTTP headers. Merged on top of defaults.headers. |
saveAs | string | Yes | — | Variable name to store the response body text. |
optional | boolean | No | false | If true, non-2xx HTTP responses do not cause pipeline failure. The saveAs variable remains unset. |
Behavior
- Merges
defaults.headersthen applies stepheaders(step values override defaults) - Follows HTTP redirects (301, 302, 303, 307, 308)
- Stores raw response body as string; encoding is UTF-8
- Timeout: 30 seconds (app-defined)
- Non-2xx response throws pipeline error unless
optional: true
extract.regex — Regular Expression Extraction
Extracts text from a string variable using a regular expression pattern and capture group.
{
"step": "extract.regex",
"from": "pageHtml",
"pattern": "data-id=\"(\\d+)\"",
"group": 1,
"saveAs": "dataId",
"onlyIfMissing": "dataId"
}Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
step | string | Yes | — | Must be "extract.regex". |
from | string | Yes | — | Source variable name containing the text to search. |
pattern | string | Yes | — | JavaScript-compatible regex pattern. Escape backslashes for JSON (\d → \\d). |
group | integer | No | 0 | Capture group index. 0 = full match, 1 = first parenthesized group, etc. |
saveAs | string | Yes | — | Variable to store the extracted text (empty string if no match). |
onlyIfMissing | string | No | — | Variable name to check. If this variable already has a truthy value, the step is skipped (useful for deduplication in try branches). |
Behavior
- Uses JavaScript
String.prototype.match()semantics - First match only (no global flag)
- If no match and
onlyIfMissingis not set, the step stores an empty string (does not error)
json.parse — JSON String Parsing
Parses a JSON-formatted string into a structured object for subsequent navigation.
{
"step": "json.parse",
"from": "sourcesBody",
"saveAs": "sources"
}Fields
| Field | Type | Required | Description |
|---|---|---|---|
step | string | Yes | Must be "json.parse". |
from | string | Yes | Source variable containing JSON text. |
saveAs | string | Yes | Variable to store the parsed result (object or array). |
Behavior
- Uses the app's JSON parser (kotlinx.serialization)
- Supports JSON objects (
{}), arrays ([]), strings, numbers, booleans, and null - Throws pipeline error if the source is not valid JSON
json.get — JSON Value Navigation
Retrieves a value from a parsed JSON structure using a dot-separated path.
{
"step": "json.get",
"from": "sources",
"path": "sources.0.file",
"saveAs": "streamUrl"
}Fields
| Field | Type | Required | Description |
|---|---|---|---|
step | string | Yes | Must be "json.get". |
from | string | Yes | Variable name containing a parsed JSON object. |
path | string | Yes | Dot-separated navigation path. Array indices use numeric keys (0, 1, 2). Null-safety: if any intermediate key is null/missing, the result is null (no error). |
saveAs | string | Yes | Variable to store the retrieved value. Non-string values are converted to string. |
Path Examples
| Path | Result |
|---|---|
sources.file | "https://example.com/stream.m3u8" |
sources.0.file | First element of sources array, then file key |
data.meta.title | Nested object traversal: data.meta.title |
tracks.1.label | Second element of tracks array, then label key |
map.videos — Video Stream Output
The terminal step that produces the final video stream objects for playback. Must be the last step in the pipeline.
{
"step": "map.videos",
"file": "{{sources.sources.0.file}}",
"quality": "Auto",
"headers": { "Referer": "https://example.com/" },
"subtitles": {
"from": "sources.tracks",
"urlKey": "file",
"labelKey": "label"
},
"intro": "sources.intro",
"outro": "sources.outro"
}Fields
| Field | Type | Required | Description |
|---|---|---|---|
step | string | Yes | Must be "map.videos". |
file | string | Yes | Final video URL. Can be HLS master playlist (.m3u8) or direct media file (.mp4). Supports {{variable}} templates. |
quality | string | No | Quality label displayed in the player UI (e.g. "Auto", "1080p", "720p", "480p"). |
headers | object | No | HTTP headers required by the CDN or streaming server during playback. Common headers: Referer, User-Agent, Origin. |
subtitles | object | No | Subtitle track configuration. See Subtitles below. |
intro | string | No | Variable path to the intro end timestamp (in seconds). Used by the app's AniskipService for skip-intro button. |
outro | string | No | Variable path to the outro start timestamp (in seconds). Used for skip-outro. |
Subtitles Object
{
"subtitles": {
"from": "sources.tracks",
"urlKey": "file",
"labelKey": "label"
}
}| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Variable path to an array of subtitle track objects. |
urlKey | string | Yes | Key in each track object for the subtitle file URL (usually file). |
labelKey | string | Yes | Key in each track object for the display label (e.g. "English", "Español"). |
Each subtitle object in the array should look like:
{ "file": "https://example.com/subs/en.vtt", "label": "English" }try — Conditional Fallback Branches
Evaluates branches in order. The first branch that completes without error wins. Unselected branches do not execute.
{
"step": "try",
"branches": [
{
"name": "AniList route",
"when": { "op": "gt", "variable": "malId", "value": 0 },
"steps": [ /* pipeline steps */ ]
},
{
"name": "MAL fallback",
"steps": [ /* pipeline steps */ ]
}
]
}Branch Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Debug label for the branch (not shown in UI). |
when | object | No | Condition that must be met for the branch to be attempted. See When Conditions. |
steps | array | Yes | Pipeline steps for this branch. Must end with a terminal step (like map.videos). |
When Conditions
| Op | Target Type | Description | Example |
|---|---|---|---|
gt | number | Numeric greater than value | { "op": "gt", "variable": "malId", "value": 0 } |
eq | string/number | Equality comparison | { "op": "eq", "variable": "lang", "value": "dub" } |
exists | any | Variable is truthy (non-empty, non-null) | { "op": "exists", "variable": "pageHtml" } |
Behavior
- Branches without a
whencondition always attempt - Multiple branches can succeed, but only the first is used
- If no branch succeeds, pipeline fails with
"no branch succeeded" - Variable scope is shared across all branches (later branches see variables set by earlier failed branches)
index.json Format
The repository index file that the app fetches to discover available packs:
{
"schemaVersion": 1,
"name": "Anisurge Official Extensions",
"engine": "ANISURGE",
"homepage": "https://github.com/Anisurge/extensions",
"extensions": [
{
"id": "anokoto",
"name": "Anokoto",
"version": "1.0.1",
"versionCode": 2,
"language": "all",
"nsfw": false,
"description": "MegaPlay HLS + softsubs from AniList or MAL.",
"author": "Anisurge",
"iconUrl": "https://raw.githubusercontent.com/Anisurge/extensions/main/extensions/anokoto/icon.png",
"downloadUrl": "https://raw.githubusercontent.com/Anisurge/extensions/main/extensions/anokoto/anokoto.asx",
"minAppVersionCode": 140
}
]
}Index Entry Fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Pack ID, must match content/docs/<id>/<id>.asx folder/files |
name | string | Yes | Display name |
version | string | Yes | Latest version string |
versionCode | integer | Yes | Latest version code |
downloadUrl | string | Yes | HTTPS URL to the .asx file |
language | string | No | Language filter |
nsfw | boolean | No | Adult content flag |
description | string | No | Short description |
author | string | No | Author name |
iconUrl | string | No | Icon URL |
minAppVersionCode | integer | No | Minimum app build |
Validation
Run the official validator before publishing:
node scripts/validate.mjsThe validator checks:
- All
.asxfiles are valid JSON schemaVersionis1idmatches[a-z0-9-]+versionCodeis a positive integer- Pipeline has at least one step ending with
map.videos - Step field types match schema
- No unrecognized fields
- Index entries match pack files (ID, version, versionCode)
Create an Extension — .asx Pack Author Guide
Complete authoring guide for Anisurge .asx extension packs — declarative JSON pipeline authoring, step types, variable templates, conditional branching, validation, and publishing workflow.
Testing Extensions — Validation, Smoke Tests, and Debugging
Comprehensive testing guide for Anisurge .asx extension packs — schema validation, deep link installation testing, playback smoke tests, update verification, and troubleshooting common issues.