Library Capability
How a library plugin declares mediaTypes, item schemas, entities, and renderer slots.
A library plugin defines what a library type is. It owns:
- The set of mediaTypes the library represents (
movies,tv,audiobooks,photos, etc.) and per-type config flags. - The bundling strategy that determines how scanned files are grouped into items.
- The path rules that classify discovered files (primary, trailer, companion, and so on).
- The item schema: typed fields stored on each library item.
- The entity definitions for show, season, person, genre, and any other records that items link to.
- The renderer config that decides which fields paint which UI slots, and what extra sections appear below them.
If a media type renders or behaves differently in Aviato, that difference lives in a library plugin, not in the web app. The web app is intentionally generic: it consumes whatever schema the library plugin returns and renders it via the slot vocabulary.
Manifest declaration
Two parts of the manifest matter for library plugins.
mediaTypes lists the supported types. Use the array form for
the simple case; switch to the object form when you need per-type
flags:
"capabilities": ["library"],
"mediaTypes": ["movies"]"capabilities": ["library"],
"mediaTypes": {
"tv": { "episodic": true }
}Per-type flags currently understood:
| Flag | Default | Effect |
|---|---|---|
episodic | false | Enables the player's "End of current episode" sleep timer (and future auto-advance). |
seekable | true | When false, hides player seek controls (e.g. books). |
idleProtection | true | When false, suppresses the "Are you still there?" prompt (e.g. books). |
Add new flags when the host UI needs to behave differently for a
media type. Never branch on the mediaTypes string itself in the
web; branch on a declared flag.
capabilityConfig.library declares bundling and path rules:
"capabilityConfig": {
"library": {
"bundling": { "strategy": "per-folder" },
"paths": [
{ "extensions": ["system:video"] },
{ "type": "trailer", "rules": ["*trailer*", "trailers/**/*"], "extensions": ["system:video"] },
{ "type": "behind-the-scenes", "rules": ["*behind?the?scenes*", "*bts*"], "extensions": ["system:video"] },
{ "type": "deleted-scene", "rules": ["*deleted?scene*"], "extensions": ["system:video"] },
{ "type": "extra", "rules": ["extras/**/*", "featurettes/**/*"], "extensions": ["system:video"] },
{ "type": "companion", "extensions": ["system:text", ".nfo", ".jpg", ".srt"] }
]
}
}Bundling strategies
strategy: "per-folder": every primary file in a folder bundles
into one item. Used by aviato-library-movies.
strategy: "per-file": each primary file is its own item. Pair
with an identity block for grouping under a parent entity:
"bundling": {
"strategy": "per-file",
"identity": { "pattern": "S(?<season>\\d+)E(?<episode>\\d+)", "scope": "directory" }
}Used by aviato-library-tv: every episode file is its own item
but shares a parent show entity at the directory level.
Path rules
Each entry classifies files by glob rules and/or extensions.
The first matching entry wins. Type vocabulary (non-exhaustive),
defined by MediaFileTypeEnum in @aviato/plugin-sdk:
primary (default), trailer, behind-the-scenes,
deleted-scene, extra, companion. Companion files are
sidecars (artwork, subtitles, .nfo) that ride along with a
primary item but do not become items themselves.
extensions accepts:
- Raw extensions, like
".mkv"or".srt". - Aliases, including:
system:video: every common video container.system:audio: every common audio container.system:image: every common image format.system:text:.pdf,.epub,.txt.
The full alias map is exported from @aviato/plugin-sdk as
SYSTEM_EXTENSION_ALIASES, with resolveExtensions() available
as a helper.
The library schema (returned from getSchema)
When Aviato starts a library plugin it calls library.getSchema()
once and caches the result. The returned LibrarySchema drives
every UI surface Aviato renders for that library:
{
name: 'Movies',
icon: 'FilmStrip', // Phosphor icon
description: '...',
mediaTypes: ['movies'], // optional override of manifest
itemSchema: { ... }, // typed property map for library items
entitySchemas: { ... }, // typed property maps per entity type
searchableFields: ['title', 'year'],
filterableFields: ['genres', 'year', 'rating'],
libraryViewBy: ['entity:show', 'items'], // browse defaults
display: { // library-wide visual hints
poster: { aspect: 'portrait' },
heroBadges: { field: 'year' },
},
allowItemRematch: true,
entityRenderers: { // optional: paints entity detail pages
show: { view: 'list', viewOptions: { ... }, slots: { ... }, extras: [...] },
season: { view: 'horizontal-scroll', slots: { ... } },
},
itemRenderer: { // optional: paints item detail pages
slots: { ... },
extras: [...],
},
}Item and entity schemas
itemSchema and entitySchemas[type] follow the same shape: a
property map naming the fields stored against an item or entity,
their type (string, number, string[], entity-ref,
artwork-ref, etc.), and optional metadata like editable,
order, and label. Aviato uses this schema to:
- Render the item-detail editor (Fix Match → "Edit item").
- Drive the per-entity detail page (
/library/<id>/<entityType>/<entityId>). - Type the bundle delta payloads that hooks return.
Library plugins don't store fields directly. They declare the shape, and indexer plugins or hook plugins populate values during ingestion. Aviato persists everything as JSON keyed by the schema.
Entities
Entities are first-class records owned by a library plugin: a show, a season, a person, an album, a genre. They exist independently of items so they can be referenced from many items at once and so they get their own URL and detail page.
To declare an entity:
- Add an entry to
entitySchemasdescribing its property map. - Optionally add
entityRenderers[type]to control how the entity's detail page renders. - Optionally include
entity:<type>inlibraryViewByso the library browse view shows entities of that type by default (for example, shows instead of episodes).
Items reference entities via entity-ref fields in their item
schema. Indexer plugins emit entity payloads alongside item
payloads during indexing, and Aviato reconciles them into the
entity graph.
The aviato-tmdb indexer, for example, emits show, season,
and person entities when it indexes a TV episode. The
aviato-library-tv plugin declares those types in its schema and
renders them.
Renderer slots
Both entityRenderers[type] and itemRenderer use the same
slot vocabulary: the same key means the same thing on entity
pages and item detail pages. Slots bind a region of the rendered
page to a metadata source.
slots: {
title: { field: 'title' },
subtitle: { fields: ['seasonNumber', 'episodeNumber'], format: 'template', template: 'S{0}E{1}' },
description: { field: 'overview' },
rating: { field: 'voteAverage', fallbackField: 'imdbRating' },
poster: { prefer: ['poster', 'thumb'] }, // asset slot
backdrop: { prefer: ['fanart', 'backdrop'] },
links: { include: ['canonicalIds', 'externalLinks'] },
}extras declares ordered sections rendered below the slot region:
extras: [
{ type: 'kv-grid', title: 'Details', fields: ['runtime', 'releaseDate', 'genres'] },
{ type: 'chips', title: 'Cast', field: 'cast', limit: 10 },
{ type: 'entity-cards', title: 'Seasons', source: 'children', childType: 'season' },
]When itemRenderer is absent, Aviato falls back to a generic
layout. When entityRenderers[type] is absent, the entity detail
page is hidden: the entity exists in the graph but has no
dedicated UI.
Library-wide display hints
display lives at the top of LibrarySchema and controls visuals
that apply across every page in the library, not specific to the
detail layout:
display.poster.aspectis'square' | 'portrait' | 'landscape'. Browse cards and home rows render at this aspect; mismatched artwork is letterboxed.display.heroBadgesis aSlotValuethat resolves to a comma-joined string and renders as badge chips on library hero banners.
Library plugin RPC contract
Methods Aviato calls on a library plugin (library.* namespace):
| Method | Called when | Returns |
|---|---|---|
getSchema | Plugin starts (cached) | LibrarySchema |
getSortOptions | User opens the sort dropdown | SortOption[] |
getFilterOptions | User opens the filter dropdown | FilterOption[] |
getGroupingOptions | User toggles grouping | GroupingOption[] |
getItemSummary | Building list/grid rows | ItemSummary (compact projection) |
getItemDetail | Opening the item detail page | ItemDetail (full projection) |
The summary/detail split exists so list views stay fast: list rows only need a poster URL, title, year, runtime, and rating, while the detail page needs cast, crew, related entities, and so on.
Reference
The following types are exported from @aviato/plugin-sdk:
LibrarySchema,LibraryDisplaySchema,EntityRendererConfig,ItemRendererConfig.- The slot value vocabulary,
RendererSlotsSchema, andRendererExtraSchema. - The entity schema definitions used by
entitySchemasandentity-reffields. SYSTEM_EXTENSION_ALIASESandresolveExtensions()for thesystem:*aliases.
Reference plugins to read: aviato-library-movies,
aviato-library-tv, aviato-library-audiobooks,
aviato-library-photos.
See also
- Hooks, events, and views for hook plugins that populate the fields a library plugin declares (TMDb, embedded metadata, posters).
- Plugin system overview