@vestra-player/sdk 1.5.20 → 1.5.21
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 +11 -0
- package/dist/commands.js +2 -2
- package/dist/plugin/services.js +1 -0
- package/dist/plugin/testing.js +9 -1
- package/dist/plugin/types.d.ts +10 -4
- package/llms-full.txt +23 -13
- package/llms.txt +19 -19
- package/package.json +1 -1
- package/slint/vestra/icons.slint +3 -0
- package/slint/vestra/widgets.slint +19 -30
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.5.21
|
|
4
|
+
|
|
5
|
+
**Who must change: nobody.** Plugins built on earlier SDKs keep working unchanged; the additions need player 0.5.2. Additive and bug fixes; `apiVersion` stays `vestra/1`.
|
|
6
|
+
|
|
7
|
+
- **`Host.run("fullscreen")`** (player 0.5.2; requested by the playback plugin for a bottom-bar button): toggles the main window's fullscreen exactly like the Toggle Fullscreen command (Enter, F11): in when windowed, out when fullscreen. Read the result from `window.state.fullscreen`. `unavailable` when the player has no window; players before 0.5.2 reject the id with `invalid`, so set `"minPlayerVersion": "0.5.2"`. `HostAction` gains `"fullscreen"`.
|
|
8
|
+
- **Default mouse bindings** (player 0.5.2, user ruling): a left click on the video is Play/Pause (`Mouse:LeftClick`, fired on release) and nothing is bound to a double click; Toggle Fullscreen keeps `Enter`, `Alt+Enter`, `F11`. `BUILTIN_COMMANDS` says so. A plugin that declared `Mouse:LeftClick` itself is shadowed by the player's default, as for any key the player binds; users' own bindings are unchanged.
|
|
9
|
+
- **`ToolTipArea` no longer swallows a press** (`slint/vestra/widgets.slint`, the player's widget library; bug fix): the tip was a `PopupWindow`, so while it showed, the first press anywhere only closed it, and it took the keyboard focus. It is now Slint's input-transparent tooltip: every press reaches the control under the pointer. It shows after about half a second (was 600 ms), and `showing` follows that delay closely. No API change.
|
|
10
|
+
- **Icons `fullscreen` and `exit-fullscreen`** in `slint/vestra/icons.slint` (14 × 12, the V-Line style).
|
|
11
|
+
- **`TestHost`**: `host.run("fullscreen")` flips `host.mainWindow.fullscreen` and emits `window.state` (recorded in `coreRuns`); `host/play-pause` declares `Space` and `Mouse:LeftClick`.
|
|
12
|
+
- Docs: *Commands* (the player's mouse defaults), *Playback* (a fullscreen button), the Theme and widgets example (the tooltip); generated tables and `llms.txt` / `llms-full.txt` regenerated.
|
|
13
|
+
|
|
3
14
|
## 1.5.20
|
|
4
15
|
|
|
5
16
|
Republishes 1.5.19, which was tagged but never published: its API documentation build failed (an example title and four undocumented `IMAGE_LIMITS` fields). Documentation only; the code is the same as 1.5.19 below.
|
package/dist/commands.js
CHANGED
|
@@ -142,7 +142,7 @@ vestra.playback | reopen | Reopen Current/Last File | Ctrl+Y
|
|
|
142
142
|
vestra.playback | copy-name | Copy to Clipboard ▸ File Name
|
|
143
143
|
vestra.playback | copy-folder | Copy to Clipboard ▸ Folder Path
|
|
144
144
|
vestra.playback | copy-path | Copy to Clipboard ▸ Full Path
|
|
145
|
-
host | play-pause | Playback ▸ Play/Pause | Space
|
|
145
|
+
host | play-pause | Playback ▸ Play/Pause | Space, Mouse:LeftClick
|
|
146
146
|
host | previous | Playback ▸ Previous | PageUp, Mouse:X1
|
|
147
147
|
host | next | Playback ▸ Next | PageDown, Mouse:X2
|
|
148
148
|
host | frame-back | Playback ▸ Seek ▸ Previous Frame | D
|
|
@@ -372,7 +372,7 @@ vestra.visualizer | audio-cover | Audio ▸ Show Album Cover for Audio Only
|
|
|
372
372
|
vestra.nes | nes.open | Emulator ▸ Open NES ROM…
|
|
373
373
|
vestra.nes | nes.stop | Emulator ▸ Stop NES
|
|
374
374
|
vestra.nes | nes.window | Emulator ▸ NES Tools…
|
|
375
|
-
host | fullscreen | Toggle Fullscreen | Enter, Alt+Enter, F11
|
|
375
|
+
host | fullscreen | Toggle Fullscreen | Enter, Alt+Enter, F11
|
|
376
376
|
vestra.window | pip | Screen ▸ Picture-in-Picture
|
|
377
377
|
vestra.window | mini | Screen ▸ Mini Size | \`
|
|
378
378
|
vestra.window | size.0.5 | Screen ▸ 0.5× | 1
|
package/dist/plugin/services.js
CHANGED
package/dist/plugin/testing.js
CHANGED
|
@@ -1375,7 +1375,7 @@ export class TestHost {
|
|
|
1375
1375
|
["Playback", "Play/Pause"],
|
|
1376
1376
|
201,
|
|
1377
1377
|
"domain",
|
|
1378
|
-
["Space"],
|
|
1378
|
+
["Space", "Mouse:LeftClick"],
|
|
1379
1379
|
false,
|
|
1380
1380
|
],
|
|
1381
1381
|
[
|
|
@@ -2735,6 +2735,7 @@ export class TestHost {
|
|
|
2735
2735
|
"volume-up",
|
|
2736
2736
|
"volume-down",
|
|
2737
2737
|
"mute",
|
|
2738
|
+
"fullscreen",
|
|
2738
2739
|
];
|
|
2739
2740
|
if (!actions.includes(String(p.action)))
|
|
2740
2741
|
throw new HostError("invalid", `unknown host action ${p.action}`);
|
|
@@ -2747,6 +2748,13 @@ export class TestHost {
|
|
|
2747
2748
|
throw new HostError("invalid", "seconds must be 0.1..3600 in tenths");
|
|
2748
2749
|
seconds = p.seconds;
|
|
2749
2750
|
}
|
|
2751
|
+
// SDK 1.5.21: the main window's Toggle Fullscreen, like Enter: in when
|
|
2752
|
+
// windowed, out when fullscreen, then `window.state`.
|
|
2753
|
+
if (p.action === "fullscreen") {
|
|
2754
|
+
this.coreRuns.push("fullscreen");
|
|
2755
|
+
this.setMainWindow({ fullscreen: !this.mainWindow.fullscreen });
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2750
2758
|
this.#runCore(String(p.action), seconds);
|
|
2751
2759
|
},
|
|
2752
2760
|
"player.setStepSeek": (p) => {
|
package/dist/plugin/types.d.ts
CHANGED
|
@@ -3877,22 +3877,28 @@ export interface Player {
|
|
|
3877
3877
|
setAudioDevice(id: string | null): Promise<void>;
|
|
3878
3878
|
}
|
|
3879
3879
|
/**
|
|
3880
|
-
* The core's basic playback actions (menu commands owned by the player)
|
|
3880
|
+
* The core's basic playback actions (menu commands owned by the player),
|
|
3881
|
+
* and the main window's fullscreen toggle.
|
|
3881
3882
|
*
|
|
3882
3883
|
* | action | default bindings | behaviour |
|
|
3883
3884
|
* | --- | --- | --- |
|
|
3884
3885
|
* | `stop` | F4 | close the source |
|
|
3885
|
-
* | `play-pause` | Space | pause / resume, replay after the end |
|
|
3886
|
+
* | `play-pause` | Space, a left click on the video (player 0.5.2) | pause / resume, replay after the end |
|
|
3886
3887
|
* | `previous` / `next` | PageUp, Mouse:X1 / PageDown, Mouse:X2 | ask the sequence provider |
|
|
3887
3888
|
* | `frame-back` / `frame-forward` | D / F | `player.step("frame", …)` |
|
|
3888
3889
|
* | `seek-backward` / `seek-forward` | ← / → | relative seek by `setStepSeek` seconds (or `host.run`'s `seconds`), exact or to keyframes as `setStepSeek` says |
|
|
3889
3890
|
* | `rate-normal`, `rate-down`, `rate-up` | Z, X, C | 1×, ±0.1 within 0.25–4 |
|
|
3890
3891
|
* | `volume-up` / `volume-down` | ↑ / ↓, wheel | ±5 (`volume-up` stops at 100) |
|
|
3891
3892
|
* | `mute` | M | toggle mute |
|
|
3893
|
+
* | `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) |
|
|
3892
3894
|
*
|
|
3893
|
-
* In the binding overlay their keys are `host/<action>`.
|
|
3895
|
+
* In the binding overlay their keys are `host/<action>`. `fullscreen`
|
|
3896
|
+
* changes no playback state: read the result from `window.state.fullscreen`
|
|
3897
|
+
* (`plugin.window.onChange`), which also changes when the user toggles it.
|
|
3898
|
+
* Players before 0.5.2 reject it with `invalid`: set
|
|
3899
|
+
* `"minPlayerVersion": "0.5.2"` when you use it.
|
|
3894
3900
|
*/
|
|
3895
|
-
export type HostAction = "play-pause" | "stop" | "previous" | "next" | "frame-back" | "frame-forward" | "seek-backward" | "seek-forward" | "rate-down" | "rate-up" | "rate-normal" | "volume-up" | "volume-down" | "mute";
|
|
3901
|
+
export type HostAction = "play-pause" | "stop" | "previous" | "next" | "frame-back" | "frame-forward" | "seek-backward" | "seek-forward" | "rate-down" | "rate-up" | "rate-normal" | "volume-up" | "volume-down" | "mute" | "fullscreen";
|
|
3896
3902
|
/** `plugin.host`: the player's own core actions. */
|
|
3897
3903
|
export interface Host {
|
|
3898
3904
|
/**
|
package/llms-full.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @vestra-player/sdk 1.5.
|
|
1
|
+
# @vestra-player/sdk 1.5.21: 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
|
|
|
@@ -445,7 +445,7 @@ Key names describe keys, not characters, with two deliberate exceptions:
|
|
|
445
445
|
- **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`).
|
|
446
446
|
- **`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.
|
|
447
447
|
|
|
448
|
-
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.)
|
|
448
|
+
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.
|
|
449
449
|
|
|
450
450
|
##### The user's bindings
|
|
451
451
|
|
|
@@ -579,7 +579,7 @@ The player's **Previous** and **Next** (menu, keys, the bottom bar) are not tied
|
|
|
579
579
|
|
|
580
580
|
#### Core actions
|
|
581
581
|
|
|
582
|
-
Play/pause, stop, previous/next, frame steps, relative seeks, speed, volume and mute are **core actions**: commands the player registers itself, so they work with no plugin running. plugin.host.run(action) runs one exactly as its menu item or key would, with the same checks and the same on-screen text. A plugin's play button should call `host.run("play-pause")` rather than `setPaused`, so that it behaves like the Space key in every case (restart after the end, the "Paused" message, disabled without a source).
|
|
582
|
+
Play/pause, stop, previous/next, frame steps, relative seeks, speed, volume and mute are **core actions**: commands the player registers itself, so they work with no plugin running. plugin.host.run(action) runs one exactly as its menu item or key would, with the same checks and the same on-screen text. A plugin's play button should call `host.run("play-pause")` rather than `setPaused`, so that it behaves like the Space key in every case (restart after the end, the "Paused" message, disabled without a source). A fullscreen button calls `host.run("fullscreen")` (player 0.5.2), which toggles the main window like Enter; show the button's state from `window.state.fullscreen`.
|
|
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
|
|
|
@@ -2176,6 +2176,7 @@ The table lists the API whose documentation names a player version, newest last:
|
|
|
2176
2176
|
| 0.4.2 | Resolvers.fileTypes, Resolvers.onFileTypesChange |
|
|
2177
2177
|
| 0.4.3 | CommandOptions.path, PropValue, View.set, Appearance.setLanguage, TemplateArgs, Text, ConfirmOptions.args, OsdPanel.set, OsdPanelOptions.maxColumns, Osd.show |
|
|
2178
2178
|
| 0.5.1 | ImageRef, ImageOptions.maxSide, PropValue, Ui.image, Ui.remoteImage, SlotState.reason, Panel.setInteraction, PlaybackStats.presentedFps, Player.setStepSeek, Host.run, Packages.reload |
|
|
2179
|
+
| 0.5.2 | HostAction |
|
|
2179
2180
|
|
|
2180
2181
|
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).
|
|
2181
2182
|
|
|
@@ -2410,7 +2411,7 @@ Every command the player (`host`) and its built-in plugins register when the pla
|
|
|
2410
2411
|
| Copy to Clipboard ▸ File Name | | `vestra.playback/copy-name` |
|
|
2411
2412
|
| Copy to Clipboard ▸ Folder Path | | `vestra.playback/copy-folder` |
|
|
2412
2413
|
| Copy to Clipboard ▸ Full Path | | `vestra.playback/copy-path` |
|
|
2413
|
-
| Playback ▸ Play/Pause | `Space` | `host/play-pause` |
|
|
2414
|
+
| Playback ▸ Play/Pause | `Space`, `Mouse:LeftClick` | `host/play-pause` |
|
|
2414
2415
|
| Playback ▸ Previous | `PageUp`, `Mouse:X1` | `host/previous` |
|
|
2415
2416
|
| Playback ▸ Next | `PageDown`, `Mouse:X2` | `host/next` |
|
|
2416
2417
|
| Playback ▸ Seek ▸ Previous Frame | `D` | `host/frame-back` |
|
|
@@ -2640,7 +2641,7 @@ Every command the player (`host`) and its built-in plugins register when the pla
|
|
|
2640
2641
|
| Emulator ▸ Open NES ROM… | | `vestra.nes/nes.open` |
|
|
2641
2642
|
| Emulator ▸ Stop NES | | `vestra.nes/nes.stop` |
|
|
2642
2643
|
| Emulator ▸ NES Tools… | | `vestra.nes/nes.window` |
|
|
2643
|
-
| Toggle Fullscreen | `Enter`, `Alt+Enter`, `F11
|
|
2644
|
+
| Toggle Fullscreen | `Enter`, `Alt+Enter`, `F11` | `host/fullscreen` |
|
|
2644
2645
|
| Screen ▸ Picture-in-Picture | | `vestra.window/pip` |
|
|
2645
2646
|
| Screen ▸ Mini Size | ``` | `vestra.window/mini` |
|
|
2646
2647
|
| Screen ▸ 0.5× | `1` | `vestra.window/size.0.5` |
|
|
@@ -2753,7 +2754,7 @@ The player's own playback commands, which plugin.host.run runs by id (capability
|
|
|
2753
2754
|
| Action | Menu item | Default bindings |
|
|
2754
2755
|
| --- | --- | --- |
|
|
2755
2756
|
| `stop` | Close | `F4` |
|
|
2756
|
-
| `play-pause` | Playback ▸ Play/Pause | `Space` |
|
|
2757
|
+
| `play-pause` | Playback ▸ Play/Pause | `Space`, `Mouse:LeftClick` |
|
|
2757
2758
|
| `previous` | Playback ▸ Previous | `PageUp`, `Mouse:X1` |
|
|
2758
2759
|
| `next` | Playback ▸ Next | `PageDown`, `Mouse:X2` |
|
|
2759
2760
|
| `frame-back` | Playback ▸ Seek ▸ Previous Frame | `D` |
|
|
@@ -2766,6 +2767,7 @@ The player's own playback commands, which plugin.host.run runs by id (capability
|
|
|
2766
2767
|
| `volume-up` | Audio ▸ Volume + | `ArrowUp`, `Mouse:WheelUp` |
|
|
2767
2768
|
| `volume-down` | Audio ▸ Volume − | `ArrowDown`, `Mouse:WheelDown` |
|
|
2768
2769
|
| `mute` | Audio ▸ Mute | `M` |
|
|
2770
|
+
| `fullscreen` | Toggle Fullscreen | `Enter`, `Alt+Enter`, `F11` |
|
|
2769
2771
|
|
|
2770
2772
|
The player also owns **Toggle Fullscreen** (`host/fullscreen`), **Leave Fullscreen** (`host/exit-fullscreen`, `Escape`, only in fullscreen) and **Quit** (`host/quit`); their keys are in Built-in commands.
|
|
2771
2773
|
|
|
@@ -2940,17 +2942,19 @@ Icon { name: "close"; width: 20px; height: 20px; } // scaled
|
|
|
2940
2942
|
| `add` | 10 × 10 | 1.5px |
|
|
2941
2943
|
| `remove` | 10 × 10 | 1.5px |
|
|
2942
2944
|
| `sort` | 10 × 10 | 1.5px |
|
|
2945
|
+
| `fullscreen` | 14 × 12 | 1.5px |
|
|
2946
|
+
| `exit-fullscreen` | 14 × 12 | 1.5px |
|
|
2943
2947
|
|
|
2944
2948
|
#### Widgets
|
|
2945
2949
|
|
|
2946
2950
|
`@vestra/widgets.slint`: compact controls drawn with the theme. Other controls come from `std-widgets.slint`.
|
|
2947
2951
|
|
|
2948
|
-
**`ToolTipArea`**: Hover for
|
|
2952
|
+
**`ToolTipArea`**: Hover for about half a second to show `text` beside the pointer. The tip closes when the pointer leaves, or presses on content that does not take the press itself; it shows again on the next hover. It is Slint's input-transparent tooltip: every press reaches the control under the pointer, and the tip does not take the keyboard focus. (Up to SDK 1.5.20 the tip was a PopupWindow, which swallowed the first press after it showed and took the focus while it was open.)
|
|
2949
2953
|
|
|
2950
2954
|
| Member | Kind | Default | Note |
|
|
2951
2955
|
| --- | --- | --- | --- |
|
|
2952
2956
|
| `text` | in `string` | | |
|
|
2953
|
-
| `showing` | out `bool` | | The tip is showing (read-only). |
|
|
2957
|
+
| `showing` | out `bool` | | The tip is showing (read-only); it follows the tip's delay closely, not exactly. |
|
|
2954
2958
|
|
|
2955
2959
|
**`Button`**: Dialog button: text (21px, or 18px when `small`), or an icon button when `text` is empty and `icon` holds Path data drawn in an icon-width × icon-height viewbox (filled, or 1.5px round-capped lines when `stroked`, as the @vestra/icons.slint set). The caller sizes icon buttons.
|
|
2956
2960
|
|
|
@@ -5278,23 +5282,29 @@ interface Player {
|
|
|
5278
5282
|
|
|
5279
5283
|
### HostAction
|
|
5280
5284
|
|
|
5281
|
-
The core's basic playback actions (menu commands owned by the player)
|
|
5285
|
+
The core's basic playback actions (menu commands owned by the player),
|
|
5286
|
+
and the main window's fullscreen toggle.
|
|
5282
5287
|
|
|
5283
5288
|
| action | default bindings | behaviour |
|
|
5284
5289
|
| --- | --- | --- |
|
|
5285
5290
|
| `stop` | F4 | close the source |
|
|
5286
|
-
| `play-pause` | Space | pause / resume, replay after the end |
|
|
5291
|
+
| `play-pause` | Space, a left click on the video (player 0.5.2) | pause / resume, replay after the end |
|
|
5287
5292
|
| `previous` / `next` | PageUp, Mouse:X1 / PageDown, Mouse:X2 | ask the sequence provider |
|
|
5288
5293
|
| `frame-back` / `frame-forward` | D / F | `player.step("frame", …)` |
|
|
5289
5294
|
| `seek-backward` / `seek-forward` | ← / → | relative seek by `setStepSeek` seconds (or `host.run`'s `seconds`), exact or to keyframes as `setStepSeek` says |
|
|
5290
5295
|
| `rate-normal`, `rate-down`, `rate-up` | Z, X, C | 1×, ±0.1 within 0.25–4 |
|
|
5291
5296
|
| `volume-up` / `volume-down` | ↑ / ↓, wheel | ±5 (`volume-up` stops at 100) |
|
|
5292
5297
|
| `mute` | M | toggle mute |
|
|
5298
|
+
| `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) |
|
|
5293
5299
|
|
|
5294
|
-
In the binding overlay their keys are `host/<action>`.
|
|
5300
|
+
In the binding overlay their keys are `host/<action>`. `fullscreen`
|
|
5301
|
+
changes no playback state: read the result from `window.state.fullscreen`
|
|
5302
|
+
(`plugin.window.onChange`), which also changes when the user toggles it.
|
|
5303
|
+
Players before 0.5.2 reject it with `invalid`: set
|
|
5304
|
+
`"minPlayerVersion": "0.5.2"` when you use it.
|
|
5295
5305
|
|
|
5296
5306
|
```ts
|
|
5297
|
-
type HostAction = "play-pause" | "stop" | "previous" | "next" | "frame-back" | "frame-forward" | "seek-backward" | "seek-forward" | "rate-down" | "rate-up" | "rate-normal" | "volume-up" | "volume-down" | "mute";
|
|
5307
|
+
type HostAction = "play-pause" | "stop" | "previous" | "next" | "frame-back" | "frame-forward" | "seek-backward" | "seek-forward" | "rate-down" | "rate-up" | "rate-normal" | "volume-up" | "volume-down" | "mute" | "fullscreen";
|
|
5298
5308
|
```
|
|
5299
5309
|
|
|
5300
5310
|
### Host
|
|
@@ -9730,7 +9740,7 @@ From top to bottom:
|
|
|
9730
9740
|
- **The window.** A fixed `width`; `Theme.bg-panel` instead of a hard-coded colour, so the background follows the player's palette.
|
|
9731
9741
|
- **The properties.** `level` is `in-out` because both the plugin and the user change it; `label` is only written by the plugin. `level-changed` reports a drag; `reset` reports the reset buttons.
|
|
9732
9742
|
- **The layout.** `Theme.dialog-padding` and `Theme.font-body` give the spacing and text size of the player's dialogs.
|
|
9733
|
-
- **`ToolTipArea`** shows its `text` after the pointer rests on its content for 600 ms.
|
|
9743
|
+
- **`ToolTipArea`** shows its `text` after the pointer rests on its content for about half a second (600 ms before player 0.5.2). The tip never takes a press or the keyboard focus: a click goes to the control under the pointer even while the tip shows.
|
|
9734
9744
|
- **The sliders** are bound _two-way_ to `level` with `<=>`, so dragging one moves the other at once, inside Slint. `changed` passes the value to the plugin. A one-way binding (`value: root.level`) would be broken by Slint the first time the user moved the slider. `panel: true` is the panel style; without it, the bar style.
|
|
9735
9745
|
- **`Button`** with `text` is a dialog button; `small: true` is the 18-pixel one.
|
|
9736
9746
|
- **Icon buttons** have no `text`; `icon` is SVG-style path data drawn in an `icon-width` × `icon-height` box (14×12 by default). `stroked: true` draws lines instead of filling. `checked` draws the icon in the accent colour.
|
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.21: 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: L2120–
|
|
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–2184.
|
|
37
37
|
|
|
38
38
|
**main.ts**
|
|
39
39
|
|
|
@@ -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:
|
|
79
|
+
- No capability: `tools`, `storage`, `system`, `app`, `ui` (images and Markdown), `i18n`, reading window.state, appearance.theme and packages.list. Details: L2185–2227.
|
|
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: L1606–1771; TestHost:
|
|
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: L6855.
|
|
82
82
|
|
|
83
83
|
**Command line**
|
|
84
84
|
|
|
@@ -106,7 +106,7 @@ 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
|
|
109
|
+
- Others: PluginError, llms-full.txt L3126.
|
|
110
110
|
|
|
111
111
|
## Reference
|
|
112
112
|
|
|
@@ -115,30 +115,30 @@ export default async function activate(plugin: Plugin) {
|
|
|
115
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
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
117
|
- Guidelines: Interface guidelines L1937–2021; Menu guidelines L2022–2119
|
|
118
|
-
- Reference: Manifest L2120–
|
|
119
|
-
- [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html):
|
|
120
|
-
- [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html):
|
|
118
|
+
- Reference: Manifest L2120–2184; Capabilities L2185–2227; Limits L2228–2322; Commands, menus and bindings L2323–2791; Platforms L2792–2820; Theme L2821–3027; Command line L3028–3083
|
|
119
|
+
- [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L3084–6690
|
|
120
|
+
- [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L6691–8055
|
|
121
121
|
|
|
122
122
|
## API
|
|
123
123
|
|
|
124
124
|
Where each module of `plugin` (`plugin.<module>`) is declared:
|
|
125
125
|
|
|
126
|
-
- Plugin
|
|
127
|
-
- Commands
|
|
126
|
+
- Plugin L3318, Scope L3187, PluginError L3126, Disposable L3099
|
|
127
|
+
- Commands L3530; Windows L3760; Panels L4403; Dialogs L4689; Player L5137; video: VideoFilter L5443, VideoView L5506, RenderOptions L5548; audio: AudioFilter L5467; Subtitles L5646; media: MediaCapture L5806; Resolvers L5911; Packages L6153; Osd L5379; Host L5310; Clipboard L6285; Power L6305; Tools L6338; Storage L6381; System L6404; Secrets L6422; window: MainWindow L4526; App L4607; Bindings L6255; Ui L3635; Timeline L4483; Drops L4059; Appearance L4088; I18n L4230; Settings L4336.
|
|
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.
|
|
134
|
-
- blur: A tool window with one slider that blurs the playing video.
|
|
135
|
-
- signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone.
|
|
136
|
-
- bookmark: A tool window bound to the playback state: remember the position and jump back to it.
|
|
137
|
-
- panel-menu: A sidebar panel with its own right-click menu.
|
|
138
|
-
- menus: Radio menu items, separator groups and a menu item whose title changes.
|
|
139
|
-
- theme-widgets: A tool window drawn with the player's theme and widgets.
|
|
140
|
-
- markdown: A window that shows a Markdown document.
|
|
141
|
-
- i18n: A plugin in the player's language: English source text, a Chinese translation.
|
|
133
|
+
- hello: The README Quick start: one menu command and an on-screen message. L8479–8568
|
|
134
|
+
- blur: A tool window with one slider that blurs the playing video. L8569–8830
|
|
135
|
+
- signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L8831–9163
|
|
136
|
+
- bookmark: A tool window bound to the playback state: remember the position and jump back to it. L9164–9348
|
|
137
|
+
- panel-menu: A sidebar panel with its own right-click menu. L9349–9554
|
|
138
|
+
- menus: Radio menu items, separator groups and a menu item whose title changes. L9555–9714
|
|
139
|
+
- theme-widgets: A tool window drawn with the player's theme and widgets. L9715–9878
|
|
140
|
+
- markdown: A window that shows a Markdown document. L9879–10073
|
|
141
|
+
- i18n: A plugin in the player's language: English source text, a Chinese translation. L10074–10241
|
|
142
142
|
|
|
143
143
|
## Optional
|
|
144
144
|
|
package/package.json
CHANGED
package/slint/vestra/icons.slint
CHANGED
|
@@ -45,6 +45,9 @@ export global Icons {
|
|
|
45
45
|
if name == "add" { return "M 5 1.5 V 8.5 M 1.5 5 H 8.5"; }
|
|
46
46
|
if name == "remove" { return "M 1.5 5 H 8.5"; }
|
|
47
47
|
if name == "sort" { return "M 3 1.5 V 8.5 M 1.2 6.7 L 3 8.5 L 4.8 6.7 M 7 8.5 V 1.5 M 5.2 3.3 L 7 1.5 L 8.8 3.3"; }
|
|
48
|
+
// Four corners pointing out (enter) or in (leave), the default 14 × 12 box.
|
|
49
|
+
if name == "fullscreen" { return "M 1.5 4.5 V 1.5 H 4.5 M 9.5 1.5 H 12.5 V 4.5 M 12.5 7.5 V 10.5 H 9.5 M 4.5 10.5 H 1.5 V 7.5"; }
|
|
50
|
+
if name == "exit-fullscreen" { return "M 4.5 1.5 V 4.5 H 1.5 M 9.5 1.5 V 4.5 H 12.5 M 12.5 7.5 H 9.5 V 10.5 M 1.5 7.5 H 4.5 V 10.5"; }
|
|
48
51
|
return "";
|
|
49
52
|
}
|
|
50
53
|
// Line width.
|
|
@@ -5,15 +5,20 @@
|
|
|
5
5
|
import { TextEdit } from "std-widgets.slint";
|
|
6
6
|
import { Theme } from "theme.slint";
|
|
7
7
|
|
|
8
|
-
// Hover for
|
|
9
|
-
// the pointer leaves or presses
|
|
8
|
+
// Hover for about half a second to show `text` beside the pointer. The tip
|
|
9
|
+
// closes when the pointer leaves, or presses on content that does not take
|
|
10
|
+
// the press itself; it shows again on the next hover. It is Slint's
|
|
11
|
+
// input-transparent tooltip: every press reaches the control under the
|
|
12
|
+
// pointer, and the tip does not take the keyboard focus. (Up to SDK 1.5.20 the tip was a
|
|
13
|
+
// PopupWindow, which swallowed the first press after it showed and took the
|
|
14
|
+
// focus while it was open.)
|
|
10
15
|
export component ToolTipArea {
|
|
11
16
|
in property <string> text;
|
|
12
|
-
// The tip is showing (read-only)
|
|
17
|
+
// The tip is showing (read-only); it follows the tip's delay closely,
|
|
18
|
+
// not exactly.
|
|
13
19
|
out property <bool> showing;
|
|
14
|
-
//
|
|
15
|
-
// (Never assign the timer's `running`: that drops its binding
|
|
16
|
-
// tip would show only once.)
|
|
20
|
+
// Pressed during this hover: no tip until the pointer leaves.
|
|
21
|
+
// (Never assign the timer's `running`: that drops its binding.)
|
|
17
22
|
private property <bool> done;
|
|
18
23
|
area := TouchArea {
|
|
19
24
|
width: 100%; height: 100%;
|
|
@@ -22,40 +27,24 @@ export component ToolTipArea {
|
|
|
22
27
|
if !self.has-hover {
|
|
23
28
|
root.done = false;
|
|
24
29
|
root.showing = false;
|
|
25
|
-
tip.close();
|
|
26
30
|
}
|
|
27
31
|
}
|
|
28
32
|
pointer-event(event) => {
|
|
29
33
|
if event.kind == PointerEventKind.down {
|
|
30
34
|
root.done = true;
|
|
31
35
|
root.showing = false;
|
|
32
|
-
tip.close();
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
triggered => {
|
|
40
|
-
root.done = true;
|
|
41
|
-
root.showing = true;
|
|
42
|
-
tip.show();
|
|
38
|
+
// Removing it closes an open tip.
|
|
39
|
+
if root.text != "" && !root.done: Tooltip {
|
|
40
|
+
// Interpolated text is plain: `*` or `_` in it are not markup.
|
|
41
|
+
text: @markdown("\{root.text}");
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Rectangle {
|
|
50
|
-
background: Theme.bg-panel;
|
|
51
|
-
border-color: Theme.line;
|
|
52
|
-
border-width: 1px;
|
|
53
|
-
border-radius: Theme.radius-control;
|
|
54
|
-
HorizontalLayout {
|
|
55
|
-
padding-left: 5px; padding-right: 5px; padding-top: 2px; padding-bottom: 2px;
|
|
56
|
-
Text { text: root.text; color: Theme.text; font-size: Theme.font-body; }
|
|
57
|
-
}
|
|
58
|
-
}
|
|
44
|
+
Timer {
|
|
45
|
+
interval: 500ms;
|
|
46
|
+
running: area.has-hover && root.text != "" && !root.done && !root.showing;
|
|
47
|
+
triggered => { root.showing = true; }
|
|
59
48
|
}
|
|
60
49
|
}
|
|
61
50
|
|