Skip to main content
Version: 0.0.50

Manifest and Hooks Reference

This is the public reference for manifest.json, the global plugin object, hook contexts, and metadata returned by plugins. The TypeScript declarations are the source for compile-time contracts:

Install them with npm install --save-dev @shisho/plugin-sdk. See Developing Plugins for a build workflow.

Artifact Layout

The plugin directory or release ZIP must put these files at its root:

manifest.json
main.js

Additional files and directories are allowed. When main.js executes, it must create a non-null global object named plugin.

Manifest Fields

{
"manifestVersion": 1,
"id": "example-metadata",
"name": "Example Metadata",
"version": "1.2.0",
"overview": "Finds metadata from Example Books.",
"description": "Longer details shown on the plugin page.",
"homepage": "https://github.com/example/example-metadata",
"license": "MIT",
"minShishoVersion": "0.0.49",
"capabilities": {},
"configSchema": {}
}
FieldRequiredContract
manifestVersionYesInteger 1. Other values are rejected.
idYesNon-empty plugin identifier. Keep it stable across releases and match the repository entry and installation directory ID.
nameYesNon-empty display name.
versionYesNon-empty release version. Use a comparable semantic version for update handling.
overviewNoShort one-line summary, separate from the longer description.
descriptionNoLonger plugin description.
homepageNoPlugin home or source URL.
licenseNoLicense name or identifier.
minShishoVersionNoMinimum compatible Shisho version. Loading fails as incompatible when the running version is older.
capabilitiesNoHook declarations, identifier registrations, and permissions.
configSchemaNoAdministrator-configurable values available through shisho.config.

A JavaScript hook without its corresponding capability causes plugin loading to fail. A declared capability without a JavaScript hook is ignored. An onUninstalling lifecycle callback does not need a manifest capability.

Hook Capabilities

A plugin can declare and implement any combination of the four hook capabilities.

Input Converter Capability

{
"capabilities": {
"inputConverter": {
"description": "Converts MOBI to EPUB",
"sourceTypes": ["mobi"],
"mimeTypes": ["application/x-mobipocket-ebook"],
"targetType": "epub"
}
}
}
  • sourceTypes is required and lists accepted file extensions without a leading dot.
  • targetType is required and names the produced extension.
  • mimeTypes and description are optional.

File Parser Capability

{
"capabilities": {
"fileParser": {
"description": "Reads Example Book metadata",
"types": ["example"],
"mimeTypes": ["application/x-example-book"]
}
}
}
  • types is required and lists extensions without a leading dot.
  • mimeTypes and description are optional.
  • epub, cbz, m4b, and pdf are reserved built-in extensions and cannot be claimed by a file parser.

When MIME types are present, Shisho compares compatible MIME values rather than requiring byte-for-byte string equality, so registered aliases and MIME parameters can match.

Metadata Enricher Capability

{
"capabilities": {
"metadataEnricher": {
"description": "Searches Example Books",
"fileTypes": ["epub", "m4b"],
"fields": ["title", "authors", "description", "language", "abridged"]
}
}
}
  • fields is required. Missing or empty fields disable only the enricher hook and produce a load warning.
  • fileTypes is optional. Omit it to allow every file type.
  • Invalid field names cause plugin loading to fail.

Valid declarations are:

title, subtitle, authors, narrators, series, seriesNumber, genres, tags,
description, publisher, url, releaseDate, cover, identifiers, language,
abridged

seriesNumber is an alias for the full series group. cover and series grouping rules are described under Grouped Metadata.

Output Generator Capability

{
"capabilities": {
"outputGenerator": {
"description": "Generates MOBI downloads",
"id": "mobi",
"name": "MOBI",
"sourceTypes": ["epub"]
}
}
}

id, name, and sourceTypes are required. The ID is the stable output format identifier; name is its display label.

Permission Capabilities

