@vestra-player/sdk 1.5.18 → 1.5.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/llms-full.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @vestra-player/sdk 1.5.18: full reference
1
+ # @vestra-player/sdk 1.5.20: full reference
2
2
 
3
3
  > Everything needed to write a Vestra Player plugin (plugin API `vestra/1`): the guides, every public declaration of `@vestra-player/sdk` and `@vestra-player/sdk/testing` with its documentation, and the complete source of the example plugins. Generated from the SDK's sources by scripts/llms.mjs; the short index is llms.txt.
4
4
 
@@ -583,6 +583,23 @@ Play/pause, stop, previous/next, frame steps, relative seeks, speed, volume and
583
583
 
584
584
  The difference from the `Player` methods: a `Player` control is a precise operation the plugin is responsible for (conditional, silent, its own error handling); a core action is the user's action, performed on the plugin's behalf. The action ids, menu places and default keys are in Reference: commands; how keys reach them is in Commands, menus and key bindings.
585
585
 
586
+ ##### Step seeks: exact or keyframe
587
+
588
+ ← / → (`seek-backward` / `seek-forward`) seek by the step that player.setStepSeek sets (5 s by default). By default they land on the exact time, which on a file with keyframes far apart means decoding from the previous keyframe first: a visible stall on 4K video. `setStepSeek({ seconds, keyframes: true })` (player 0.5.1, SDK 1.5.19) makes them land on a keyframe instead: forward on the first keyframe at or after position + step, backward on the last at or before position − step, and every press moves. Presses during a seek add up and continue from where it landed, and the on-screen text shows the landed time. Sources without moving video still seek exactly. The seek bar, `player.seek`, scrubs, chapters, loops and `player.step` are never affected.
589
+
590
+ For more steps of your own (Ctrl+→ and the like), call `plugin.host.run("seek-forward", { seconds: 30 })`: the same checks, mode, accumulation and text as →. In keyframe mode it resolves once the seek has landed, so `player.state.position` is current afterwards; do not show your own text for it. Set `"minPlayerVersion": "0.5.1"` when you rely on either option: older players ignore them.
591
+
592
+ ```ts
593
+ const keyframes = true; // the plugin's own setting
594
+ await plugin.player.setStepSeek({ seconds: 5, keyframes });
595
+ const seek = (delta: number) =>
596
+ plugin.host.run(delta < 0 ? "seek-backward" : "seek-forward", {
597
+ seconds: Math.abs(delta),
598
+ });
599
+ ```
600
+
601
+ In tests, `TestHost.keyframes` models the source's keyframes, and `host.coreSeeks` records each step seek with where it landed.
602
+
586
603
  ## Concept: Video and audio processing
587
604
 
588
605
  A plugin can change what the user sees and hears in three different places. They look alike in the API (each is a handle with `set`, a `status` and `onStatus`), but they act at different stages and have different owners, so choosing the right one matters:
