Skip to main content

Introduction to Writing Plugins

Writing Plugins for Unmanic should be easy.

All that is required to get started is a basic knowledge of writing Python scripts.

Directory Structure

The basic directory structure of a Plugin should be:

my_new_plugin
├── changelog.md
├── description.md
├── info.json
├── lib
├── package.json
├── plugin.py
├── requirements.post-install.txt
├── requirements.txt
└── static

File: changelog.md

This file should be used to record changes made to the Plugin.


File: description.json (optional)

This file can be used to extend the description provided within the info.json file.


File: info.json

A JSON file containing the metadata of your Plugin. This JSON file should contain the following data:

  • author - Your name.
  • compatibility - A list of Unmanic Plugin Handler versions that this Plugin is compatible with (see table below).
  • description - A long description of your Plugin detailing what it does. To include line-breaks, insert a \n.
  • icon - A URI to an image. If no icon is provided, the default Plugin icon will be used in the WebUI.
  • id - A string identifier for your Plugin. Should only contain lowercase a-z or _ characters.
  • name - A very short name for your Plugin.
  • platform - Platform compatibility of this plugin. Can be any combination of ["all", "linux", "windows", "mac"].
  • priorities - A dictionary of the initial priority that this Plugin's runners within the Plugin flow.
  • tags - A comma separated list able to be used as keywords when searching for Plugins.
  • defer_dependency_install - Optional boolean. When true, Unmanic will install this plugin's requirements.txt and package.json dependencies during plugin installation instead of assuming they were already bundled with the plugin package.
  • version - The version of your Plugin.
Example:
{
"author": "Josh.5",
"compatibility": [
1,
2
],
"description": "Specify a language tag for Unmanic to try and put as 1st subtitle track.",
"defer_dependency_install": false,
"icon": "https://raw.githubusercontent.com/Josh5/unmanic.plugin.reorder_subtitle_streams_by_language/master/icon.png",
"id": "reorder_subtitle_streams_by_language",
"name": "Re-order subtitle streams by language",
"platform": [
"all"
],
"priorities": {
"on_library_management_file_test": 99,
"on_worker_process": 2
},
"tags": "subtitle,ffmpeg,library file test",
"version": "1.0.4"
}
Plugin handler compatibility:
Plugin handlerUnmanic versions
v1v0.1.0 - v0.1.4
v2v0.2.0 - current

Directory: lib (optional)

Location of any additional Python modules imported by this plugin. Use this directory if you are including files from another project on GitHub, etc.


File: package.json (optional)

This file will be read during the plugin build in GitHub. Any nodeJS packages listed will be installed and packaged with the plugin.

Python modules will be installed to {plugin root}/node_modules.


File: plugin.py

The main Pugin Python module.

This file will be imported and it's functions called by the main Unmanic process.


File: requirements.txt (optional)

This file will be read during the plugin build in GitHub. Any Python modules listed will be installed and packaged with the plugin.

Python modules will be installed to {plugin root}/site-packages.


File: requirements.post-install.txt (optional)

This file may be used when a packaged plugin needs to install Python dependencies at plugin install time.

When a plugin zip is installed, Unmanic checks for requirements.post-install.txt and, if present, installs the listed Python modules into {plugin root}/site-packages.

Use this file for dependencies that should be resolved on the target Unmanic system during installation rather than being pre-bundled into the plugin package.

This file is processed during packaged plugin installation whether or not defer_dependency_install is set.

Dependency Installation Modes

Unmanic supports two dependency installation patterns for plugin authors.

1. Bundled dependencies

This is the default plugin packaging model.

  • Add Python dependencies to requirements.txt.
  • Add frontend dependencies to package.json if needed.
  • Build/package the plugin so those dependencies are bundled with the plugin.
  • Do not set defer_dependency_install unless you explicitly want the target Unmanic instance to install dependencies during plugin installation.

2. Deferred dependency installation

Set "defer_dependency_install": true in info.json when you want Unmanic to install dependencies during plugin installation.