{
"capabilities": {
"httpAccess": {
"description": "Calls the Example Books API",
"domains": ["api.example.com", "*.covers.example.com"]
},
"fileAccess": {
"description": "Reads sidecars next to book files",
"level": "read"
},
"ffmpegAccess": {
"description": "Transcodes audio"
},
"shellAccess": {
"description": "Runs the Example converter",
"commands": ["example-convert"]
}
}
}
CapabilityRequired MembersEffect
httpAccessdomains: string[]Allows synchronous HTTP requests to exact domains or *.example.com wildcard patterns. Redirect targets are checked too.
fileAccesslevel: "read" | "readwrite"Grants broad filesystem reads or reads and writes beyond paths supplied to a hook.
ffmpegAccessNoneAllows shisho.ffmpeg.transcode, probe, and version.
shellAccesscommands: string[]Allows shisho.shell.exec only for listed command names. Arguments do not pass through a shell.

Each capability can include an optional description. Review the precise path rules and APIs in the Host API Reference.

Custom Identifier Types

Register identifiers that Shisho can display and validate:

{
"capabilities": {
"identifierTypes": [
{
"id": "example_books",
"name": "Example Books",
"urlTemplate": "https://example.com/book/{value}",
"pattern": "^EB-[0-9]+$"
}
]
}
}

id and name are required. urlTemplate and validation pattern are optional. Use {value} as the value placeholder. Metadata can then return { "type": "example_books", "value": "EB-123" }.

Configuration Schema

configSchema maps arbitrary keys to form definitions:

{
"configSchema": {
"apiKey": {
"type": "string",
"label": "API Key",
"description": "Key issued by Example Books",
"required": true,
"secret": true
},
"maxResults": {
"type": "number",
"label": "Maximum Results",
"default": 10,
"min": 1,
"max": 50
},
"strategy": {
"type": "select",
"label": "Strategy",
"options": [
{ "value": "fast", "label": "Fast" },
{ "value": "thorough", "label": "Thorough" }
]
}
}
}
MemberRequiredMeaning
typeYesstring, boolean, number, select, or textarea
labelYesDisplay label
descriptionNoHelp text
requiredNoMarks the value required in the UI
secretNoMasks the stored value when shown again
defaultNoString, number, or boolean default
min, maxNoNumeric input limits
optionsFor useful selectsArray of { value, label } string pairs

At runtime, shisho.config.get(key) returns a configured string or undefined; getAll() returns string values. Parse booleans and numbers in plugin code when needed.

Input Converter Hook

An input converter must complete within five minutes.

interface InputConverterContext {
sourcePath: string;
targetDir: string;
}

interface ConvertResult {
success: boolean;
targetPath: string;
}
plugin = {
inputConverter: {
convert: function (context) {
var target = context.targetDir + "/converted.epub";
// Produce target using shisho.fs, shisho.archive, FFmpeg, or an allowed command.
return { success: true, targetPath: target };
},
},
};

Return the actual output path. Hook-provided source and target paths are available to filesystem and archive operations without broad fileAccess.

File Parser Hook

A file parser must complete within one minute.

interface FileParserContext {
filePath: string;
fileType: string;
}

fileParser.parse(context) returns ParsedMetadata:

plugin = {
fileParser: {
parse: function (context) {
return {
title: "Example Book",
authors: [{ name: "A. Writer", role: "writer" }],
releaseDate: "2025-06-15",
language: "en-US",
identifiers: [{ type: "isbn_13", value: "9781234567890" }],
};
},
},
};

The parser receives access to filePath. Return only metadata actually present or reliably derived.

Metadata Enricher Hook

A metadata search must complete within one minute.

interface SearchContext {
query: string;
author?: string;
identifiers?: Array<{ type: string; value: string }>;
file?: {
fileType?: string;
filePath?: string;
duration?: number;
pageCount?: number;
filesizeBytes?: number;
};
}

interface SearchResponse {
results: ParsedMetadata[];
}
plugin = {
metadataEnricher: {
search: function (context) {
return {
results: [
{
title: "Example Book",
authors: [{ name: "A. Writer", role: "writer" }],
description: "A matched edition.",
coverUrl: "https://covers.example.com/123.jpg",
confidence: 0.94,
},
],
};
},
},
};

query is always present. Other search hints are optional. When file.filePath is present, the enricher may read exactly that target file without broad fileAccess; it may not write it or read siblings unless fileAccess grants that access.

There is no separate enrich hook. Each result contains candidate metadata directly.

