@vestra-player/sdk 1.5.46 → 1.5.47

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.47
4
+
5
+ **Who must change: nobody.** No changes to the TypeScript API, `apiVersion` stays `vestra/1`, no new capability, no player version needed. The built-in command table follows player 0.6.0's new default keys: a plugin whose documentation or tests list the player's default keys (from `BUILTIN_COMMANDS`, or Escape, Enter, F11 and the side mouse buttons by hand) should update them.
6
+
7
+ - **Player 0.6.0 default keys** (`BUILTIN_COMMANDS`, the generated key tables, `HostAction`): **Toggle Fullscreen** (`host/fullscreen`) is `Escape` only (up to 0.5.x `Enter`, `Alt+Enter`, `F11`); **Leave Fullscreen** (`host/exit-fullscreen`) has no default key (up to 0.5.x `Escape`); the new **Enter Fullscreen** (`host/enter-fullscreen`) has no default key and no menu row and is enabled only when windowed (Leave Fullscreen only in fullscreen); **Previous** is `PageUp`, `Mouse:X2` and **Next** `PageDown`, `Mouse:X1` (the side buttons swapped: back is next, forward is previous). The side buttons now fire anywhere in the main window or the floating sidebar window, except while a menu is open, not only over the video. `host.run` takes the same actions as before (`fullscreen` toggles). `TestHost`'s core actions use the new Previous / Next bindings.
8
+ - **Rows that cannot change are not encoded again.** An update pass encodes every row of a bound array to find the changed ones; in a 20,000-row list that was about 40% of a click. A deep-frozen row (`Object.freeze` on it and on everything inside it: plain objects and arrays, no getters, no own `toJSON`; image and document handles allowed: they are immutable, their wire form is fixed when made, so they need no freezing) that the bind function returns again is now encoded once more and then taken from a cache kept by the row object (weakly: a row the plugin drops goes with its entry), with its limit counts. Rows that are not frozen, or hold a mutable part, are encoded on every pass as before, so changes made in place are still sent. To benefit, keep an unchanged row as the same frozen object and make a new one when it changes ([Arrays: only the changed rows are sent](docs/explanation/ui.md#arrays-only-the-changed-rows-are-sent)). Measured in the test host with the playlist at 20,000 rows memoized that way: a click from about 24 ms to about 14 ms to the rows write.
9
+ - _Commands, menus and key bindings_: the example of a disabled command letting its key go no longer uses Escape on Leave Fullscreen.
10
+
3
11
  ## 1.5.46
4
12
 
5
13
  **Who must change: nobody.** No changes to the TypeScript API, `apiVersion` stays `vestra/1`, no new capability. The new limits and the split writes take effect with player 0.6.0 (large lists P3); with older players arrays are sent whole as before and the old limits apply there. **A plugin that binds a whole long list depends on them: set `"minPlayerVersion": "0.6.0"`.**
package/dist/commands.js CHANGED
@@ -265,8 +265,8 @@ vestra.playback | copy-name | Copy to Clipboard ▸ File Name
265
265
  vestra.playback | copy-folder | Copy to Clipboard ▸ Folder Path
266
266
  vestra.playback | copy-path | Copy to Clipboard ▸ Full Path
267
267
  host | play-pause | Playback ▸ Play/Pause | Space, Mouse:LeftClick
268
- host | previous | Playback ▸ Previous | PageUp, Mouse:X1
269
- host | next | Playback ▸ Next | PageDown, Mouse:X2
268
+ host | previous | Playback ▸ Previous | PageUp, Mouse:X2
269
+ host | next | Playback ▸ Next | PageDown, Mouse:X1
270
270
  host | frame-back | Playback ▸ Seek ▸ Previous Frame | D
271
271
  host | frame-forward | Playback ▸ Seek ▸ Next Frame | F
272
272
  vestra.playback | keyframe-back | Playback ▸ Seek ▸ Previous Keyframe | Ctrl+Shift+ArrowLeft
@@ -492,7 +492,7 @@ vestra.audio | audio.normalize | Audio ▸ Processing ▸ Normalize | Shift+N
492
492
  vestra.audio | audio.clarity | Audio ▸ Processing ▸ Crystalizer | Shift+C
493
493
  vestra.audio | audio.reset | Audio ▸ Reset
494
494
  vestra.visualizer | audio-cover | Audio ▸ Show Album Cover for Audio Only
495
- host | fullscreen | Toggle Fullscreen | Enter, Alt+Enter, F11
495
+ host | fullscreen | Toggle Fullscreen | Escape
496
496
  vestra.window | pip | Screen ▸ Picture-in-Picture
497
497
  vestra.window | mini | Screen ▸ Mini Size | \`
498
498
  vestra.window | size.0.5 | Screen ▸ 0.5× | 1
@@ -536,7 +536,8 @@ vestra.preferences | language.fr | Settings ▸ Language ▸ Français
536
536
  vestra.preferences | language.es | Settings ▸ Language ▸ Español
537
537
  vestra.info | info.about | About Vestra Player… | F1
538
538
  host | quit | Quit | Cmd+Q
539
- host | exit-fullscreen | (Leave Fullscreen) | Escape
539
+ host | enter-fullscreen | (Enter Fullscreen)
540
+ host | exit-fullscreen | (Leave Fullscreen)
540
541
  host | sidebar | (Toggle Sidebar)
541
542
  vestra.info | info.brief | (Brief Info) | Shift+Tab
542
543
  vestra.playlist | playlist.play | (Play) | Enter, P | panel
@@ -66,8 +66,11 @@ export declare const BINDING_INPUTS: Readonly<{
66
66
  */
67
67
  readonly named: readonly ["Space", "Enter", "Tab", "Escape", "Backspace", "Delete", "Insert", "Home", "End", "PageUp", "PageDown", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Plus", ...string[], "NumpadPlus", "NumpadMinus", "NumpadMultiply", "NumpadDivide", "NumpadEnter", "NumpadDecimal"];
68
68
  /**
69
- * Mouse inputs on the video area. `:LeftHalf` and `:RightHalf` tell the
70
- * halves of the video apart for a double click.
69
+ * Mouse inputs on the video area; the side buttons `Mouse:X1` (back) and
70
+ * `Mouse:X2` (forward) anywhere in the main window or the floating sidebar
71
+ * window, except while a menu is open (player 0.6.0).
72
+ * `:LeftHalf` and `:RightHalf` tell the halves of the video apart for a
73
+ * double click.
71
74
  */
72
75
  readonly mouse: readonly ["Mouse:LeftClick", "Mouse:LeftDoubleClick", "Mouse:LeftDoubleClick:LeftHalf", "Mouse:LeftDoubleClick:RightHalf", "Mouse:MiddleClick", "Mouse:X1", "Mouse:X2", "Mouse:WheelUp", "Mouse:WheelDown", "Mouse:WheelLeft", "Mouse:WheelRight"];
73
76
  }>;
@@ -97,8 +97,11 @@ export const BINDING_INPUTS = Object.freeze({
97
97
  "NumpadDecimal",
98
98
  ],
99
99
  /**
100
- * Mouse inputs on the video area. `:LeftHalf` and `:RightHalf` tell the
101
- * halves of the video apart for a double click.
100
+ * Mouse inputs on the video area; the side buttons `Mouse:X1` (back) and
101
+ * `Mouse:X2` (forward) anywhere in the main window or the floating sidebar
102
+ * window, except while a menu is open (player 0.6.0).
103
+ * `:LeftHalf` and `:RightHalf` tell the halves of the video apart for a
104
+ * double click.
102
105
  */
103
106
  mouse: [
104
107
  "Mouse:LeftClick",
@@ -2254,7 +2254,7 @@ export class TestHost {
2254
2254
  ["Playback", "Previous"],
2255
2255
  202,
2256
2256
  "domain",
2257
- ["PageUp", "Mouse:X1"],
2257
+ ["PageUp", "Mouse:X2"],
2258
2258
  false,
2259
2259
  ],
2260
2260
  [
@@ -2262,7 +2262,7 @@ export class TestHost {
2262
2262
  ["Playback", "Next"],
2263
2263
  203,
2264
2264
  "domain",
2265
- ["PageDown", "Mouse:X2"],
2265
+ ["PageDown", "Mouse:X1"],
2266
2266
  false,
2267
2267
  ],
2268
2268
  [
@@ -4248,7 +4248,7 @@ export class TestHost {
4248
4248
  throw new HostError("invalid", "seconds must be 0.1..3600 in tenths");
4249
4249
  seconds = p.seconds;
4250
4250
  }
4251
- // SDK 1.5.21: the main window's Toggle Fullscreen, like Enter: in when
4251
+ // SDK 1.5.21: the main window's Toggle Fullscreen, like Escape: in when
4252
4252
  // windowed, out when fullscreen, then `window.state`.
4253
4253
  if (p.action === "fullscreen") {
4254
4254
  this.coreRuns.push("fullscreen");
@@ -999,9 +999,12 @@ export interface CommandOptions {
999
999
  * `Home`, `End`, `PageUp`, `PageDown`, `ArrowLeft`/`Right`/`Up`/`Down`,
1000
1000
  * `Plus`, any other single symbol as typed (`">"`, not `"Shift+."`),
1001
1001
  * `Numpad0`–`Numpad9`, `NumpadPlus`, `NumpadMinus`, `NumpadMultiply`,
1002
- * `NumpadDivide`, `NumpadEnter`, `NumpadDecimal`, and the video-area mouse
1002
+ * `NumpadDivide`, `NumpadEnter`, `NumpadDecimal`, the video-area mouse
1003
1003
  * inputs `Mouse:LeftClick`, `Mouse:LeftDoubleClick[:LeftHalf|:RightHalf]`,
1004
- * `Mouse:MiddleClick`, `Mouse:X1`, `Mouse:X2`, `Mouse:WheelUp`/`Down`/`Left`/`Right`.
1004
+ * `Mouse:MiddleClick`, `Mouse:WheelUp`/`Down`/`Left`/`Right`, and the side
1005
+ * buttons `Mouse:X1` (back), `Mouse:X2` (forward), from 0.6.0 on anywhere
1006
+ * in the main window or the floating sidebar window, except while a menu
1007
+ * is open.
1005
1008
  *
1006
1009
  * Platforms: on macOS `Ctrl+X` fires for both ⌃X and ⌘X while `Cmd+X`
1007
1010
  * means ⌘X only; on Windows `Cmd` is the Windows logo key, so write
@@ -6061,13 +6064,13 @@ export interface Player {
6061
6064
  * | --- | --- | --- |
6062
6065
  * | `stop` | F4 | close the source |
6063
6066
  * | `play-pause` | Space, a left click on the video (player 0.5.2) | pause / resume, replay after the end |
6064
- * | `previous` / `next` | PageUp, Mouse:X1 / PageDown, Mouse:X2 | ask the sequence provider |
6067
+ * | `previous` / `next` | PageUp, Mouse:X2 / PageDown, Mouse:X1 (from 0.6.0; up to 0.5.x X1 was previous and X2 next) | ask the sequence provider |
6065
6068
  * | `frame-back` / `frame-forward` | D / F | `player.step("frame", …)` |
6066
6069
  * | `seek-backward` / `seek-forward` | ← / → | relative seek by `setStepSeek` seconds (or `host.run`'s `seconds`), exact or to keyframes as `setStepSeek` says |
6067
6070
  * | `rate-normal`, `rate-down`, `rate-up` | Z, X, C | 1×, ±0.1 within 0.25–4 |
6068
6071
  * | `volume-up` / `volume-down` | ↑ / ↓, wheel | ±5 (`volume-up` stops at 100) |
6069
6072
  * | `mute` | M | toggle mute |
6070
- * | `fullscreen` | Enter, Alt+Enter, F11 | toggle the main window's fullscreen: enter it when windowed, leave it when fullscreen, as the Toggle Fullscreen command does (SDK 1.5.21, player 0.5.2; `unavailable` when the player has no window) |
6073
+ * | `fullscreen` | Escape (from 0.6.0; up to 0.5.x Enter, Alt+Enter, F11) | toggle the main window's fullscreen: enter it when windowed, leave it when fullscreen, as the Toggle Fullscreen command does (SDK 1.5.21, player 0.5.2; `unavailable` when the player has no window) |
6071
6074
  *
6072
6075
  * In the binding overlay their keys are `host/<action>`. `fullscreen`
6073
6076
  * changes no playback state: read the result from `window.state.fullscreen`
package/dist/plugin/ui.js CHANGED
@@ -83,8 +83,113 @@ const isPrimitive = (value) => value === null ||
83
83
  (typeof value === "number" && Number.isFinite(value));
84
84
  /** A row as `JSON.stringify` writes it inside an array. */
85
85
  const encodeRow = (row) => JSON.stringify(row) ?? "null";
86
+ /** What a row's encoding holds: a Markdown document, an image. */
87
+ const HAS_MARKDOWN = 1;
88
+ const HAS_IMAGE = 2;
89
+ const marksOf = (enc) => (enc.includes('"$vestraMarkdown"') ? HAS_MARKDOWN : 0) |
90
+ (enc.includes('"$vestraImage"') ? HAS_IMAGE : 0);
91
+ /**
92
+ * Row encodings by row object, shared by every property (a row's JSON does
93
+ * not depend on where it is bound). Only rows that cannot change are kept
94
+ * ({@link settled}): a plugin that mutates its rows in place sees no
95
+ * difference, and one that keeps unchanged rows as the same deep-frozen
96
+ * objects skips encoding them on every pass. Weak: a row the plugin drops
97
+ * goes with its entry.
98
+ */
99
+ const settledRows = new WeakMap();
100
+ /**
101
+ * Frozen rows seen once. A frozen row is verified and kept on its second
102
+ * pass, so rows frozen afresh on every pass cost one set entry, not a
103
+ * verification each.
104
+ */
105
+ const seenRows = new WeakSet();
106
+ /** Frozen rows that can still change (a mutable part, a getter): never kept. */
107
+ const unsettledRows = new WeakSet();
108
+ /**
109
+ * `value` can never change what `JSON.stringify` writes for it: a primitive,
110
+ * an image or document handle (their wire form is fixed when made), or a
111
+ * frozen plain object or array whose own enumerable properties are data
112
+ * properties (no getter, no own `toJSON`) holding such values. Freezing
113
+ * fixes the properties and the prototype for good, so the answer holds as
114
+ * long as the object lives.
115
+ */
116
+ function settled(value, depth) {
117
+ if (value === null || typeof value !== "object")
118
+ return typeof value !== "function";
119
+ if (value instanceof ImageHandle || value instanceof MarkdownHandle)
120
+ return true;
121
+ if (depth > UI_VALUE_LIMITS.depth || !Object.isFrozen(value))
122
+ return false;
123
+ const proto = Object.getPrototypeOf(value);
124
+ if (Array.isArray(value)
125
+ ? proto !== Array.prototype
126
+ : proto !== Object.prototype && proto !== null)
127
+ return false;
128
+ // An own `toJSON`, enumerable or not, is called by `JSON.stringify`.
129
+ if (Object.prototype.hasOwnProperty.call(value, "toJSON"))
130
+ return false;
131
+ for (const key of Object.keys(value)) {
132
+ const property = Object.getOwnPropertyDescriptor(value, key);
133
+ if (!property || !("value" in property))
134
+ return false;
135
+ if (!settled(property.value, depth + 1))
136
+ return false;
137
+ }
138
+ return true;
139
+ }
140
+ /** A row's encoding and marks, from {@link settledRows} when it is kept. */
141
+ function rowEncoding(row, cache) {
142
+ if (cache && row !== null && typeof row === "object") {
143
+ // A kept row is frozen: looked up first, `isFrozen` only on a miss.
144
+ const kept = settledRows.get(row);
145
+ if (kept)
146
+ return kept;
147
+ }
148
+ if (cache &&
149
+ row !== null &&
150
+ typeof row === "object" &&
151
+ Object.isFrozen(row)) {
152
+ const enc = encodeRow(row);
153
+ const entry = { enc, marks: marksOf(enc) };
154
+ if (!seenRows.has(row))
155
+ seenRows.add(row);
156
+ else if (!unsettledRows.has(row)) {
157
+ if (settled(row, 1))
158
+ settledRows.set(row, entry);
159
+ else
160
+ unsettledRows.add(row);
161
+ }
162
+ return entry;
163
+ }
164
+ const enc = encodeRow(row);
165
+ return { enc, marks: marksOf(enc) };
166
+ }
86
167
  /** Each row of an array as `JSON.stringify` writes it; a hole is `null`. */
87
- const encodeRows = (rows) => Array.from(rows, encodeRow);
168
+ function encodeRows(rows) {
169
+ // A `toJSON` added to the shared prototypes would change any row's JSON:
170
+ // then nothing is taken from (or kept in) the cache.
171
+ const cache = !("toJSON" in Object.prototype) && !("toJSON" in Array.prototype);
172
+ const enc = [];
173
+ const marks = new Uint8Array(rows.length);
174
+ let markdown = false;
175
+ for (let i = 0; i < rows.length; i++) {
176
+ const row = rowEncoding(rows[i], cache);
177
+ enc[i] = row.enc;
178
+ marks[i] = row.marks;
179
+ if (row.marks & HAS_MARKDOWN)
180
+ markdown = true;
181
+ }
182
+ return { enc, marks, markdown, cache };
183
+ }
184
+ /** A row's limit counts, kept with its encoding when the row cannot change. */
185
+ function rowCount(row, cache) {
186
+ const kept = cache && row !== null && typeof row === "object"
187
+ ? settledRows.get(row)
188
+ : undefined;
189
+ if (!kept)
190
+ return countRow(row);
191
+ return (kept.count ??= countRow(row));
192
+ }
88
193
  function sameRows(a, b) {
89
194
  if (a.length !== b.length)
90
195
  return false;
@@ -102,7 +207,7 @@ function sentOf(value, patches) {
102
207
  return {
103
208
  kind: "rows",
104
209
  rows: {
105
- enc: encodeRows(value),
210
+ enc: encodeRows(value).enc,
106
211
  field: keyed?.field ?? null,
107
212
  keys: keyed?.keys ?? null,
108
213
  counts: [],
@@ -142,7 +247,7 @@ function tooLarge(key, ops) {
142
247
  function rowPatch(sent, next, rows) {
143
248
  if (sent.enc.length === 0)
144
249
  return null;
145
- if (next.enc.some((row) => row.includes('"$vestraMarkdown"')))
250
+ if (next.markdown)
146
251
  return null;
147
252
  const nextKeyed = sent.field === null ? null : next.keyed();
148
253
  const keyed = nextKeyed !== null && nextKeyed.field === sent.field;
@@ -152,11 +257,12 @@ function rowPatch(sent, next, rows) {
152
257
  // A released image is refused wherever it is, as in a whole write: the
153
258
  // rows the patch does not carry are checked too (those holding images).
154
259
  for (let j = 0; j < rows.length; j++)
155
- if (plan.from[j] >= 0 && next.enc[j].includes('"$vestraImage"'))
260
+ if (plan.from[j] >= 0 && next.marks[j] & HAS_IMAGE)
156
261
  wireValue(rows[j] ?? null);
157
262
  const counts = next.enc.map((_, j) => {
158
263
  const from = plan.from[j];
159
- return (from >= 0 ? sent.counts[from] : undefined) ?? countRow(rows[j]);
264
+ return ((from >= 0 ? sent.counts[from] : undefined) ??
265
+ rowCount(rows[j], next.cache));
160
266
  });
161
267
  if (!withinLimits(counts))
162
268
  return null;
@@ -372,8 +478,10 @@ export class ViewBase {
372
478
  }
373
479
  if (Array.isArray(value) && this.#patches) {
374
480
  // Row by row: the same work as one `JSON.stringify`, and the rows to
375
- // diff against those last sent.
376
- const enc = encodeRows(value);
481
+ // diff against those last sent. Rows that cannot change (deep-frozen
482
+ // objects bound again, SDK 1.5.47) are taken from `settledRows`.
483
+ const encoded = encodeRows(value);
484
+ const { enc } = encoded;
377
485
  const signature = () => `[${enc.join(",")}]`;
378
486
  const changed = sent?.kind === "rows"
379
487
  ? !sameRows(sent.rows.enc, enc)
@@ -386,7 +494,7 @@ export class ViewBase {
386
494
  value,
387
495
  changed,
388
496
  signature,
389
- rows: { enc, keyed },
497
+ rows: { ...encoded, keyed },
390
498
  sent: (counts = []) => ({
391
499
  kind: "rows",
392
500
  rows: {
@@ -470,9 +578,7 @@ export class ViewBase {
470
578
  const seq = ++this.#seq;
471
579
  // Rows holding Markdown documents go whole, as before: the player
472
580
  // merges documents in place and takes no parts of them.
473
- if (Array.isArray(value) &&
474
- pending.rows &&
475
- !pending.rows.enc.some((row) => row.includes(MARKDOWN_KEY))) {
581
+ if (Array.isArray(value) && pending.rows && !pending.rows.markdown) {
476
582
  const sizes = pending.rows.enc.map(jsonBytes);
477
583
  const count = prefixWithin(sizes, CHUNK_BYTES);
478
584
  if (count < value.length) {
package/llms-full.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @vestra-player/sdk 1.5.46: full reference
1
+ # @vestra-player/sdk 1.5.47: 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
 
@@ -2630,8 +2630,8 @@ Every command the player (`host`) and its built-in plugins register when the pla
2630
2630
  | Copy to Clipboard ▸ Folder Path | | `vestra.playback/copy-folder` |
2631
2631
  | Copy to Clipboard ▸ Full Path | | `vestra.playback/copy-path` |
2632
2632
  | Playback ▸ Play/Pause | `Space`, `Mouse:LeftClick` | `host/play-pause` |
2633
- | Playback ▸ Previous | `PageUp`, `Mouse:X1` | `host/previous` |
2634
- | Playback ▸ Next | `PageDown`, `Mouse:X2` | `host/next` |
2633
+ | Playback ▸ Previous | `PageUp`, `Mouse:X2` | `host/previous` |
2634
+ | Playback ▸ Next | `PageDown`, `Mouse:X1` | `host/next` |
2635
2635
  | Playback ▸ Seek ▸ Previous Frame | `D` | `host/frame-back` |
2636
2636
  | Playback ▸ Seek ▸ Next Frame | `F` | `host/frame-forward` |
2637
2637
  | Playback ▸ Seek ▸ Previous Keyframe | `Ctrl+Shift+ArrowLeft` | `vestra.playback/keyframe-back` |
@@ -2857,7 +2857,7 @@ Every command the player (`host`) and its built-in plugins register when the pla
2857
2857
  | Audio ▸ Processing ▸ Crystalizer | `Shift+C` | `vestra.audio/audio.clarity` |
2858
2858
  | Audio ▸ Reset | | `vestra.audio/audio.reset` |
2859
2859
  | Audio ▸ Show Album Cover for Audio Only | | `vestra.visualizer/audio-cover` |
2860
- | Toggle Fullscreen | `Enter`, `Alt+Enter`, `F11` | `host/fullscreen` |
2860
+ | Toggle Fullscreen | `Escape` | `host/fullscreen` |
2861
2861
  | Screen ▸ Picture-in-Picture | | `vestra.window/pip` |
2862
2862
  | Screen ▸ Mini Size | ``` | `vestra.window/mini` |
2863
2863
  | Screen ▸ 0.5× | `1` | `vestra.window/size.0.5` |
@@ -2901,7 +2901,8 @@ Every command the player (`host`) and its built-in plugins register when the pla
2901
2901
  | Settings ▸ Language ▸ Español | | `vestra.preferences/language.es` |
2902
2902
  | About Vestra Player… | `F1` | `vestra.info/info.about` |
2903
2903
  | Quit | `Cmd+Q` | `host/quit` |
2904
- | Leave Fullscreen (not in the menu) | `Escape` | `host/exit-fullscreen` |
2904
+ | Enter Fullscreen (not in the menu) | | `host/enter-fullscreen` |
2905
+ | Leave Fullscreen (not in the menu) | | `host/exit-fullscreen` |
2905
2906
  | Toggle Sidebar (not in the menu) | | `host/sidebar` |
2906
2907
  | Brief Info (not in the menu) | `Shift+Tab` | `vestra.info/info.brief` |
2907
2908
  | Play (not in the menu) | `Enter`, `P` (panel focus) | `vestra.playlist/playlist.play` |
@@ -2979,7 +2980,7 @@ A menu item shows the first of its keyboard bindings that is in effect.
2979
2980
  | `digits` | `0`–`9` | Digit keys of the main keyboard: `0` to `9`. |
2980
2981
  | `functionKeys` | `F1`–`F24` | Function keys: `F1` to `F24`. |
2981
2982
  | `named` | `Space`, `Enter`, `Tab`, `Escape`, `Backspace`, `Delete`, `Insert`, `Home`, `End`, `PageUp`, `PageDown`, `ArrowLeft`, `ArrowRight`, `ArrowUp`, `ArrowDown`, `Plus`, `Numpad0`, `Numpad1`, `Numpad2`, `Numpad3`, `Numpad4`, `Numpad5`, `Numpad6`, `Numpad7`, `Numpad8`, `Numpad9`, `NumpadPlus`, `NumpadMinus`, `NumpadMultiply`, `NumpadDivide`, `NumpadEnter`, `NumpadDecimal` | Other named keys, matched by the physical key. `Plus` is the `+` key however it is typed; the `Numpad…` names are the numeric keypad only, never the main keyboard. |
2982
- | `mouse` | `Mouse:LeftClick`, `Mouse:LeftDoubleClick`, `Mouse:LeftDoubleClick:LeftHalf`, `Mouse:LeftDoubleClick:RightHalf`, `Mouse:MiddleClick`, `Mouse:X1`, `Mouse:X2`, `Mouse:WheelUp`, `Mouse:WheelDown`, `Mouse:WheelLeft`, `Mouse:WheelRight` | Mouse inputs on the video area. `:LeftHalf` and `:RightHalf` tell the halves of the video apart for a double click. |
2983
+ | `mouse` | `Mouse:LeftClick`, `Mouse:LeftDoubleClick`, `Mouse:LeftDoubleClick:LeftHalf`, `Mouse:LeftDoubleClick:RightHalf`, `Mouse:MiddleClick`, `Mouse:X1`, `Mouse:X2`, `Mouse:WheelUp`, `Mouse:WheelDown`, `Mouse:WheelLeft`, `Mouse:WheelRight` | Mouse inputs on the video area; the side buttons `Mouse:X1` (back) and `Mouse:X2` (forward) anywhere in the main window or the floating sidebar window, except while a menu is open (player 0.6.0). `:LeftHalf` and `:RightHalf` tell the halves of the video apart for a double click. |
2983
2984
 
2984
2985
  #### Core actions
2985
2986
 
@@ -2989,8 +2990,8 @@ The player's own playback commands, which plugin.host.run runs by id (capability
2989
2990
  | --- | --- | --- |
2990
2991
  | `stop` | Close | `F4` |
2991
2992
  | `play-pause` | Playback ▸ Play/Pause | `Space`, `Mouse:LeftClick` |
2992
- | `previous` | Playback ▸ Previous | `PageUp`, `Mouse:X1` |
2993
- | `next` | Playback ▸ Next | `PageDown`, `Mouse:X2` |
2993
+ | `previous` | Playback ▸ Previous | `PageUp`, `Mouse:X2` |
2994
+ | `next` | Playback ▸ Next | `PageDown`, `Mouse:X1` |
2994
2995
  | `frame-back` | Playback ▸ Seek ▸ Previous Frame | `D` |
2995
2996
  | `frame-forward` | Playback ▸ Seek ▸ Next Frame | `F` |
2996
2997
  | `seek-backward` | Playback ▸ Seek ▸ Back 5 s | `ArrowLeft` |
@@ -3001,9 +3002,9 @@ The player's own playback commands, which plugin.host.run runs by id (capability
3001
3002
  | `volume-up` | Audio ▸ Volume + | `ArrowUp`, `Mouse:WheelUp` |
3002
3003
  | `volume-down` | Audio ▸ Volume − | `ArrowDown`, `Mouse:WheelDown` |
3003
3004
  | `mute` | Audio ▸ Mute | `M` |
3004
- | `fullscreen` | Toggle Fullscreen | `Enter`, `Alt+Enter`, `F11` |
3005
+ | `fullscreen` | Toggle Fullscreen | `Escape` |
3005
3006
 
3006
- The player also owns **Toggle Fullscreen** (`host/fullscreen`), **Leave Fullscreen** (`host/exit-fullscreen`, `Escape`, only in fullscreen) and **Quit** (`host/quit`), and **Toggle Sidebar** (`host/sidebar`, player 0.5.10: the bottom bar's sidebar button, outside the menu, no default key); their keys are in Built-in commands.
3007
+ The player also owns **Toggle Fullscreen** (`host/fullscreen`, `Escape` from player 0.6.0; up to 0.5.x `Enter`, `Alt+Enter` and `F11`), **Enter Fullscreen** (`host/enter-fullscreen`, player 0.6.0: no default key, outside the menu, enabled only when windowed), **Leave Fullscreen** (`host/exit-fullscreen`: no default key from player 0.6.0, up to 0.5.x `Escape`; outside the menu, enabled only in fullscreen) and **Quit** (`host/quit`), and **Toggle Sidebar** (`host/sidebar`, player 0.5.10: the bottom bar's sidebar button, outside the menu, no default key); their keys are in Built-in commands.
3007
3008
 
3008
3009
  #### Keys the system takes first
3009
3010
 
@@ -4106,7 +4107,7 @@ flowchart TB
4106
4107
 
4107
4108
  - **Where bindings apply.** Bindings belong to the main window: they fire while it or the floating sidebar window has focus. They do **not** fire in tool windows or the Options window; keys there are the Slint file's own business (a `FocusScope`, a default button). While a menu or a system dialog is open, bindings pause.
4108
4109
  - **Conflicts are not errors.** A binding that loses is written to the player's log and takes effect by itself when the winner goes away (its plugin stops, the user rebinds it). Tests can check `host.conflicts` (TestHost.conflicts).
4109
- - **A disabled command lets its key go.** This is what makes context-dependent keys work: `Escape` bound to "Leave Fullscreen" does nothing outside fullscreen, so `Escape` reaches the focused control. Give `reason` to a command whose key should still be taken and explained while it is disabled.
4110
+ - **A disabled command lets its key go.** This is what makes context-dependent keys work: a command bound to `Delete` that is disabled while nothing is selected does nothing then, so `Delete` reaches the focused control (a text field deletes a character). Give `reason` to a command whose key should still be taken and explained while it is disabled.
4110
4111
  - **`repeat: true`** fires again on the keyboard's auto-repeat while the key is held; without it a binding fires once per press.
4111
4112
  - **Some keys never reach a binding.** The system takes some keys first, and the standard close keys close a tool window, the floating sidebar or the Options window before any binding sees them (in the main window they are ordinary keys). Keys the system takes first lists them; default bindings avoid them.
4112
4113
 
@@ -4119,7 +4120,7 @@ Key names describe keys, not characters, with two deliberate exceptions:
4119
4120
  - **Option combinations match the physical key**, so `Alt+O` fires for ⌥O although that key types `ø`, and dead keys (⌥E, ⌥N…) fire too. On layouts that need Option to type a symbol (German ⌥5 = ``, ⌥L = `@`), a binding for the typed symbol (`"["`, `"@"`) wins over one for the physical key (`Alt+5`).
4120
4121
  - **`Ctrl` is portable, `Cmd` is not.** On macOS `Ctrl+X` fires for both ⌃X and ⌘X, `Cmd+X` only for ⌘X. On Windows `Cmd` is the Windows logo key, which the system mostly keeps, so write `Ctrl+…` for a binding that works on both systems.
4121
4122
 
4122
- Mouse bindings apply only over the video area. `Mouse:LeftDoubleClick:LeftHalf` and `:RightHalf` win over the plain double click; wheel bindings count accumulated scroll steps. The right button is reserved for the context menu, and a left drag in window mode moves the window instead of clicking. A `Mouse:LeftClick` fires on release, except when the same modifiers also have a double-click binding and the click's command is not checkable: then the player waits the system's double-click interval to tell a click from a double click. (A checkable command such as play/pause runs at once; a double click runs it twice, which restores its state, and the double-click binding still fires.) The player's defaults (player 0.5.2): a left click on the video is Play/Pause and nothing is bound to a double click (up to 0.5.1 a double click was Toggle Fullscreen); a click whose command is disabled does nothing.
4123
+ Mouse bindings apply only over the video area, except the side buttons `Mouse:X1` (back) and `Mouse:X2` (forward), which fire anywhere in the main window or the floating sidebar window, except while a menu is open, as in browsers (player 0.6.0; before, only over the video area). `Mouse:LeftDoubleClick:LeftHalf` and `:RightHalf` win over the plain double click; wheel bindings count accumulated scroll steps. The right button is reserved for the context menu, and a left drag in window mode moves the window instead of clicking. A `Mouse:LeftClick` fires on release, except when the same modifiers also have a double-click binding and the click's command is not checkable: then the player waits the system's double-click interval to tell a click from a double click. (A checkable command such as play/pause runs at once; a double click runs it twice, which restores its state, and the double-click binding still fires.) The player's defaults (player 0.5.2): a left click on the video is Play/Pause and nothing is bound to a double click (up to 0.5.1 a double click was Toggle Fullscreen); a click whose command is disabled does nothing.
4123
4124
 
4124
4125
  ##### The user's bindings
4125
4126
 
@@ -4144,7 +4145,7 @@ plugin.commands.add({
4144
4145
 
4145
4146
  #### The player's own commands
4146
4147
 
4147
- The player registers some commands itself, with the owner `host`: **Toggle Fullscreen**, **Leave Fullscreen**, **Quit**, **Toggle Sidebar** (the bottom bar's sidebar button, player 0.5.10) and the core playback actions (play/pause, stop, previous/next, frame step, relative seek, speed, volume, mute). They exist whether or not any plugin runs, and the user rebinds them like any other command.
4148
+ The player registers some commands itself, with the owner `host`: **Toggle Fullscreen** (`Escape` from player 0.6.0), **Enter Fullscreen** and **Leave Fullscreen** (player 0.6.0: no default key, each enabled only where it acts), **Quit**, **Toggle Sidebar** (the bottom bar's sidebar button, player 0.5.10) and the core playback actions (play/pause, stop, previous/next, frame step, relative seek, speed, volume, mute). They exist whether or not any plugin runs, and the user rebinds them like any other command.
4148
4149
 
4149
4150
  A plugin button that does what a core action does should run that action with plugin.host.run (capability `commands`): it applies the same checks and shows the same on-screen text as the menu item and the key, so a bottom bar's play button and the Space key behave identically. The action ids, their menu places and default keys are in Reference: commands; what they do to playback is in Playback.
4150
4151
 
@@ -4650,6 +4651,8 @@ From player 0.6.0 and SDK 1.5.44, a changed array (a list's rows) is sent as the
4650
4651
  - **Your Slint code must not write into the rows of an array property** (`rows[i].selected = true` in a handler). A whole write used to overwrite such a change on the next update; a row patch touches only the rows whose value changed in your plugin, so the edited row keeps the Slint-side value until your value for that row changes. Send the event to the plugin with a callback and change the row there.
4651
4652
  - **`set()` with an unchanged array sends the whole array**, as `set()` always sends: use it to pull a list back to your rows. A bound array whose rows did not change sends nothing.
4652
4653
 
4654
+ To find the changed rows the SDK encodes every row of a bound array on each update pass, which in a list of tens of thousands of rows is most of a pass. From SDK 1.5.47 it skips that for rows it can prove unchanged: a **deep-frozen** row object (`Object.freeze` on the row and on every object and array inside it, plain objects and arrays only, no getters or own `toJSON`; image and document handles may sit inside: they are immutable, so they need no freezing) that the bind function returns again is encoded once and then taken from a cache kept by the row object. To use it in a long list, keep each row as the same frozen object while it does not change and make a new one when it does (memoize by the row's id and the fields it shows). Nothing else changes: rows that are not frozen, or that hold a mutable part, are encoded on every pass as before, so a plugin that changes its rows in place keeps working.
4655
+
4653
4656
  ##### Two-way controls
4654
4657
 
4655
4658
  A control whose value both the user and the plugin change (a slider, a switch, a text field, a combo box) needs a **two-way binding to an `in-out` property**:
@@ -5817,6 +5820,7 @@ Every SDK release's CHANGELOG entry opens with who must change and what happens
5817
5820
 
5818
5821
  | Release | Who must change | Guide |
5819
5822
  | --- | --- | --- |
5823
+ | [1.5.47](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md#1547) | **Nobody.** No changes to the TypeScript API, `apiVersion` stays `vestra/1`, no new capability, no player version needed. | — |
5820
5824
  | [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
5825
  | [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. | — |
5822
5826
  | [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. | — |
@@ -6765,9 +6769,12 @@ interface CommandOptions {
6765
6769
  * `Home`, `End`, `PageUp`, `PageDown`, `ArrowLeft`/`Right`/`Up`/`Down`,
6766
6770
  * `Plus`, any other single symbol as typed (`">"`, not `"Shift+."`),
6767
6771
  * `Numpad0`–`Numpad9`, `NumpadPlus`, `NumpadMinus`, `NumpadMultiply`,
6768
- * `NumpadDivide`, `NumpadEnter`, `NumpadDecimal`, and the video-area mouse
6772
+ * `NumpadDivide`, `NumpadEnter`, `NumpadDecimal`, the video-area mouse
6769
6773
  * inputs `Mouse:LeftClick`, `Mouse:LeftDoubleClick[:LeftHalf|:RightHalf]`,
6770
- * `Mouse:MiddleClick`, `Mouse:X1`, `Mouse:X2`, `Mouse:WheelUp`/`Down`/`Left`/`Right`.
6774
+ * `Mouse:MiddleClick`, `Mouse:WheelUp`/`Down`/`Left`/`Right`, and the side
6775
+ * buttons `Mouse:X1` (back), `Mouse:X2` (forward), from 0.6.0 on anywhere
6776
+ * in the main window or the floating sidebar window, except while a menu
6777
+ * is open.
6771
6778
  *
6772
6779
  * Platforms: on macOS `Ctrl+X` fires for both ⌃X and ⌘X while `Cmd+X`
6773
6780
  * means ⌘X only; on Windows `Cmd` is the Windows logo key, so write
@@ -11252,13 +11259,13 @@ and the main window's fullscreen toggle.
11252
11259
  | --- | --- | --- |
11253
11260
  | `stop` | F4 | close the source |
11254
11261
  | `play-pause` | Space, a left click on the video (player 0.5.2) | pause / resume, replay after the end |
11255
- | `previous` / `next` | PageUp, Mouse:X1 / PageDown, Mouse:X2 | ask the sequence provider |
11262
+ | `previous` / `next` | PageUp, Mouse:X2 / PageDown, Mouse:X1 (from 0.6.0; up to 0.5.x X1 was previous and X2 next) | ask the sequence provider |
11256
11263
  | `frame-back` / `frame-forward` | D / F | `player.step("frame", …)` |
11257
11264
  | `seek-backward` / `seek-forward` | ← / → | relative seek by `setStepSeek` seconds (or `host.run`'s `seconds`), exact or to keyframes as `setStepSeek` says |
11258
11265
  | `rate-normal`, `rate-down`, `rate-up` | Z, X, C | 1×, ±0.1 within 0.25–4 |
11259
11266
  | `volume-up` / `volume-down` | ↑ / ↓, wheel | ±5 (`volume-up` stops at 100) |
11260
11267
  | `mute` | M | toggle mute |
11261
- | `fullscreen` | Enter, Alt+Enter, F11 | toggle the main window's fullscreen: enter it when windowed, leave it when fullscreen, as the Toggle Fullscreen command does (SDK 1.5.21, player 0.5.2; `unavailable` when the player has no window) |
11268
+ | `fullscreen` | Escape (from 0.6.0; up to 0.5.x Enter, Alt+Enter, F11) | toggle the main window's fullscreen: enter it when windowed, leave it when fullscreen, as the Toggle Fullscreen command does (SDK 1.5.21, player 0.5.2; `unavailable` when the player has no window) |
11262
11269
 
11263
11270
  In the binding overlay their keys are `host/<action>`. `fullscreen`
11264
11271
  changes no playback state: read the result from `window.state.fullscreen`
@@ -17625,7 +17632,9 @@ const BINDING_INPUTS: Readonly<{
17625
17632
  * Other named keys, matched by the physical key. `Plus` is the `+` key however it is typed; the `Numpad…` names are the numeric keypad only, never the main keyboard.
17626
17633
  */
17627
17634
  readonly named: readonly ["Space", "Enter", "Tab", "Escape", "Backspace", "Delete", "Insert", "Home", "End", "PageUp", "PageDown", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Plus", ...string[], "NumpadPlus", "NumpadMinus", "NumpadMultiply", "NumpadDivide", "NumpadEnter", "NumpadDecimal"];
17628
- /** Mouse inputs on the video area. `:LeftHalf` and `:RightHalf` tell the halves of the video apart for a double click. */
17635
+ /**
17636
+ * Mouse inputs on the video area; the side buttons `Mouse:X1` (back) and `Mouse:X2` (forward) anywhere in the main window or the floating sidebar window, except while a menu is open (player 0.6.0). `:LeftHalf` and `:RightHalf` tell the halves of the video apart for a double click.
17637
+ */
17629
17638
  readonly mouse: readonly ["Mouse:LeftClick", "Mouse:LeftDoubleClick", "Mouse:LeftDoubleClick:LeftHalf", "Mouse:LeftDoubleClick:RightHalf", "Mouse:MiddleClick", "Mouse:X1", "Mouse:X2", "Mouse:WheelUp", "Mouse:WheelDown", "Mouse:WheelLeft", "Mouse:WheelRight"];
17630
17639
  }>;
17631
17640
  ```
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # Vestra Player SDK
2
2
 
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.
3
+ > @vestra-player/sdk 1.5.47: 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
 
@@ -80,7 +80,7 @@ export default async function activate(plugin: Plugin) {
80
80
  - `video.upscaling`: VideoUpscaling.state/set/onChange
81
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–2021; TestHost: L15484.
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: L15491.
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 L5954.
111
+ - Others: PluginError, llms-full.txt L5958.
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
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
118
+ - Reference: Manifest L2218–2292; Capabilities L2293–2353; Limits L2354–2499; Commands, menus and bindings L2500–3026; Platforms L3027–3057; Theme L3058–3407; Command line L3408–3465; Error codes L3466–3513; Translations L3514–3606; Test host L3607–3793
119
+ - Explanation: How a plugin runs L3794–3996; Commands, menus and key bindings L3997–4151; Playback state, controls and sources L4152–4311; Video and audio processing L4312–4432; Windows, panels, settings pages, dialogs and the OSD L4433–4697; GPU and software rendering L4698–4714; The player's Rust core L4715–5056; How the player runs and talks to plugins L5057–5396
120
+ - Guidelines: Plugin rules L5397–5408; Interface guidelines L5409–5525; Menu guidelines L5526–5584
121
+ - Upgrading: Migrate a plugin to English source text L5585–5734; Migrating off package rollback (1.5.16, removed in 1.5.17) L5735–5812; Who must change, release by release L5813–5880
122
+ - [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L5881–15164
123
+ - [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L15165–18029
124
124
 
125
125
  ## API
126
126
 
127
127
  Where each `plugin.<module>` is declared:
128
128
 
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.
129
+ - Plugin L6297, Scope L6033, PluginError L5958, Disposable L5896
130
+ - Commands L6890; When L6484; Windows L7836; Panels L9282; Dialogs L9952; Player L10693; video: VideoFilter L11573, VideoView L11673, RenderOptions L11760, VideoShaders L11838, VideoUpscaling L12196; audio: AudioFilter L11618; Subtitles L12432; media: MediaCapture L12836; Resolvers L13066; Packages L13468; Osd L11438; Host L11280; Clipboard L13797; Power L13884; Tools L13943; Storage L14095; System L14294; Secrets L14374; window: MainWindow L9599; App L9779; Rendering L14637; Bindings L13696; Ui L7182; Timeline L9511; Drops L8529; Appearance L8610; I18n L8843; Settings L9126.
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. 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
136
+ - hello: The README Quick start: one menu command and an on-screen message. L18464–18559
137
+ - blur: A tool window with one slider that blurs the playing video. L18560–18827
138
+ - signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L18828–19166
139
+ - bookmark: A tool window bound to the playback state: remember the position and jump back to it. L19167–19359
140
+ - panel-menu: A sidebar panel with its own right-click menu. L19360–19574
141
+ - menus: Radio menu items, separator groups and a menu item whose title changes. L19575–19740
142
+ - theme-widgets: A tool window drawn with the player's theme and widgets. L19741–19910
143
+ - markdown: A window that shows a Markdown document. L19911–20113
144
+ - i18n: A plugin in the player's language: English source text, a Chinese translation. L20114–20287
145
145
 
146
146
  ## Optional
147
147
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vestra-player/sdk",
3
- "version": "1.5.46",
3
+ "version": "1.5.47",
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": {