AnisurgeAnisurge / extensions

.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

FieldTypeRequiredDefaultDescription
schemaVersionintegerYesMust be 1. Determines parsing rules.
idstringYesUnique pack identifier. Pattern: [a-z0-9-]+. Must match the folder name in the catalog.
namestringYesHuman-readable display name shown in the Extensions list and install dialog.
versionstringYesDisplay version, e.g. "1.2.0". Shown in UI but not used for update detection.
versionCodeintegerYesMonotonic integer for update detection. Must increase on every change. Max: 2,147,483,647.
languagestringNo"all"Language code for content filtering.
nsfwbooleanNofalseMarks the pack for adult content. Shows warning labels in the app.
descriptionstringNoShort description (1-3 sentences) displayed in catalog cards.
authorstringNoCreator name, handle, or organization.
homepagestringNoProject website or source code URL.
iconUrlstringNoHTTPS URL to a 48×48 PNG icon. Displayed in install dialog and catalog cards.
minAppVersionCodeintegerNo0Minimum app build number required. Prevents installation on incompatible app versions.
capabilitiesobjectNo{}Feature capability flags. See Capabilities.
defaults.headersobjectNo{}Default HTTP headers applied to all http.get steps. Merged, step-level headers take precedence.
pipeline.resolvearrayYesNon-empty array of step objects. Must end with a map.videos step.

Capabilities Object

{
  "capabilities": {
    "subDub": true,
    "resolveBy": ["anilistId", "malId"]
  }
}
FieldTypeDefaultDescription
subDubbooleanfalseIf true, the app shows a Sub/Dub toggle. The {{lang}} variable is set to sub or dub accordingly.
resolveBystring[]["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

FieldTypeRequiredDefaultDescription
stepstringYesMust be "http.get".
urlstringYesRequest URL. Supports {{variable}} template substitution from context and previous step results.
headersobjectNo{}Per-request HTTP headers. Merged on top of defaults.headers.
saveAsstringYesVariable name to store the response body text.
optionalbooleanNofalseIf true, non-2xx HTTP responses do not cause pipeline failure. The saveAs variable remains unset.

Behavior

  • Merges defaults.headers then applies step headers (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

FieldTypeRequiredDefaultDescription
stepstringYesMust be "extract.regex".
fromstringYesSource variable name containing the text to search.
patternstringYesJavaScript-compatible regex pattern. Escape backslashes for JSON (\d\\d).
groupintegerNo0Capture group index. 0 = full match, 1 = first parenthesized group, etc.
saveAsstringYesVariable to store the extracted text (empty string if no match).
onlyIfMissingstringNoVariable 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 onlyIfMissing is 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

FieldTypeRequiredDescription
stepstringYesMust be "json.parse".
fromstringYesSource variable containing JSON text.
saveAsstringYesVariable 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

FieldTypeRequiredDescription
stepstringYesMust be "json.get".
fromstringYesVariable name containing a parsed JSON object.
pathstringYesDot-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).
saveAsstringYesVariable to store the retrieved value. Non-string values are converted to string.

Path Examples

PathResult
sources.file"https://example.com/stream.m3u8"
sources.0.fileFirst element of sources array, then file key
data.meta.titleNested object traversal: data.meta.title
tracks.1.labelSecond 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

FieldTypeRequiredDescription
stepstringYesMust be "map.videos".
filestringYesFinal video URL. Can be HLS master playlist (.m3u8) or direct media file (.mp4). Supports {{variable}} templates.
qualitystringNoQuality label displayed in the player UI (e.g. "Auto", "1080p", "720p", "480p").
headersobjectNoHTTP headers required by the CDN or streaming server during playback. Common headers: Referer, User-Agent, Origin.
subtitlesobjectNoSubtitle track configuration. See Subtitles below.
introstringNoVariable path to the intro end timestamp (in seconds). Used by the app's AniskipService for skip-intro button.
outrostringNoVariable path to the outro start timestamp (in seconds). Used for skip-outro.

Subtitles Object

{
  "subtitles": {
    "from": "sources.tracks",
    "urlKey": "file",
    "labelKey": "label"
  }
}
FieldTypeRequiredDescription
fromstringYesVariable path to an array of subtitle track objects.
urlKeystringYesKey in each track object for the subtitle file URL (usually file).
labelKeystringYesKey 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

FieldTypeRequiredDescription
namestringNoDebug label for the branch (not shown in UI).
whenobjectNoCondition that must be met for the branch to be attempted. See When Conditions.
stepsarrayYesPipeline steps for this branch. Must end with a terminal step (like map.videos).

When Conditions

OpTarget TypeDescriptionExample
gtnumberNumeric greater than value{ "op": "gt", "variable": "malId", "value": 0 }
eqstring/numberEquality comparison{ "op": "eq", "variable": "lang", "value": "dub" }
existsanyVariable is truthy (non-empty, non-null){ "op": "exists", "variable": "pageHtml" }

Behavior

  • Branches without a when condition 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

FieldTypeRequiredDescription
idstringYesPack ID, must match content/docs/<id>/<id>.asx folder/files
namestringYesDisplay name
versionstringYesLatest version string
versionCodeintegerYesLatest version code
downloadUrlstringYesHTTPS URL to the .asx file
languagestringNoLanguage filter
nsfwbooleanNoAdult content flag
descriptionstringNoShort description
authorstringNoAuthor name
iconUrlstringNoIcon URL
minAppVersionCodeintegerNoMinimum app build

Validation

Run the official validator before publishing:

node scripts/validate.mjs

The validator checks:

  1. All .asx files are valid JSON
  2. schemaVersion is 1
  3. id matches [a-z0-9-]+
  4. versionCode is a positive integer
  5. Pipeline has at least one step ending with map.videos
  6. Step field types match schema
  7. No unrecognized fields
  8. Index entries match pack files (ID, version, versionCode)