Surfaces¶
A plugin declares where it may appear and hands over a description of what it wants. Podlibre builds the widgets from a fixed vocabulary and sends back events. A plugin cannot draw anything Podlibre cannot name — which is the price of never being able to freeze the window, and the reason writing a plugin needs no knowledge of a widget toolkit.
Where a plugin can land¶
| Surface | Lands | Typical use |
|---|---|---|
screen |
A full page in the content area, opened from a workflow step | An importer |
editor_pane |
A pane in the episode editor, beside tracks and transcript | Chapters |
side_panel |
The inspector on the right, while a given screen is open | Audio filters |
dialog |
A modal form, for a short question | Publishing settings |
palette |
Commands in the command palette, invisible until searched | A show-notes writer |
field_editor |
The widget used wherever a field it declares is edited | Any plugin adding a field |
The widget vocabulary¶
| Widget | For |
|---|---|
heading, text |
Saying something |
input, url, number, choice, switch |
Asking something |
list |
Rows the user can pick from |
button |
Running one of your commands |
progress |
A task's state, bound to a task id |
separator |
Shape |
A widget with an id contributes its value to the command it triggers. Strings beginning @ are
looked up in the plugin's own translation catalogue.
A list marked selectable = true contributes what the user chose. It arrives under
selection_as if the widget names one, and under <id>_selected otherwise — so a list called
episodes whose command wants guids says:
Saying what a row looks like¶
Podlibre fills a list from the key of the same name in whatever your command returned. It does
not know what your rows contain, so the view says which key to show, which to add after it, and
which identifies the row:
[[widgets]]
kind = "list"
id = "episodes"
selectable = true
selection_as = "guids"
text_key = "title" # the row's main text
detail_keys = ["pub_date", "duration"] # appended after it, separated by dots
value_key = "guid" # what the selection sends to the command
The defaults are text_key = "title" and value_key = "id", with no details. A row that is a
plain string rather than a table is drawn as itself and sends itself.
A command is called with the arguments it accepts, and no others. A screen offers every field
on it, and most commands want two of them; passing the lot would mean adding a field to a view
breaks a command that never asked for it. A command taking **kwargs gets everything. A missing
required argument still fails loudly, because that is a real mistake rather than a tidy-up.
What comes back¶
A command's return value is matched to the view by name: a key called episodes fills the list
with that id, a key called progress moves that bar. Two keys are special:
| Key | Effect |
|---|---|
message |
Written under the screen as the status line |
Podlibre does not compose that sentence for you, and it should not: only your plugin knows whether twelve means episodes, minutes or failures, and only your catalogue has the words in the user's language. Translate it yourself and return it:
A command that returns nothing leaves the status line empty, which is the right outcome for a command whose effect is visible on screen anyway.
The escape hatch, and who gets it¶
Built-in plugins that need real drawing — the editor's waveform, the player's scrubber — are
marked native and do run in the UI process. That flag is not available to installed plugins.
The two that use it ship with Podlibre and are reviewed like the shell itself.
If the vocabulary cannot express something your plugin genuinely needs, that is worth an issue: the intended answer is a new surface kind that everyone gets, not an exception for one plugin.