This option exists primarily for plugins whose packaged dependencies would be too large to reasonably ship inside the plugin repository.

In practice, this matters most for plugins intended for the official plugin repository hosted on GitHub. If bundling the built plugin with all of its dependencies would create artifacts that are too large for GitHub's storage limits or generally too large to manage well in the repository, you can defer dependency installation and let the target Unmanic instance install them after the plugin itself has been installed.

This allows the plugin source and package metadata to remain small while still making large Python or frontend dependency sets available on the destination system at install time.

When this flag is enabled during packaged plugin installation:

  • requirements.post-install.txt is installed first, if present.
  • requirements.txt is then installed into the plugin's site-packages directory.
  • package.json dependencies are then installed and built.
  • The requirements.txt install recreates site-packages, so any Python packages installed only by requirements.post-install.txt will be replaced unless they are also present in requirements.txt.

Example:

{
"id": "my_plugin",
"name": "My Plugin",
"author": "Example Author",
"version": "0.0.1",
"description": "Example plugin using deferred dependency installation.",
"defer_dependency_install": true,
"compatibility": [2]
}

When To Use defer_dependency_install

Use defer_dependency_install when:

  • the plugin's bundled Python or Node dependencies would make the packaged plugin too large to store comfortably in a Git-based plugin repository
  • the plugin is intended for the official repository and packaging everything into the published plugin would exceed practical GitHub size limits
  • installing dependencies on the destination Unmanic system is a better tradeoff than committing large built dependency payloads to the repository

Do not use defer_dependency_install when:

  • your dependency set is reasonably small and can be bundled normally
  • you do not need to work around repository size constraints
  • you want the most predictable install behavior with dependencies already packaged with the plugin

For most plugins, it is better to leave defer_dependency_install unset or false and ship the plugin with its dependencies bundled normally.

Choosing Between requirements.txt and requirements.post-install.txt

  • Use requirements.txt for the main Python dependencies of your plugin.
  • Use requirements.post-install.txt for Python dependencies that should be installed during packaged plugin installation even when defer_dependency_install is not enabled.
  • If both files exist and the plugin is installed from a package, requirements.post-install.txt is processed first.
  • If defer_dependency_install is also enabled, ensure packages required after installation are present in requirements.txt, because that later install rebuilds site-packages.

Development Caveat

At the time of writing, the local plugin reload workflow used during development installs requirements.txt directly when you reload plugins from disk. The requirements.post-install.txt behavior described above is part of the packaged plugin install path.

Because of this:

  • Keep development dependencies in requirements.txt if you rely on --reload-plugins during local plugin development.
  • Treat requirements.post-install.txt as an install-time feature for packaged plugin installs.
  • If you use defer_dependency_install, test both local development reloads and packaged plugin installation so you verify the behavior you expect in both paths.

Directory: static (optional)

Location of any static assets to be served via the webserver.

Assets located in this directory will be available via the webserver at /unmanic/panel/{plugin ID}/static/(.*).

Plugin Module

The plugin.py file is a stand-alone Python module. From this module you may import other modules as you see fit. There is no limitation on what may be executed within the runner of your Plugin.


Runners

The Plugin module is made up of defined runner functions. A Plugin may include multiple runner functions such that it is executed at multiple stages of the library optimisation process.

A data parameter is provided to the runner functions. This data parameter is a dictionary object of information pertaining to that stage of the library optimisation process. This data object's schema that is provided to a plugin runner should still exist once the plugin runner function has completed execution. During the function, that data may be manipulated as you see fit. A plugin runner may fail if data is removed from that data dictionary.

Plugins should be tested with the Plugin Manager CLI before publishing changes to ensure that the returned data matches the required schema for all included runner functions.

Example:
def on_worker_process(data):
...
return
Runner TypeDocumentation
on_library_management_file_testLINK
on_worker_processLINK
on_postprocessor_file_movementLINK
on_postprocessor_task_resultsLINK
render_frontend_panelLINK
render_plugin_apiLINK