@@ -856,7 +873,8 @@ export component ListPanel inherits Rectangle {
856
873
  ##### Names and values
857
874
 
858
875
  - Write names in camelCase or kebab-case in TypeScript: the SDK turns every capital letter into `-` plus the lower-case letter (`canMark` → `can-mark`, `strengthChanged` → `strength-changed`). Fields inside struct values are **not** converted, so spell struct fields exactly as the Slint struct does (and without `_`, which Slint treats as `-`).
859
- - Values must be JSON: booleans, numbers, strings, arrays (Slint models) and objects (Slint structs). Two exceptions: an image from ui.image, only as the **whole** value of an `image` property (nested in an array or object it is `invalid`), and a document from ui.markdown wherever the Slint type is `[MarkdownBlock]`: the whole value, or (SDK 1.5.4, the player after 0.4.0) a field at any depth, such as the `body` of each message in a chat list.
876
+ - Values must be JSON: booleans, numbers, strings, arrays (Slint models) and objects (Slint structs). Two exceptions: an image from ui.image or ui.remoteImage wherever the Slint type is `image`: the whole value, or (SDK 1.5.19, player 0.5.1) a field at any depth, such as the logo of each row of a list; and a document from ui.markdown wherever the Slint type is `[MarkdownBlock]`: the whole value, or (SDK 1.5.4, the player after 0.4.0) a field at any depth, such as the `body` of each message in a chat list.
877
+ - Images in rows: give small pictures `maxSide` (about twice the drawn size, `64` for a 32 px logo), so that the player decodes them small. The images nested in one view's values may show at most 32 MB of decoded pixels together; a write past that is refused with `limit`. A nested image whose file fails the player's checks is drawn empty, and the rest of the row is shown. Rows with images update in place, so a `ListView` keeps its scroll position when the list is written again.
860
878
  - Every name must exist in the Slint file. Writing a property the file does not declare makes a tool window's `show()` or a panel's `ready` fail, and in a settings page it keeps the Options window from opening; for a tool window, so does a callback bound with `on()` that the file does not declare. Once the view is open, such writes are reported to onError.
861
879
 
862
880
  ##### set, bind and the update pass
@@ -2157,7 +2175,7 @@ The table lists the API whose documentation names a player version, newest last:
2157
2175
  | 0.4.1 | PluginError, FileResolverOptions, PackageCandidate.install, PluginWarning.code, Packages.validate |
2158
2176
  | 0.4.2 | Resolvers.fileTypes, Resolvers.onFileTypesChange |
2159
2177
  | 0.4.3 | CommandOptions.path, PropValue, View.set, Appearance.setLanguage, TemplateArgs, Text, ConfirmOptions.args, OsdPanel.set, OsdPanelOptions.maxColumns, Osd.show |
2160
- | 0.5.1 | SlotState.reason, Panel.setInteraction, PlaybackStats.presentedFps |
2178
+ | 0.5.1 | ImageRef, ImageOptions.maxSide, PropValue, Ui.image, Ui.remoteImage, SlotState.reason, Panel.setInteraction, PlaybackStats.presentedFps, Player.setStepSeek, Host.run, Packages.reload |
2161
2179
 
2162
2180
  The Slint library carries no version tags: `Theme.danger` needs player 0.3.0; `@vestra/icons.slint` and the palette `vestra-light` need 0.4.0 (Theme).
2163
2181
 
@@ -2178,7 +2196,7 @@ A plugin lists what it may do in the manifest's `capabilities` (Manifest). A cal
2178
2196
  | `ui.window` | Windows.create | — | Open tool windows | |
2179
2197
  | `ui.mount` | Panels.mount, Panels.bottom, Panels.sidebar, Panels.backdrop, PanelSlot.onChange, Panel.onChange, BackdropSlot.onChange | — | Show panels in the bottom bar, the sidebar or behind the video | |
2180
2198
  | `ui.dialog` | Dialogs.confirm, Dialogs.openFile, Dialogs.openFiles, Dialogs.openDirectory, Dialogs.saveFile | — | Show file pickers and confirmations | |
2181
- | `plugins.manage` | Packages.validate, Packages.validateArchive, Packages.setEnabled, Packages.uninstall | — | Install, uninstall and disable other plugins | yes |
2199
+ | `plugins.manage` | Packages.validate, Packages.validateArchive, Packages.setEnabled, Packages.reload, Packages.uninstall | — | Install, uninstall and disable other plugins | yes |
2182
2200
  | `processing.video` | Plugin.video.filter, Plugin.video.view, Plugin.video.render | `playback.read` | Process the picture (filters, shaders) | |
2183
2201
  | `processing.audio` | Plugin.audio.filter | `playback.read`, `events` | Process the sound | |
2184
2202
  | `subtitles.read` | Subtitles.state, Subtitles.onChange, Subtitles.refresh | — | Read subtitles | |
@@ -2651,7 +2669,6 @@ Every command the player (`host`) and its built-in plugins register when the pla
2651
2669
  | Settings ▸ Keyboard Shortcuts… | | `vestra.hotkeys/keys` |
2652
2670
  | Settings ▸ Mouse… | | `vestra.hotkeys/mouse` |
2653
2671
  | Settings ▸ Ignore Default Shortcuts | | `vestra.hotkeys/ignore-defaults` |
2654
- | Settings ▸ Plugin Manager… | | `vestra.plugins/manage` |
2655
2672
  | Settings ▸ Appearance ▸ Vestra Dark | | `vestra.preferences/theme.vestra` |
2656
2673
  | Settings ▸ Appearance ▸ Vestra Light | | `vestra.preferences/theme.vestra-light` |
2657
2674
  | Settings ▸ Appearance ▸ Show Logo When Idle | | `vestra.visualizer/idle-logo` |
@@ -3537,6 +3554,20 @@ interface ImageRef {
3537
3554
  }
3538
3555
  ```
3539
3556
 
3557
+ ### ImageOptions
3558
+
3559
+ Options of Ui.image and Ui.remoteImage.
3560
+
3561
+ ```ts
3562
+ interface ImageOptions {
3563
+ /**
3564
+ * Decode the image scaled down, aspect kept, so that neither side is over this many pixels (an integer 1–4096); smaller images stay as they are. Use about twice the drawn size (64 for a 32 px logo) so that it stays sharp on high-density screens. It keeps the decoded memory small: a 1024×1024 icon is 4 MB decoded, 16 KB at `maxSide: 64`.
3565
+ * @player 0.5.1; older players refuse the reference (`invalid`).
3566
+ */
3567
+ maxSide?: number;
3568
+ }
3569
+ ```
3570
+
3540
3571
  ### MarkdownRef
3541
3572
 
3542
3573
  A Markdown document for `MarkdownView` or `MarkdownBlocks`, made by
@@ -3571,9 +3602,8 @@ interface MarkdownOptions {
3571
3602
 
3572
3603
  ### PropValue
3573
3604
 
3574
- The value of one Slint property: JSON with Markdown documents at any
3575
- depth (PropData), or an image as the whole value of an `image`
3576
- property.
3605
+ The value of one Slint property: JSON with Markdown documents and images
3606
+ at any depth (PropData).
3577
3607
 
3578
3608
  ```ts
3579
3609
  type PropValue = PropData | ImageRef;
@@ -3581,11 +3611,11 @@ type PropValue = PropData | ImageRef;
3581
3611
 
3582
3612
  ### PropData
3583
3613
 
3584
- JSON whose values may also be Markdown documents, at any depth: the part
3585
- of PropValue that nests.
3614
+ JSON whose values may also be Markdown documents and (SDK 1.5.19) images,
3615
+ at any depth: the part of PropValue that nests.
3586
3616
 
3587
3617
  ```ts
3588
- type PropData = null | boolean | number | string | MarkdownRef | Text | TextList | PropData[] | {
3618
+ type PropData = null | boolean | number | string | MarkdownRef | ImageRef | Text | TextList | PropData[] | {
3589
3619
  [key: string]: PropData;
3590
3620
  };
3591
3621
  ```
@@ -3611,10 +3641,22 @@ interface Ui {
3611
3641
  * Reference a PNG or JPEG file for an `image` property.
3612
3642
  * @capability None.
3613
3643
  * @param path - Absolute path of the image file, inside the package directory or the data directory.
3644
+ * @param options - `maxSide` (SDK 1.5.19, player 0.5.1): decode the image scaled down, aspect kept, so that neither side is over it.
3614
3645
  * @returns A new ImageRef, owned by this scope.
3615
- * @throws invalid (throws) `path` is not a non-empty string.
3646
+ * @throws invalid (throws) `path` is not a non-empty string, or `maxSide` is not an integer 1–4096.
3616
3647
  */
3617
- image(path: string): ImageRef;
3648
+ image(path: string, options?: ImageOptions): ImageRef;
3649
+ /**
3650
+ * Download an `https:` PNG or JPEG image (a thumbnail, a repository's plugin icon) and reference the local copy, as Ui.image does.
3651
+ * @capability None (the plugin process has network access).
3652
+ * @player Any (the reference is an ordinary ImageRef); nested in a value, player 0.5.1.
3653
+ * @param url - The image's `https:` address.
3654
+ * @param options - As for Ui.image.
3655
+ * @returns The reference, owned by this scope, once the file is in the cache.
3656
+ * @throws invalid (rejects) `url` is not an `https:` address, or `maxSide` is not an integer 1–4096.
3657
+ * @throws unavailable (rejects) the download failed, timed out, was too large, or is not a PNG or JPEG image; or the plugin has no data directory.
3658
+ */
3659
+ remoteImage(url: string, options?: ImageOptions): Promise<ImageRef>;
3618
3660
  /**
3619
3661
  * Prepare a Markdown document for `MarkdownView` (`@vestra/markdown.slint`).
3620
3662
  * @capability None.
@@ -5181,10 +5223,28 @@ interface Player {
5181
5223
  */
5182
5224
  step(unit: "frame" | "keyframe", direction: "backward" | "forward", options?: Conditional): Promise<void>;
5183
5225
  /**
5184
- * The core's first-tier relative seek (`seek-backward` / `seek-forward`, ← / →): 0.1–3600 seconds in tenths, default 5. The newest call of any plugin wins; it reverts when that plugin stops.
5226
+ * The core's first-tier relative seek (`seek-backward` / `seek-forward`,
5227
+ * ← / →): 0.1–3600 seconds in tenths, default 5. The newest call of any
5228
+ * plugin wins; it reverts when that plugin stops.
5229
+ *
5230
+ * `keyframes: true` (player 0.5.1, SDK 1.5.19): the step seeks
5231
+ * (`seek-backward` / `seek-forward`, including Host.run with
5232
+ * `seconds` and the picture-in-picture skips) land on a keyframe instead
5233
+ * of the exact time: forward on the first keyframe at or after position +
5234
+ * step, backward on the last at or before position − step, and they
5235
+ * always move. Presses during a seek add up and continue from where it
5236
+ * landed; the on-screen text shows the landed time. Sources without moving
5237
+ * video seek exactly. The seek bar, Player.seek, scrubs, chapters,
5238
+ * loops and Player.step are unaffected. Omitted or `false`: exact
5239
+ * seeks, as before. `seconds` and `keyframes` are written as a pair: the
5240
+ * newest call sets both.
5241
+ *
5242
+ * Older players ignore `keyframes`: set `"minPlayerVersion": "0.5.1"` in
5243
+ * the manifest when you rely on it.
5185
5244
  */
5186
5245
  setStepSeek(options: {
5187
5246
  seconds: number;
5247
+ keyframes?: boolean;
5188
5248
  }): Promise<void>;
5189
5249
  /** The chapters of the current media (empty without media or chapters), read on demand; `sourceId` tells which source they belong to. `playback.read`. */
5190
5250
  chapters(): Promise<{
@@ -5226,7 +5286,7 @@ The core's basic playback actions (menu commands owned by the player).
5226
5286
  | `play-pause` | Space | pause / resume, replay after the end |
5227
5287
  | `previous` / `next` | PageUp, Mouse:X1 / PageDown, Mouse:X2 | ask the sequence provider |
5228
5288
  | `frame-back` / `frame-forward` | D / F | `player.step("frame", …)` |
5229
- | `seek-backward` / `seek-forward` | ← / → | relative seek by `setStepSeek` seconds |
5289
+ | `seek-backward` / `seek-forward` | ← / → | relative seek by `setStepSeek` seconds (or `host.run`'s `seconds`), exact or to keyframes as `setStepSeek` says |
5230
5290
  | `rate-normal`, `rate-down`, `rate-up` | Z, X, C | 1×, ±0.1 within 0.25–4 |
5231
5291
  | `volume-up` / `volume-down` | ↑ / ↓, wheel | ±5 (`volume-up` stops at 100) |
5232
5292
  | `mute` | M | toggle mute |
@@ -5252,6 +5312,23 @@ interface Host {
5252
5312
  * Prefer this over reimplementing playback buttons.
5253
5313
  */
5254
5314
  run(action: HostAction): Promise<void>;
5315
+ /**
5316
+ * One step seek of `seconds` (0.1–3600 in tenths) instead of the
5317
+ * Player.setStepSeek step: the same checks, mode (exact or
5318
+ * keyframes), accumulation and on-screen text as ← / →. Use it for more
5319
+ * seek steps of your own (Ctrl+→ and the like) so that they add up with
5320
+ * the core's and land the same way.
5321
+ *
5322
+ * In keyframe mode it resolves once the seek has landed (so
5323
+ * `player.state.position` is current after the `await`); presses that add
5324
+ * up resolve together, the last with the text. In exact mode it resolves
5325
+ * once the seek is submitted, as before. `invalid` for `seconds` out of
5326
+ * range.
5327
+ * @player 0.5.1 (set `"minPlayerVersion": "0.5.1"`: older players ignore `seconds` and seek by the `setStepSeek` step)
5328
+ */
5329
+ run(action: "seek-backward" | "seek-forward", options: {
5330
+ seconds: number;
5331
+ }): Promise<void>;
5255
5332
  }
5256
5333
  ```
5257
5334
 
@@ -6092,6 +6169,23 @@ interface Packages {
6092
6169
  * Stop or start a plugin (`plugins.manage`). An installed plugin stays disabled across launches; a development load only for this run. `invalid` to disable oneself, `missing` unknown. `busy` while it is being installed. `unsupported` to disable a built-in (PluginInfo.builtin): users manage third-party plugins only (players released with SDK 1.5.18 on; older ones disabled built-ins too).
6093
6170
  */
6094
6171
  setEnabled(id: string, enabled: boolean): Promise<void>;
6172
+ /**
6173
+ * Restart a plugin (`plugins.manage`): stop it and start it again from the
6174
+ * same package with the same data directory, for example to recover one
6175
+ * that misbehaves. Built-ins included. A stopped or failed plugin is just
6176
+ * started. The disabled flag is never written, so a reload never leaves
6177
+ * a plugin disabled.
6178
+ *
6179
+ * Resolves once the plugin is stopped and its start is scheduled; the
6180
+ * player starts it as soon as the old process is gone (at most 20 s).
6181
+ * Follow it with Packages.onChange: `starting`, then `running`,
6182
+ * or `failed` with the reason.
6183
+ *
6184
+ * `invalid` for oneself or a disabled plugin (enable it instead),
6185
+ * `missing` unknown, `busy` while it is being installed or reloaded.
6186
+ * @player 0.5.1; older players reject it as an unknown request (`unsupported`).
6187
+ */
6188
+ reload(id: string): Promise<void>;
6095
6189
  /**
6096
6190
  * Remove an installed plugin (`plugins.manage`); `removeData` also deletes its data directory, otherwise reinstalling it from the same source reconnects to its data. Its user bindings stay (as orphans). `unsupported` for built-ins and development loads, `missing` unknown, `invalid` for oneself.
6097
6191
  */
@@ -6991,12 +7085,16 @@ class TestHost implements Transport {
6991
7085
  kind: string;
6992
7086
  title?: string | null;
6993
7087
  }[]): void;
6994
- /** Runtime images written to views (`plugin.ui.image`), newest last. The SDK refuses images of released scopes before anything is sent. */
7088
+ /**
7089
+ * Runtime images written to views (`plugin.ui.image`, `plugin.ui.remoteImage`), whole values and (SDK 1.5.19) images nested in rows, newest last. The SDK refuses images of released scopes before anything is sent. The test host does not read the files, so it does not check the player's per-view budget (`IMAGE_LIMITS.viewBytes`).
7090
+ */
6995
7091
  readonly images: {
6996
7092
  /** The image file's path, as given to `ui.image`. */
6997
7093
  path: string;
6998
7094
  /** The SDK's reference number for that `ImageRef`. */
6999
7095
  ref: number;
7096
+ /** Its `maxSide` option, when given. */
7097
+ maxSide?: number;
7000
7098
  }[];
7001
7099
  /**
7002
7100
  * The file an image property shows, or `null` when the value is not a runtime image. View properties hold images in their wire form; this reads the path back.
@@ -7317,6 +7415,25 @@ class TestHost implements Transport {
7317
7415
  constructor();
7318
7416
  /** The `player.setStepSeek` value in effect (default 5). */
7319
7417
  stepSeek: number;
7418
+ /** The `player.setStepSeek` `keyframes` in effect (default `false`, SDK 1.5.19). */
7419
+ stepSeekKeyframes: boolean;
7420
+ /**
7421
+ * Test data: the keyframe times (seconds, ascending) of the current source, for keyframe step seeks. `null` (the default): none modelled, and step seeks are exact even with `stepSeekKeyframes`.
7422
+ */
7423
+ keyframes: number[] | null;
7424
+ /**
7425
+ * Every step seek the core ran (`seek-backward` / `seek-forward`, from a key, the menu or `host.run`), newest last: the step, whether it went to a keyframe, and where it landed.
7426
+ */
7427
+ readonly coreSeeks: {
7428
+ /** `seek-backward` or `seek-forward`. */
7429
+ action: string;
7430
+ /** The step: `host.run`'s `seconds`, else `setStepSeek`'s. */
7431
+ seconds: number;
7432
+ /** It landed on a keyframe (`stepSeekKeyframes` and keyframes modelled). */
7433
+ keyframes: boolean;
7434
+ /** The new position. */
7435
+ landed: number;
7436
+ }[];
7320
7437
  /** Every `player.step`, newest last. */
7321
7438
  readonly steps: {
7322
7439
  /** `"frame"` or `"keyframe"`. */
@@ -7430,7 +7547,7 @@ class TestHost implements Transport {
7430
7547
  /** Every `packages.setEnabled` / `uninstall` / `install`, newest last. */
7431
7548
  readonly packageCalls: {
7432
7549
  /** Which call. */
7433
- method: "setEnabled" | "uninstall" | "install";
7550
+ method: "setEnabled" | "reload" | "uninstall" | "install";
7434
7551
  /** The target plugin id. */
7435
7552
  id: string;
7436
7553
  /** `setEnabled`'s value. */
@@ -7447,7 +7564,7 @@ class TestHost implements Transport {
7447
7564
  */
7448
7565
  readonly candidates: Map<string, PackageManifest>;
7449
7566
  /**
7450
- * Remote Markdown images (`plugin.ui.markdown`): address → a local PNG or JPEG file served for it, or `null` for a failing download. Nothing is fetched from the network in tests; unknown addresses fail.
7567
+ * Remote images (`plugin.ui.markdown`, `plugin.ui.remoteImage`): address → a local PNG or JPEG file served for it, or `null` for a failing download. Nothing is fetched from the network in tests; unknown addresses fail.
7451
7568
  */
7452
7569
  readonly remoteImages: Map<string, string | null>;
7453
7570
  /**
@@ -7876,6 +7993,25 @@ const UI_VALUE_LIMITS: {
7876
7993
  };
7877
7994
  ```
7878
7995
 
7996
+ ### IMAGE_LIMITS
7997
+
7998
+ The player's runtime image limits (`host/src/ui_image.rs`): a file's
7999
+ bytes and sides, the decoded pixels each plugin caches, and (SDK 1.5.19,
8000
+ player 0.5.1) the decoded pixels the nested images of one view may show.
8001
+
8002
+ ```ts
8003
+ const IMAGE_LIMITS: Readonly<{
8004
+ /** The largest image file the player reads, in bytes. */
8005
+ fileBytes: number;
8006
+ /** The longest side, in pixels, the player accepts for an image file. */
8007
+ side: 4096;
8008
+ /** The decoded pixel bytes the player caches for each plugin's images. */
8009
+ pluginBytes: number;
8010
+ /** The decoded pixel bytes the nested images of one view may show (player 0.5.1). */
8011
+ viewBytes: number;
8012
+ }>;
8013
+ ```
8014
+
7879
8015
  ### HostError
7880
8016
 
7881
8017
  A definite refusal from the player (or the plugin runner), with a stable
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # Vestra Player SDK
2
2
 
3
- > @vestra-player/sdk 1.5.18: write plugins for Vestra Player in TypeScript (plugin API `vestra/1`). A plugin is a folder with `manifest.json` and an entry module whose default export `activate(plugin)` the player calls; it runs in its own Node.js process. Everything a plugin creates (commands, windows, panels, filters, listeners…) is a handle that is released automatically when the plugin stops. L<n> are line numbers in llms-full.txt, next to this file: every page, declaration and example.
3
+ > @vestra-player/sdk 1.5.20: write plugins for Vestra Player in TypeScript (plugin API `vestra/1`). A plugin is a folder with `manifest.json` and an entry module whose default export `activate(plugin)` the player calls; it runs in its own Node.js process. Everything a plugin creates (commands, windows, panels, filters, listeners…) is a handle that is released automatically when the plugin stops. L<n> are line numbers in llms-full.txt, next to this file: every page, declaration and example.
4
4
 
5
5
  **Rules**
6
6
 
@@ -33,7 +33,7 @@ my-plugin/
33
33
  }
34
34
  ```
35
35
 
36
- Fields: `id`, `version`, `apiVersion`, `entry`, `capabilities`, `name`, `author`, `punchline`, `description`, `tags`, `icon`, `readme`, `changelog`, `sourceUrl`, `license`, `minPlayerVersion`; unknown fields and capabilities are rejected. Rules and limits: L2102–2165.
36
+ Fields: `id`, `version`, `apiVersion`, `entry`, `capabilities`, `name`, `author`, `punchline`, `description`, `tags`, `icon`, `readme`, `changelog`, `sourceUrl`, `license`, `minPlayerVersion`; unknown fields and capabilities are rejected. Rules and limits: L2120–2183.
37
37
 
38
38
  **main.ts**
39
39
 
@@ -60,7 +60,7 @@ export default async function activate(plugin: Plugin) {
60
60
  - `ui.window`: Windows.create
61
61
  - `ui.mount`: Panels.mount/bottom/sidebar/backdrop, PanelSlot/Panel/BackdropSlot.onChange
62
62
  - `ui.dialog`: Dialogs.confirm/openFile/openFiles/openDirectory/saveFile
63
- - `plugins.manage`: Packages.validate/validateArchive/setEnabled/uninstall
63
+ - `plugins.manage`: Packages.validate/validateArchive/setEnabled/reload/uninstall
64
64
  - `processing.video`: Plugin.video.filter/video.view/video.render (also `playback.read`)
65
65
  - `processing.audio`: Plugin.audio.filter (also `playback.read`, `events`)
66
66
  - `subtitles.read`: Subtitles.state/onChange/refresh
@@ -76,9 +76,9 @@ export default async function activate(plugin: Plugin) {
76
76
  - `ui.settings`: Settings.page/show
77
77
  - `ui.theme`: Appearance.set/setLanguage
78
78
  - `secrets`: Secrets.get/set/delete
79
- - No capability: `tools`, `storage`, `system`, `app`, `ui` (images and Markdown), `i18n`, reading window.state, appearance.theme and packages.list. Details: L2166–2208.
79
+ - No capability: `tools`, `storage`, `system`, `app`, `ui` (images and Markdown), `i18n`, reading window.state, appearance.theme and packages.list. Details: L2184–2226.
80
80
 
81
- **Test**: `tests/*.test.ts` with `node:test`, run by `vestra-plugin test`. `startPlugin(activate, { directory: new URL("..", import.meta.url) })` from `@vestra-player/sdk/testing` returns `{ host, stop }`; `host` is a TestHost (an in-memory player): `host.setSource(…)`, `host.command(id).run()`, `host.press(key)`, `await host.settle()`, then assert on `host.osd`, `host.window(id).props`… Guide: L1588–1753; TestHost: L6751.
81
+ **Test**: `tests/*.test.ts` with `node:test`, run by `vestra-plugin test`. `startPlugin(activate, { directory: new URL("..", import.meta.url) })` from `@vestra-player/sdk/testing` returns `{ host, stop }`; `host` is a TestHost (an in-memory player): `host.setSource(…)`, `host.command(id).run()`, `host.press(key)`, `await host.settle()`, then assert on `host.osd`, `host.window(id).props`… Guide: L1606–1771; TestHost: L6845.
82
82
 
83
83
  **Command line**
84
84
 
@@ -106,39 +106,39 @@ export default async function activate(plugin: Plugin) {
106
106
  - `limit`: A player-wide limit was reached, a property value is over the limits of PropValue
107
107
  - `reserved`: The id is `vestra` or starts with `vestra.`
108
108
  - `versionMismatch`: The package needs a newer player or another `apiVersion`
109
- - Others: PluginError, llms-full.txt L3105.
109
+ - Others: PluginError, llms-full.txt L3122.
110
110
 
111
111
  ## Reference
112
112
 
113
113
  - [llms-full.txt](https://vestrasys.github.io/vestra-player-sdk/llms-full.txt), also node_modules/@vestra-player/sdk/llms-full.txt; the pages are on the [site](https://vestrasys.github.io/vestra-player-sdk/).
114
114
  - Tutorials: Getting started L9–214
115
- - Concepts: How a plugin runs L215–364; Commands, menus and key bindings L365–462; Playback state, controls and sources L463–585; Video and audio processing L586–663; Windows, panels, settings pages, dialogs and the OSD L664–950
116
- - How-to: Keep a slider responsive while dragging L951–1125; Remember a window's state between runs L1126–1255; Translate a plugin L1256–1439; Migrate a plugin to English source text L1440–1587; Test a plugin L1588–1753; Publish a plugin L1754–1842; Migrating off package rollback (1.5.16, removed in 1.5.17) L1843–1918
117
- - Guidelines: Interface guidelines L1919–2003; Menu guidelines L2004–2101
118
- - Reference: Manifest L2102–2165; Capabilities L2166–2208; Limits L2209–2303; Commands, menus and bindings L2304–2772; Platforms L2773–2801; Theme L2802–3006; Command line L3007–3062
119
- - [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L3063–6586
120
- - [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L6587–7909
115
+ - Concepts: How a plugin runs L215–364; Commands, menus and key bindings L365–462; Playback state, controls and sources L463–602; Video and audio processing L603–680; Windows, panels, settings pages, dialogs and the OSD L681–968
116
+ - How-to: Keep a slider responsive while dragging L969–1143; Remember a window's state between runs L1144–1273; Translate a plugin L1274–1457; Migrate a plugin to English source text L1458–1605; Test a plugin L1606–1771; Publish a plugin L1772–1860; Migrating off package rollback (1.5.16, removed in 1.5.17) L1861–1936
117
+ - Guidelines: Interface guidelines L1937–2021; Menu guidelines L2022–2119
118
+ - Reference: Manifest L2120–2183; Capabilities L2184–2226; Limits L2227–2321; Commands, menus and bindings L2322–2789; Platforms L2790–2818; Theme L2819–3023; Command line L3024–3079
119
+ - [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L3080–6680
120
+ - [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L6681–8045
121
121
 
122
122
  ## API
123
123
 
124
124
  Where each module of `plugin` (`plugin.<module>`) is declared:
125
125
 
126
- - Plugin L3297, Scope L3166, PluginError L3105, Disposable L3078
127
- - Commands L3509; Windows L3714; Panels L4357; Dialogs L4643; Player L5091; video: VideoFilter L5356, VideoView L5419, RenderOptions L5461; audio: AudioFilter L5380; Subtitles L5559; media: MediaCapture L5719; Resolvers L5824; Packages L6066; Osd L5292; Host L5240; Clipboard L6181; Power L6201; Tools L6234; Storage L6277; System L6300; Secrets L6318; window: MainWindow L4480; App L4561; Bindings L6151; Ui L3601; Timeline L4437; Drops L4013; Appearance L4042; I18n L4184; Settings L4290.
126
+ - Plugin L3314, Scope L3183, PluginError L3122, Disposable L3095
127
+ - Commands L3526; Windows L3756; Panels L4399; Dialogs L4685; Player L5133; video: VideoFilter L5433, VideoView L5496, RenderOptions L5538; audio: AudioFilter L5457; Subtitles L5636; media: MediaCapture L5796; Resolvers L5901; Packages L6143; Osd L5369; Host L5300; Clipboard L6275; Power L6295; Tools L6328; Storage L6371; System L6394; Secrets L6412; window: MainWindow L4522; App L4603; Bindings L6245; Ui L3631; Timeline L4479; Drops L4055; Appearance L4084; I18n L4226; Settings L4332.
128
128
 
129
129
  ## Examples
130
130
 
131
131
  Tested plugins in [examples/](https://github.com/vestrasys/vestra-player-sdk/tree/main/examples):
132
132
 
133
- - hello: The README Quick start: one menu command and an on-screen message. L8333–8422
134
- - blur: A tool window with one slider that blurs the playing video. L8423–8684
135
- - signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L8685–9017
136
- - bookmark: A tool window bound to the playback state: remember the position and jump back to it. L9018–9202
137
- - panel-menu: A sidebar panel with its own right-click menu. L9203–9408
138
- - menus: Radio menu items, separator groups and a menu item whose title changes. L9409–9568
139
- - theme-widgets: A tool window drawn with the player's theme and widgets. L9569–9732
140
- - markdown: A window that shows a Markdown document. L9733–9927
141
- - i18n: A plugin in the player's language: English source text, a Chinese translation. L9928–10095
133
+ - hello: The README Quick start: one menu command and an on-screen message. L8469–8558
134
+ - blur: A tool window with one slider that blurs the playing video. L8559–8820
135
+ - signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L8821–9153
136
+ - bookmark: A tool window bound to the playback state: remember the position and jump back to it. L9154–9338
137
+ - panel-menu: A sidebar panel with its own right-click menu. L9339–9544
138
+ - menus: Radio menu items, separator groups and a menu item whose title changes. L9545–9704
139
+ - theme-widgets: A tool window drawn with the player's theme and widgets. L9705–9868
140
+ - markdown: A window that shows a Markdown document. L9869–10063
141
+ - i18n: A plugin in the player's language: English source text, a Chinese translation. L10064–10231
142
142
 
143
143
  ## Optional
144
144
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vestra-player/sdk",
3
- "version": "1.5.18",
3
+ "version": "1.5.20",
4
4
  "description": "Plugin API types, test host and plugin CLI for Vestra Player (apiVersion vestra/1)",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {