@vestra-player/sdk 1.5.44 → 1.5.46
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/CHANGELOG.md +26 -0
- package/bin/vestra-plugin.mjs +59 -1
- package/dist/plugin/index.js +4 -1
- package/dist/plugin/patch.d.ts +52 -1
- package/dist/plugin/patch.js +104 -6
- package/dist/plugin/player.d.ts +11 -0
- package/dist/plugin/player.js +80 -7
- package/dist/plugin/runtime.d.ts +58 -1
- package/dist/plugin/runtime.js +216 -16
- package/dist/plugin/scope.d.ts +9 -1
- package/dist/plugin/scope.js +24 -0
- package/dist/plugin/testing.d.ts +7 -0
- package/dist/plugin/testing.js +67 -3
- package/dist/plugin/types.d.ts +41 -29
- package/dist/plugin/ui.d.ts +13 -3
- package/dist/plugin/ui.js +184 -16
- package/dist/plugin/values.d.ts +21 -36
- package/dist/plugin/values.js +22 -37
- package/dist/wire.d.ts +3 -0
- package/llms-full.txt +92 -76
- package/llms.txt +23 -23
- package/package.json +1 -1
package/llms-full.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @vestra-player/sdk 1.5.
|
|
1
|
+
# @vestra-player/sdk 1.5.46: 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
|
|
|
@@ -1903,6 +1903,8 @@ host.handle("processing.replace", () => {
|
|
|
1903
1903
|
|
|
1904
1904
|
`await host.settle()` after every action that makes the plugin talk to the player; `host.settle(400)` also lets debounces and timers due by then fire. Then assert on what the host recorded: `host.window(id).props` (kebab-case names), `host.command(id).state`, `host.osd`, `host.source`.
|
|
1905
1905
|
|
|
1906
|
+
`settle` does not wait for the once-a-second full update pass (SDK 1.5.45): after `host.setSource(...)` only the bindings that read a changed field of `plugin.player.state` run again. A value your plugin changed outside a handler (a timer, a promise continuation, a child process) without `plugin.update()` shows in the next full pass, at most about a second later; call `plugin.update()` in the plugin after such a change, or wait `await host.settle(1000)` in the test.
|
|
1907
|
+
|
|
1906
1908
|
`settle` waits only for calls to the player. Work the plugin does on its own (reading or parsing a file, a child process, a network request) can finish later on a loaded machine; poll the value you assert on instead:
|
|
1907
1909
|
|
|
1908
1910
|
```ts nocheck
|
|
@@ -2282,6 +2284,7 @@ The table lists the API whose documentation names a player version, newest last:
|
|
|
2282
2284
|
| 0.5.20 | VideoShaders |
|
|
2283
2285
|
| 0.5.21 | Scope.when, When, Bindings.onChange |
|
|
2284
2286
|
| 0.5.25 | UpscalingReason.cause, UpscalingReason.plugins, UpscalingDecodingCause, UpscalingPlugin, UpscalingVideoSize, UpscalingState.video, UpscalingState.area, UpscalingState.gpu, UpscalingState.hwdecCurrent, UpscalingState.inChain, VideoUpscaling.onChange |
|
|
2287
|
+
| 0.6.0 | PropValue |
|
|
2285
2288
|
|
|
2286
2289
|
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).
|
|
2287
2290
|
|
|
@@ -2350,7 +2353,7 @@ The check follows types, not names: `plugin.player.seek`, `const { player } = pl
|
|
|
2350
2353
|
|
|
2351
2354
|
## Reference: Limits
|
|
2352
2355
|
|
|
2353
|
-
The player bounds what one request may cost it. The limits are guards against runaway plugins, not sizes to aim for: a
|
|
2356
|
+
The player bounds what one request may cost it. The limits are guards against runaway plugins, not sizes to aim for. Since player 0.6.0 a whole list fits (50,000 playlist rows): bind it and draw it with a Slint `ListView` (a long list should use one: a `for` builds every row). The SDK sends row patches, and an array property larger than one request in parts (SDK 1.5.46); only a property's top-level array without Markdown documents is split, so any other value, and each row, must fit in one request (a row of more than 512 KiB is refused with `limit`). The SDK checks the same limits before it sends a request, so a plugin's own tests hit them too (TestHost enforces them). A name in code style is a constant you can import from `@vestra-player/sdk/testing`.
|
|
2354
2357
|
|
|
2355
2358
|
#### Commands
|
|
2356
2359
|
|
|
@@ -2378,10 +2381,10 @@ One value written to a window, panel or settings page property (View.set, View.b
|
|
|
2378
2381
|
| Limit | Value | Meaning |
|
|
2379
2382
|
| --- | --- | --- |
|
|
2380
2383
|
| `UI_VALUE_LIMITS.depth` | 8 | Nesting depth; the value itself is depth 0. |
|
|
2381
|
-
| `UI_VALUE_LIMITS.values` |
|
|
2382
|
-
| `UI_VALUE_LIMITS.arrayRows` |
|
|
2384
|
+
| `UI_VALUE_LIMITS.values` | 1048576 | Values in all, counting every array, object, string, number, boolean and null, the value itself included; a Markdown document is one. |
|
|
2385
|
+
| `UI_VALUE_LIMITS.arrayRows` | 100000 | Rows of one array. |
|
|
2383
2386
|
| `UI_VALUE_LIMITS.stringBytes` | 65536 (64 KiB) | UTF-8 bytes of one string or object field name. |
|
|
2384
|
-
| `UI_VALUE_LIMITS.textBytes` |
|
|
2387
|
+
| `UI_VALUE_LIMITS.textBytes` | 33554432 (32 MiB) | UTF-8 bytes of all strings and field names together, the text of the value's Markdown documents included. |
|
|
2385
2388
|
|
|
2386
2389
|
#### Text values
|
|
2387
2390
|
|
|
@@ -3866,14 +3869,18 @@ There is no cleanup function to return from `activate`. Because every resource i
|
|
|
3866
3869
|
A plugin's state is plain variables. The SDK keeps the player in step with it through **bindings** and the **update pass**:
|
|
3867
3870
|
|
|
3868
3871
|
- A binding is a function the SDK calls to get a current value: view.bind(() => props) for a window, panel or settings page, and the function form of a command's `enabled`, `checked`, `busy` and `reason` (Bindable).
|
|
3869
|
-
- In an update pass the SDK calls
|
|
3872
|
+
- In an update pass the SDK calls the bindings of the plugin, compares each result with the value it last sent, and sends only what changed.
|
|
3870
3873
|
|
|
3871
|
-
|
|
3874
|
+
A **full pass** calls every binding. It runs:
|
|
3872
3875
|
|
|
3873
3876
|
- after every handler the SDK calls returns (a command's `run`, a view callback, an `onChange`, `onStatus`, `onEnd` or `onStop` listener), and again when the promise it returned settles;
|
|
3874
|
-
- after the
|
|
3877
|
+
- after the subtitle, window, panel position, timeline, appearance, filter or export state changes;
|
|
3875
3878
|
- when the plugin calls plugin.update().
|
|
3876
3879
|
|
|
3880
|
+
A **precise pass** follows a change of the player state (SDK 1.5.45). While media plays the player sends its state about ten times a second, mostly with only `position` changed. The SDK notes which fields of `plugin.player.state` each binding read the last time it ran (each `view.bind` function on its own; a command's four functions together) and calls only the bindings that read a field that changed. A panel whose list reads nothing of the player state is not rebuilt on every position tick; a label that shows the position is. `player.isCurrent` and `Media.current` count as reading the source. A `player.onChange` listener is followed by a full pass, as above, unless it returned synchronously and read only fields that did not change.
|
|
3881
|
+
|
|
3882
|
+
A precise pass cannot see state the plugin changed by itself. So while precise passes leave bindings out, a full pass follows at least once a second: a variable your own timer changed without `plugin.update()` appears within about a second (before SDK 1.5.45 it usually appeared at the next position tick). Call `plugin.update()` after such a change to show it at once.
|
|
3883
|
+
|
|
3877
3884
|
Several requests within one microtask are merged into one pass, and every target has at most one write in flight: values that change meanwhile are merged into the next write. A binding that changes 60 times a second therefore costs one write per round trip, never a growing queue.
|
|
3878
3885
|
|
|
3879
3886
|
One click, end to end (a bookmark window; the video is at 42 s):
|
|
@@ -3893,7 +3900,7 @@ sequenceDiagram
|
|
|
3893
3900
|
S->>U: the label changes, Jump to bookmark is enabled
|
|
3894
3901
|
```
|
|
3895
3902
|
|
|
3896
|
-
The rule that follows: **state you change outside a handler, or after an `await` inside one, appears only at the next pass.** Changing a variable from your own `setInterval`, a socket callback or the middle of a long task shows nothing until something triggers a
|
|
3903
|
+
The rule that follows: **state you change outside a handler, or after an `await` inside one, appears only at the next full pass.** Changing a variable from your own `setInterval`, a socket callback or the middle of a long task shows nothing until something triggers one (at most about a second while media plays); call `plugin.update()` after such a change. Keep a slider responsive while dragging shows the pattern; How Slint and TypeScript talk explains `set` versus `bind` for views.
|
|
3897
3904
|
|
|
3898
3905
|
#### Stopping
|
|
3899
3906
|
|
|
@@ -4009,7 +4016,7 @@ const toggle = plugin.commands.add({
|
|
|
4009
4016
|
|
|
4010
4017
|
- **The id is the command's identity.** It is unique within the plugin; the player knows the command as `<manifest id>/<id>`. The user's own key bindings are stored under that pair, so changing a title or moving the command to another menu keeps them.
|
|
4011
4018
|
- **`path` puts it in the main menu.** Leave it out for a command that only has bindings or lives in a panel's context menu (Panel.showMenu); it then needs a `title`.
|
|
4012
|
-
- **State is declared, not pushed.** `enabled`, `checked`, `busy` and `reason` are values or functions (Bindable); `enabled` and `checked` may also be conditions from `plugin.when` (below). Functions are evaluated in every update pass and sent only when they change, so the menu's check mark follows the player without a listener you write. Command.set replaces them later.
|
|
4019
|
+
- **State is declared, not pushed.** `enabled`, `checked`, `busy` and `reason` are values or functions (Bindable); `enabled` and `checked` may also be conditions from `plugin.when` (below). Functions are evaluated in every full update pass, and after a player state change only if they read a field that changed; they are sent only when they change, so the menu's check mark follows the player without a listener you write. Command.set replaces them later.
|
|
4013
4020
|
- **The player calls `run` only when it can run.** While a command is disabled or busy, neither its menu item nor its binding calls `run`; `reason` tells the user why (it appears in the menu and, for a key press, on the video).
|
|
4014
4021
|
- **Titles and paths are fixed.** They cannot change in place. A menu that follows changing content (tracks, presets, a radio group) lives in a child scope that is disposed and rebuilt when the content changes; `order` keeps its place (Handles and scopes).
|
|
4015
4022
|
- Disposing the command removes it from the menu and the binding table; the same id can be added again at once. The number of commands per plugin and per player is limited (Reference: limits); the limit stops runaway menus, so cap menus built from media content (tracks, chapters) yourself.
|
|
@@ -4266,7 +4273,7 @@ player.openStream (capability `producer.av`) makes a source whose picture and so
|
|
|
4266
4273
|
|
|
4267
4274
|
#### Next and previous
|
|
4268
4275
|
|
|
4269
|
-
The player's **Previous** and **Next** (menu, keys, the bottom bar) are not tied to a playlist. One plugin at a time can **provide the sequence** with provideSequence, giving `next()`, `previous()` and two flags, `canNext` and `canPrevious`, which are bindings re-evaluated in every update pass.
|
|
4276
|
+
The player's **Previous** and **Next** (menu, keys, the bottom bar) are not tied to a playlist. One plugin at a time can **provide the sequence** with provideSequence, giving `next()`, `previous()` and two flags, `canNext` and `canPrevious`, which are bindings re-evaluated in every full update pass, and after a player state change only if they read a changed field.
|
|
4270
4277
|
|
|
4271
4278
|
- Every plugin sees the flags as `player.state.can.next` and `can.previous`, and player.next() asks the provider to move; the provider's `next` runs in its own scope.
|
|
4272
4279
|
- A second provider fails with `conflict` and does not fail activation; it is tried again when its flags change, so it takes over once the first provider goes away.
|
|
@@ -4627,12 +4634,12 @@ export component ListPanel inherits Rectangle {
|
|
|
4627
4634
|
|
|
4628
4635
|
| | `set({ x })` | `bind(() => ({ x }))` |
|
|
4629
4636
|
| ---------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
4630
|
-
| When it is sent | Immediately (in the next write). | In every update pass, if `x` differs from the last value sent.
|
|
4637
|
+
| When it is sent | Immediately (in the next write). | In every full update pass, and after a player state change if the function read a changed field; when `x` differs from the last value sent. |
|
|
4631
4638
|
| Same value again | Sent again. Use this to pull a control back to the model value after the user moved it. | Not sent. A field the user edited stays as the user left it until your value changes. |
|
|
4632
4639
|
| Write fails | Retried with back-off (0.25 s doubling up to 30 s). | Not repeated until the value changes. |
|
|
4633
4640
|
| Typical use | One-off values: a document, a reset. | Everything derived from plugin state: labels, enabled flags, lists, status lines. |
|
|
4634
4641
|
|
|
4635
|
-
Update passes run after every handler the SDK calls, after player and other state changes, and when you call plugin.update(); several requests are merged into one pass, and each view has at most one write in flight (The update pass has the details).
|
|
4642
|
+
Update passes run after every handler the SDK calls, after player and other state changes, and when you call plugin.update(); several requests are merged into one pass, and each view has at most one write in flight. After a player state change only the bind functions that read a changed field of `plugin.player.state` run again (The update pass has the details).
|
|
4636
4643
|
|
|
4637
4644
|
The rule to remember: **state you change after an `await` inside a handler appears only when the handler finishes**, unless something else triggers a pass. Call `plugin.update()` right after changing it (see Keep a slider responsive while dragging).
|
|
4638
4645
|
|
|
@@ -5810,6 +5817,8 @@ Every SDK release's CHANGELOG entry opens with who must change and what happens
|
|
|
5810
5817
|
|
|
5811
5818
|
| Release | Who must change | Guide |
|
|
5812
5819
|
| --- | --- | --- |
|
|
5820
|
+
| [1.5.46](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md#1546) | **Nobody.** No changes to the TypeScript API, `apiVersion` stays `vestra/1`, no new capability. | — |
|
|
5821
|
+
| [1.5.45](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md#1545) | **Nobody.** No changes to the TypeScript API, `apiVersion` stays `vestra/1`, no new capability, no player version needed. | — |
|
|
5813
5822
|
| [1.5.44](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md#1544) | **Nobody.** No changes to the TypeScript API, `apiVersion` stays `vestra/1`, no new capability. | — |
|
|
5814
5823
|
| [1.5.43](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md#1543) | **Nobody.** Additions only, `apiVersion` stays `vestra/1`, no new capability. | — |
|
|
5815
5824
|
| [1.5.42](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md#1542) | **Nobody.** Documentation only: no API changes, `apiVersion` stays `vestra/1`, no player version needed. | — |
|
|
@@ -6367,8 +6376,10 @@ interface CommandState {
|
|
|
6367
6376
|
|
|
6368
6377
|
### Bindable
|
|
6369
6378
|
|
|
6370
|
-
A value, or a function the SDK re-evaluates on every update pass
|
|
6371
|
-
|
|
6379
|
+
A value, or a function the SDK re-evaluates on every full update pass,
|
|
6380
|
+
and after a player state change only if it read a field of
|
|
6381
|
+
`plugin.player.state` that changed (see Scope.update); only
|
|
6382
|
+
changes are sent to the player.
|
|
6372
6383
|
|
|
6373
6384
|
```ts
|
|
6374
6385
|
type Bindable<T> = T | (() => T);
|
|
@@ -6377,9 +6388,9 @@ type Bindable<T> = T | (() => T);
|
|
|
6377
6388
|
Example: Mix a computed state with a fixed one
|
|
6378
6389
|
|
|
6379
6390
|
The Loop item carries a check mark while a loop is set and is always
|
|
6380
|
-
enabled. A function is evaluated again in every update pass (after
|
|
6381
|
-
handler and player state change
|
|
6382
|
-
value never changes.
|
|
6391
|
+
enabled. A function is evaluated again in every full update pass (after
|
|
6392
|
+
each handler), and after a player state change only if it read a changed
|
|
6393
|
+
field; only changes are sent, and a plain value never changes.
|
|
6383
6394
|
```ts
|
|
6384
6395
|
plugin.commands.add({
|
|
6385
6396
|
id: "loop",
|
|
@@ -6800,8 +6811,9 @@ from the menu and the binding table; the id can be added again right away.
|
|
|
6800
6811
|
|
|
6801
6812
|
The handle of one menu item and its keys. Its state (`enabled`, `checked`,
|
|
6802
6813
|
`busy`, `reason`) is bound: functions given to Commands.add or
|
|
6803
|
-
Command.set are evaluated again in every update pass
|
|
6804
|
-
|
|
6814
|
+
Command.set are evaluated again in every full update pass (after
|
|
6815
|
+
a player state change only if they read a changed field of
|
|
6816
|
+
`plugin.player.state`) and only changes reach the player. Its title, path, bindings and button cannot
|
|
6805
6817
|
change in place; dispose the command (or a child Scope) and add it
|
|
6806
6818
|
again. Disposing it, its scope or stopping the plugin removes the menu
|
|
6807
6819
|
item, its keys and its bar button.
|
|
@@ -6864,7 +6876,7 @@ const exportCommand = plugin.commands.add({
|
|
|
6864
6876
|
path: ["@video", "Export…"],
|
|
6865
6877
|
run: runExport,
|
|
6866
6878
|
});
|
|
6867
|
-
// A function: re-evaluated in every
|
|
6879
|
+
// A function: re-evaluated in every full pass and when `phase` changes.
|
|
6868
6880
|
exportCommand.set({ enabled: () => plugin.player.state.phase === "ready" });
|
|
6869
6881
|
```
|
|
6870
6882
|
|
|
@@ -7092,20 +7104,23 @@ ImageOptions.maxSide for small pictures such as logos and
|
|
|
7092
7104
|
thumbnails.
|
|
7093
7105
|
|
|
7094
7106
|
Limits per value (`UI_VALUE_LIMITS` in `@vestra-player/sdk/testing`,
|
|
7095
|
-
player 0.4.3
|
|
7096
|
-
|
|
7097
|
-
null counts, the value itself included; a
|
|
7098
|
-
|
|
7099
|
-
field
|
|
7100
|
-
document). A list of rows
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7107
|
+
player 0.6.0; players 0.4.3 to 0.5: 16384 values, 4096 rows, 1 MiB of
|
|
7108
|
+
text): nesting depth 8, 1,048,576 values in total (every array, object,
|
|
7109
|
+
string, number, boolean and null counts, the value itself included; a
|
|
7110
|
+
document or an image is one), 100,000 rows per array, 64 KiB per string
|
|
7111
|
+
or field name and 32 MiB of text in total, field names and the text of
|
|
7112
|
+
its Markdown documents included (256 KB per document). A list of rows
|
|
7113
|
+
with 13 fields is 14 values per row, so 50,000 such rows fit. An array
|
|
7114
|
+
property larger than one 1 MiB request is sent in parts (SDK 1.5.46, a
|
|
7115
|
+
player that takes row patches); only the top-level array is split, so
|
|
7116
|
+
any other value, and each row, must fit in one request (a row of more
|
|
7117
|
+
than 512 KiB is refused with `limit`). A value over a limit is refused
|
|
7118
|
+
with code
|
|
7119
|
+
`limit` and the property keeps what it showed (see View.set);
|
|
7120
|
+
`TestHost` refuses it the same way.
|
|
7121
|
+
|
|
7122
|
+
Bind a whole list and draw it with a Slint `ListView`, which builds only
|
|
7123
|
+
the rows on screen; the SDK sends what changed (row patches).
|
|
7109
7124
|
|
|
7110
7125
|
```ts
|
|
7111
7126
|
type PropValue = PropData | ImageRef;
|
|
@@ -7415,8 +7430,9 @@ a property back: a value the user changes reaches it only through a
|
|
|
7415
7430
|
callback.
|
|
7416
7431
|
|
|
7417
7432
|
`bind` is the usual way: the SDK re-evaluates bound functions in every
|
|
7418
|
-
update pass (after each handler it calls,
|
|
7419
|
-
|
|
7433
|
+
full update pass (after each handler it calls, on Scope.update),
|
|
7434
|
+
and after a player state change those that read a changed field of
|
|
7435
|
+
`plugin.player.state`, and sends only what changed, at most one write in
|
|
7420
7436
|
flight per view. `set` sends now, even an unchanged value.
|
|
7421
7437
|
|
|
7422
7438
|
Writes that fail (a name the Slint file does not declare, a value of the
|
|
@@ -7519,7 +7535,11 @@ interface View {
|
|
|
7519
7535
|
* Keep properties equal to a function of the plugin's state.
|
|
7520
7536
|
*
|
|
7521
7537
|
* The SDK calls `props` in every update pass (and right after `bind`) and
|
|
7522
|
-
* sends the values that differ from the ones it sent last.
|
|
7538
|
+
* sends the values that differ from the ones it sent last. After a change
|
|
7539
|
+
* of the player state alone it calls `props` only if it read a field of
|
|
7540
|
+
* `plugin.player.state` that changed (SDK 1.5.45); a full pass follows
|
|
7541
|
+
* after each handler, on Scope.update and at least once a second
|
|
7542
|
+
* while the player state keeps changing. Because an
|
|
7523
7543
|
* unchanged value is not sent again, text the user typed into an `in-out`
|
|
7524
7544
|
* property stays until the plugin's value for it changes.
|
|
7525
7545
|
*
|
|
@@ -7537,8 +7557,9 @@ interface View {
|
|
|
7537
7557
|
* @example Show what is playing and whether it can seek
|
|
7538
7558
|
* The status window always shows the current file and enables its seek
|
|
7539
7559
|
* controls only for seekable sources. The SDK calls the function right
|
|
7540
|
-
* away
|
|
7541
|
-
*
|
|
7560
|
+
* away, again in every full update pass (after each handler) and after
|
|
7561
|
+
* each change of `source` or `can`, and sends only the values that
|
|
7562
|
+
* changed.
|
|
7542
7563
|
* ```ts
|
|
7543
7564
|
* const status = plugin.windows.create("ui/status.slint");
|
|
7544
7565
|
* status.bind(() => ({
|
|
@@ -10947,8 +10968,8 @@ interface Player {
|
|
|
10947
10968
|
* @example Drive the player's Next and Previous from a playlist
|
|
10948
10969
|
* The player's Next and Previous items and keys play the plugin's list.
|
|
10949
10970
|
* The player calls `next` and `previous` when the user asks; `canNext`
|
|
10950
|
-
* and `canPrevious` are evaluated again after every handler the SDK runs
|
|
10951
|
-
* and while they return false the player disables its items ("No next
|
|
10971
|
+
* and `canPrevious` are evaluated again after every handler the SDK runs
|
|
10972
|
+
* (and after a player state change if they read a changed field), and while they return false the player disables its items ("No next
|
|
10952
10973
|
* item").
|
|
10953
10974
|
* ```ts
|
|
10954
10975
|
* const playAt = async (at: number) => {
|
|
@@ -17001,6 +17022,13 @@ class TestHost implements Transport {
|
|
|
17001
17022
|
* or parsing a file, a child process, a network request) is not waited
|
|
17002
17023
|
* for: on a loaded machine it can finish after `settle()` returns. Poll
|
|
17003
17024
|
* the result you assert on instead (second example).
|
|
17025
|
+
*
|
|
17026
|
+
* `settle()` does not wait for the SDK's once-a-second full update pass
|
|
17027
|
+
* (SDK 1.5.45). After `setSource` (or another player state change) only
|
|
17028
|
+
* the bindings that read a changed field of `plugin.player.state` run
|
|
17029
|
+
* again; state the plugin changed outside a handler without
|
|
17030
|
+
* `plugin.update()` shows only in the next full pass. Have the plugin
|
|
17031
|
+
* call `plugin.update()` after such a change, or wait `settle(1000)`.
|
|
17004
17032
|
* @param ms - Extra time to wait, for debounces and timers (default 0).
|
|
17005
17033
|
* @capability None.
|
|
17006
17034
|
* @throws Never.
|
|
@@ -17831,53 +17859,41 @@ keeps what it showed) and reported to `Scope.onError`: a write by
|
|
|
17831
17859
|
makes `Window.show` reject; a panel or settings page opens without it and
|
|
17832
17860
|
the failure goes to the plugin's `onError`.
|
|
17833
17861
|
|
|
17834
|
-
|
|
17835
|
-
|
|
17836
|
-
|
|
17837
|
-
|
|
17862
|
+
Since player 0.6.0 (SDK 1.5.46) they allow a whole list: a plugin binds
|
|
17863
|
+
all of its rows (a playlist of 50,000 entries fits) and the view draws
|
|
17864
|
+
them with a Slint `ListView`, which builds only the rows on screen. The
|
|
17865
|
+
SDK sends a changed array as row patches, and an array larger than one
|
|
17866
|
+
request (about 512 KiB of rows) as its first rows followed by `insert`
|
|
17867
|
+
patches of the rest; the player converts large writes off its interface
|
|
17868
|
+
thread. Before player 0.6.0 the limits were 4,096 rows, 16,384 values and
|
|
17869
|
+
1 MiB of text, so a long list had to be sent as a window of rows.
|
|
17870
|
+
|
|
17871
|
+
In a row, `null` where the view declares an `image` shows no picture
|
|
17872
|
+
(player 0.6.0): rows without a thumbnail need no placeholder image.
|
|
17838
17873
|
|
|
17839
17874
|
```ts
|
|
17840
17875
|
const UI_VALUE_LIMITS: {
|
|
17841
17876
|
/** Nesting depth; the value itself is depth 0 (8). */
|
|
17842
17877
|
readonly depth: 8;
|
|
17843
|
-
/**
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
readonly
|
|
17878
|
+
/**
|
|
17879
|
+
* Values in all, counting every array, object, string, number, boolean and null, the value itself included; a Markdown document is one (1,048,576; 16,384 before player 0.6.0).
|
|
17880
|
+
*/
|
|
17881
|
+
readonly values: number;
|
|
17882
|
+
/** Rows of one array (100,000; 4,096 before player 0.6.0). */
|
|
17883
|
+
readonly arrayRows: 100000;
|
|
17847
17884
|
/** UTF-8 bytes of one string or object field name (64 KiB). */
|
|
17848
17885
|
readonly stringBytes: number;
|
|
17849
|
-
/** UTF-8 bytes of all strings and field names together, the text of the value's Markdown documents included (1 MiB). */
|
|
17886
|
+
/** UTF-8 bytes of all strings and field names together, the text of the value's Markdown documents included (32 MiB; 1 MiB before player 0.6.0). */
|
|
17850
17887
|
readonly textBytes: number;
|
|
17851
17888
|
};
|
|
17852
17889
|
```
|
|
17853
17890
|
|
|
17854
|
-
Example:
|
|
17891
|
+
Example: Bind a whole list
|
|
17855
17892
|
|
|
17856
|
-
|
|
17857
|
-
the plugin sends only the rows around the scroll position plus the total,
|
|
17858
|
-
and the view reports where it scrolled to. After the `scrolled` handler
|
|
17859
|
-
returns, the SDK evaluates the `bind` function again and sends the new
|
|
17860
|
-
window. Each row object and each of its fields count as one value toward
|
|
17861
|
-
`values`, and so does the array holding them.
|
|
17862
|
-
```ts
|
|
17863
|
-
import { UI_VALUE_LIMITS } from "@vestra-player/sdk/testing";
|
|
17893
|
+
The view draws every row with a `ListView`; the SDK sends what changed.
|
|
17864
17894
|
|
|
17865
|
-
|
|
17866
|
-
|
|
17867
|
-
const size = Math.min(
|
|
17868
|
-
200,
|
|
17869
|
-
UI_VALUE_LIMITS.arrayRows,
|
|
17870
|
-
Math.floor((UI_VALUE_LIMITS.values - 1) / 3),
|
|
17871
|
-
);
|
|
17872
|
-
let first = 0;
|
|
17873
|
-
list.bind(() => ({
|
|
17874
|
-
total: entries.length,
|
|
17875
|
-
rows: entries.slice(first, first + size),
|
|
17876
|
-
}));
|
|
17877
|
-
// The Slint view reports its first visible row; the window follows it.
|
|
17878
|
-
list.on("scrolled", (row: number) => {
|
|
17879
|
-
first = Math.max(0, row - Math.floor(size / 2));
|
|
17880
|
-
});
|
|
17895
|
+
```ts
|
|
17896
|
+
list.bind(() => ({ rows: entries.map((e) => ({ ...e, selected: false })) }));
|
|
17881
17897
|
```
|
|
17882
17898
|
|
|
17883
17899
|
### IMAGE_LIMITS
|
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vestra Player SDK
|
|
2
2
|
|
|
3
|
-
> @vestra-player/sdk 1.5.
|
|
3
|
+
> @vestra-player/sdk 1.5.46: 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 (the player's built-in plugins share one). Everything a plugin creates (commands, windows, panels, filters, listeners…) is a handle that is released automatically when the plugin stops. L<n>: a line of llms-full.txt (next to this file), which has 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:
|
|
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: L2218–2292.
|
|
37
37
|
|
|
38
38
|
**main.ts**
|
|
39
39
|
|
|
@@ -78,9 +78,9 @@ export default async function activate(plugin: Plugin) {
|
|
|
78
78
|
- `secrets`: Secrets.get/set/delete
|
|
79
79
|
- `rendering.manage`: Rendering.setPreference/restartPlayer
|
|
80
80
|
- `video.upscaling`: VideoUpscaling.state/set/onChange
|
|
81
|
-
- No capability: `tools`, `storage`, `system`, `app`, `ui` (images and Markdown), `i18n`, reading window.state, appearance.theme, packages.list and rendering.state. Details:
|
|
81
|
+
- No capability: `tools`, `storage`, `system`, `app`, `ui` (images and Markdown), `i18n`, reading window.state, appearance.theme, packages.list and rendering.state. Details: L2293–2353.
|
|
82
82
|
|
|
83
|
-
**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` an in-memory player (TestHost): act (`host.command(id).run()`, `host.press(key)`), `await host.settle()`, assert on `host.osd`, `host.window(id).props`… Guide: L1861–
|
|
83
|
+
**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` an in-memory player (TestHost): act (`host.command(id).run()`, `host.press(key)`), `await host.settle()`, assert on `host.osd`, `host.window(id).props`… Guide: L1861–2021; TestHost: L15484.
|
|
84
84
|
|
|
85
85
|
**Command line**
|
|
86
86
|
|
|
@@ -108,40 +108,40 @@ export default async function activate(plugin: Plugin) {
|
|
|
108
108
|
- `limit`: A player-wide limit was reached, a property value is over the limits of PropValue
|
|
109
109
|
- `reserved`: The id is `vestra` or starts with `vestra.`
|
|
110
110
|
- `versionMismatch`: The package needs a newer player
|
|
111
|
-
- Others: PluginError, llms-full.txt
|
|
111
|
+
- Others: PluginError, llms-full.txt L5954.
|
|
112
112
|
|
|
113
113
|
## Reference
|
|
114
114
|
|
|
115
115
|
- [llms-full.txt](https://vestrasys.github.io/vestra-player-sdk/llms-full.txt), also node_modules/@vestra-player/sdk/llms-full.txt; pages: [site](https://vestrasys.github.io/vestra-player-sdk/).
|
|
116
116
|
- Tutorials: Getting started L9–134; Add a window L135–213; Add settings and translations L214–367; Test, check, pack and publish L368–424; Write your own blur kernel L425–685
|
|
117
|
-
- How-to: Control playback L686–854; Store a plugin's data L855–961; Load subtitles from a plugin L962–1074; Keep a slider responsive while dragging L1075–1262; Remember a window's state between runs L1263–1414; Offer a GPU rendering switch L1415–1540; Keep a command's state without keeping the plugin running L1541–1697; Translate a plugin L1698–1860; Test a plugin L1861–
|
|
118
|
-
- Reference: Manifest
|
|
119
|
-
- Explanation: How a plugin runs
|
|
120
|
-
- Guidelines: Plugin rules
|
|
121
|
-
- Upgrading: Migrate a plugin to English source text
|
|
122
|
-
- [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html):
|
|
123
|
-
- [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html):
|
|
117
|
+
- How-to: Control playback L686–854; Store a plugin's data L855–961; Load subtitles from a plugin L962–1074; Keep a slider responsive while dragging L1075–1262; Remember a window's state between runs L1263–1414; Offer a GPU rendering switch L1415–1540; Keep a command's state without keeping the plugin running L1541–1697; Translate a plugin L1698–1860; Test a plugin L1861–2021; Publish a plugin L2022–2123; Troubleshooting L2124–2217
|
|
118
|
+
- Reference: Manifest L2218–2292; Capabilities L2293–2353; Limits L2354–2499; Commands, menus and bindings L2500–3025; Platforms L3026–3056; Theme L3057–3406; Command line L3407–3464; Error codes L3465–3512; Translations L3513–3605; Test host L3606–3792
|
|
119
|
+
- Explanation: How a plugin runs L3793–3995; Commands, menus and key bindings L3996–4150; Playback state, controls and sources L4151–4310; Video and audio processing L4311–4431; Windows, panels, settings pages, dialogs and the OSD L4432–4694; GPU and software rendering L4695–4711; The player's Rust core L4712–5053; How the player runs and talks to plugins L5054–5393
|
|
120
|
+
- Guidelines: Plugin rules L5394–5405; Interface guidelines L5406–5522; Menu guidelines L5523–5581
|
|
121
|
+
- Upgrading: Migrate a plugin to English source text L5582–5731; Migrating off package rollback (1.5.16, removed in 1.5.17) L5732–5809; Who must change, release by release L5810–5876
|
|
122
|
+
- [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L5877–15157
|
|
123
|
+
- [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L15158–18020
|
|
124
124
|
|
|
125
125
|
## API
|
|
126
126
|
|
|
127
127
|
Where each `plugin.<module>` is declared:
|
|
128
128
|
|
|
129
|
-
- Plugin
|
|
130
|
-
- Commands
|
|
129
|
+
- Plugin L6293, Scope L6029, PluginError L5954, Disposable L5892
|
|
130
|
+
- Commands L6883; When L6480; Windows L7829; Panels L9275; Dialogs L9945; Player L10686; video: VideoFilter L11566, VideoView L11666, RenderOptions L11753, VideoShaders L11831, VideoUpscaling L12189; audio: AudioFilter L11611; Subtitles L12425; media: MediaCapture L12829; Resolvers L13059; Packages L13461; Osd L11431; Host L11273; Clipboard L13790; Power L13877; Tools L13936; Storage L14088; System L14287; Secrets L14367; window: MainWindow L9592; App L9772; Rendering L14630; Bindings L13689; Ui L7175; Timeline L9504; Drops L8522; Appearance L8603; I18n L8836; Settings L9119.
|
|
131
131
|
|
|
132
132
|
## Examples
|
|
133
133
|
|
|
134
134
|
Tested plugins in [examples/](https://github.com/vestrasys/vestra-player-sdk/tree/main/examples):
|
|
135
135
|
|
|
136
|
-
- hello: The README Quick start: one menu command and an on-screen message.
|
|
137
|
-
- blur: A tool window with one slider that blurs the playing video.
|
|
138
|
-
- signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone.
|
|
139
|
-
- bookmark: A tool window bound to the playback state: remember the position and jump back to it.
|
|
140
|
-
- panel-menu: A sidebar panel with its own right-click menu.
|
|
141
|
-
- menus: Radio menu items, separator groups and a menu item whose title changes.
|
|
142
|
-
- theme-widgets: A tool window drawn with the player's theme and widgets.
|
|
143
|
-
- markdown: A window that shows a Markdown document.
|
|
144
|
-
- i18n: A plugin in the player's language: English source text, a Chinese translation.
|
|
136
|
+
- hello: The README Quick start: one menu command and an on-screen message. L18455–18550
|
|
137
|
+
- blur: A tool window with one slider that blurs the playing video. L18551–18818
|
|
138
|
+
- signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L18819–19157
|
|
139
|
+
- bookmark: A tool window bound to the playback state: remember the position and jump back to it. L19158–19350
|
|
140
|
+
- panel-menu: A sidebar panel with its own right-click menu. L19351–19565
|
|
141
|
+
- menus: Radio menu items, separator groups and a menu item whose title changes. L19566–19731
|
|
142
|
+
- theme-widgets: A tool window drawn with the player's theme and widgets. L19732–19901
|
|
143
|
+
- markdown: A window that shows a Markdown document. L19902–20104
|
|
144
|
+
- i18n: A plugin in the player's language: English source text, a Chinese translation. L20105–20278
|
|
145
145
|
|
|
146
146
|
## Optional
|
|
147
147
|
|