During automatic scans:

  1. Shisho uses the first result.
  2. A provided confidence below the effective threshold skips the result. Omitted confidence does not trigger threshold rejection.
  3. Returned fields not declared by the manifest are removed. Disabled declared fields are also removed.
  4. Enrichers run in administrator-defined order. The first enricher to provide a value for a field wins.
  5. File-parsed metadata fills fields that no enricher supplied.

Interactive identification lets the user review candidate fields before applying them.

Output Generator Hook

Output generation must complete within five minutes.

interface OutputGeneratorContext {
sourcePath: string;
destPath: string;
book: {
id?: number;
title?: string;
subtitle?: string;
description?: string;
authors?: Array<{ name: string; role?: string }>;
series?: Array<{ name: string; number?: number }>;
genres?: string[];
tags?: string[];
};
file: {
id?: number;
filepath?: string;
fileType?: string;
fileRole?: string;
filesizeBytes?: number;
name?: string;
url?: string;
publisher?: string;
releaseDate?: string;
narrators?: string[];
identifiers?: Array<{ type: string; value: string }>;
};
}

outputGenerator.generate(context) writes the output to destPath and returns nothing. outputGenerator.fingerprint(context) returns a string used to decide whether cached output remains valid:

plugin = {
outputGenerator: {
generate: function (context) {
// Write context.destPath.
},
fingerprint: function (context) {
return String(context.book.title || "") + ":" +
String(context.file.fileType || "");
},
},
};

Include every input that should invalidate generated output in the fingerprint.

Parsed Metadata

All properties are optional unless stated by a nested type.

PropertyTypeSemantics
title, subtitle, description, publisher, urlstringText metadata. HTML is removed from descriptions when parsed.
authorsParsedAuthor[]Each author requires name; role is optional.
narrators, genres, tagsstring[]Resource names are resolved through Shisho's normal canonical names and aliases.
seriesstringSeries name.
seriesNumbernumberFinite series position, including fractional positions.
seriesNumberEndnumberOptional inclusive omnibus range end, greater than seriesNumber.
seriesNumberUnit"volume" | "chapter"Optional series unit. Chapter units apply to CBZ metadata.
releaseDatestringYYYY-MM-DD or RFC3339 date. Invalid dates are ignored.
languagestringBCP 47 tag such as en, en-US, or zh-Hans; Shisho normalizes accepted tags.
abridgedbooleantrue abridged, false unabridged, omitted unknown.
coverMimeTypestringMIME type for coverData.
coverDataArrayBufferRaw image bytes, most useful for parsers extracting embedded covers.
coverUrlstringRemote image URL. Its domain must be allowed by httpAccess.
coverPagenumberZero-based page index for CBZ or PDF.
durationnumberAudiobook duration in seconds.
bitrateBpsnumberAudio bitrate in bits per second.
pageCountnumberPage count.
identifiersParsedIdentifier[]Each entry requires string type and value. Standard identifier values are canonicalized when stored.
chaptersParsedChapter[]Each chapter requires title; positions use startPage, startTimestampMs, or href, with optional nested children.
confidencenumberEnricher match score from 0 to 1.

Known author roles include writer, penciller, inker, colorist, letterer, cover_artist, editor, and translator. Omitting a role creates a generic author association.

Grouped Metadata

The enricher field declaration cover controls coverData, coverMimeType, coverUrl, and coverPage together.

  • For CBZ and PDF, return coverPage. Image data and image URLs are not applied.
  • For other formats, return coverData or coverUrl. coverData takes precedence when both are present, and coverPage is ignored.
  • An invalid or out-of-range page is skipped. During automatic enrichment, an external image must have greater total resolution than the existing file cover before it replaces it.

The series or seriesNumber declaration controls the series name and all three number properties. The number group is atomic: a finite start is required, a supplied end must be finite and greater than the start, and the unit must be volume or chapter. If any supplied member is invalid, Shisho discards the complete number group.

Uninstall Lifecycle

The optional top-level onUninstalling function runs before an active plugin is removed:

plugin = {
fileParser: { parse: function () { return {}; } },
onUninstalling: function () {
shisho.log.info("Cleaning up Example Parser");
},
};

Use it for best-effort cleanup such as revoking a token or deleting plugin-managed cache files. It receives no arguments and returns nothing. Errors do not stop uninstalling. Do not depend on this hook as the only way to preserve important user data.