@vestra-player/sdk 1.5.14 → 1.5.15
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 +13 -0
- package/dist/plugin/player.js +8 -0
- package/dist/plugin/testing.js +1 -0
- package/dist/plugin/types.d.ts +52 -8
- package/dist/subtitles.d.ts +5 -1
- package/dist/wire.d.ts +3 -0
- package/llms-full.txt +43 -10
- package/llms.txt +23 -23
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.5.15
|
|
4
|
+
|
|
5
|
+
**How many frames really reach the screen, and how the video is decoded** (player 0.5.1); every player error code documented; the fullscreen bottom bar's new behaviour. Additive; `apiVersion` stays `vestra/1`, and plugins need no change.
|
|
6
|
+
|
|
7
|
+
- **`PlaybackStats.presentedFps`**: new video frames the player window showed per second over the last second, measured by the player (draws of the main window that put a new picture on screen). `framesShown` counts the frames the video renderer produced, so it cannot show frames lost afterwards, for example a window that draws only every other frame: then `presentedFps` is about half of `video.fps`. `null` when the player cannot measure it (no window, the first second) and with players before 0.5.1.
|
|
8
|
+
- **`PlaybackStats.video.decoding`**: `"hardware"` or `"software"`, from mpv's `hwdec-current` (the method stays in `video.hwdec`, e.g. `"d3d11va-copy"`); `null` before a decoder runs. With players that do not send it, the SDK derives it from `hwdec`.
|
|
9
|
+
- `framesShown` and `framesDropped` say what they count (TSDoc only).
|
|
10
|
+
- **`TestHost`**: `host.stats` takes both fields; `presentedFps` is `null` by default, and `video.decoding` follows `video.hwdec` when a test leaves it out.
|
|
11
|
+
- **`PluginError`**: the table lists the player's remaining codes with their meaning: `activation`, `command`, `input-overflow`, `internal`, `javascript`, `slint`, `owner`, `pending`, `producer`, `resolution`, `revisionConflict`, `source-geometry`, `source-geometry-unsupported`, `source-unavailable` and `unknown-expired`. `pending`, `unknown-expired` and `revisionConflict` are mostly handled inside the SDK, but can reach a plugin.
|
|
12
|
+
- **`SubtitleStyle.offsetMs`**: the range is −600000…600000 ms (±10 minutes), positive shows subtitles later, and outside it the player fails with `invalid`.
|
|
13
|
+
- **The fullscreen bottom bar** (player 0.5.1): it shows only while the pointer is in the bar's own band at the bottom of the screen, at once on entering and hidden 500 ms after leaving; keys and pointer motion elsewhere no longer reveal it, and `Panel.setInteraction` locks keep it. `SlotState.reason` `"idle"`, `Panel.setInteraction` and `Panels.mount` (`"bottom"`) said "hides after 3 seconds without activity".
|
|
14
|
+
- `llms.txt` names the declaration files by path again (`node_modules/@vestra-player/sdk/dist/plugin/types.d.ts` for the API, `dist/plugin/testing.d.ts` for TestHost) instead of `dist/plugin/*.d.ts`.
|
|
15
|
+
|
|
3
16
|
## 1.5.14
|
|
4
17
|
|
|
5
18
|
**The documentation site in seven groups, with generated reference tables.** A documentation release; `apiVersion` stays `vestra/1`, and plugins need no change. Everything a plugin author needs is now on the [documentation site](https://vestrasys.github.io/vestra-player-sdk/) once, in English.
|
package/dist/plugin/player.js
CHANGED
|
@@ -81,6 +81,12 @@ function view(raw) {
|
|
|
81
81
|
raws.set(state, raw);
|
|
82
82
|
return state;
|
|
83
83
|
}
|
|
84
|
+
/** `stats().video.decoding` from `hwdec` for players that do not send it. */
|
|
85
|
+
function decoding(hwdec) {
|
|
86
|
+
if (hwdec === null || hwdec === undefined || hwdec === "")
|
|
87
|
+
return null;
|
|
88
|
+
return hwdec === "no" ? "software" : "hardware";
|
|
89
|
+
}
|
|
84
90
|
export const rawOf = (state) => raws.get(state);
|
|
85
91
|
export const sameStamp = (a, b) => a.generation === b.generation && a.intentVersion === b.intentVersion;
|
|
86
92
|
function sourceFailure(error) {
|
|
@@ -474,6 +480,7 @@ export function player(scope) {
|
|
|
474
480
|
session: raw.session,
|
|
475
481
|
framesShown: raw.framesShown,
|
|
476
482
|
framesDropped: raw.framesDropped,
|
|
483
|
+
presentedFps: n(raw.presentedFps),
|
|
477
484
|
video: raw.video && {
|
|
478
485
|
codec: raw.video.codec,
|
|
479
486
|
width: raw.video.width,
|
|
@@ -487,6 +494,7 @@ export function player(scope) {
|
|
|
487
494
|
displayFps: n(raw.video.displayFps),
|
|
488
495
|
bitrate: n(raw.video.bitrate),
|
|
489
496
|
hwdec: n(raw.video.hwdec),
|
|
497
|
+
decoding: raw.video.decoding ?? decoding(raw.video.hwdec),
|
|
490
498
|
transfer: n(raw.video.transfer),
|
|
491
499
|
},
|
|
492
500
|
audio: raw.audio && {
|
package/dist/plugin/testing.js
CHANGED
package/dist/plugin/types.d.ts
CHANGED
|
@@ -81,6 +81,19 @@ export interface Disposable {
|
|
|
81
81
|
* | `host` | Any other failure inside the player; `message` is the player's reason. |
|
|
82
82
|
* | `disabled` | The plugin is being stopped; pending requests fail with it. |
|
|
83
83
|
* | `unknown`, `rejected`, `expired` | After a transport problem the SDK could not confirm the outcome (does not happen in normal operation). |
|
|
84
|
+
* | `activation` | The plugin opened a tool window while its activation was still pending and the player could not track it. |
|
|
85
|
+
* | `command` | The player could not run or update a command it no longer knows for this plugin (removed meanwhile, or another plugin's). |
|
|
86
|
+
* | `input-overflow` | `openStream` input: the player's queue of physical key transitions was full; the input was revoked and its keys released. |
|
|
87
|
+
* | `internal` | An internal step of the player failed (keeping an operation's result, a subtitle or media job); `message` has the reason. |
|
|
88
|
+
* | `javascript`, `slint` | {@link Packages.validate}: the package's entry module does not pass `node --check` / one of its Slint files does not compile; `message` has the diagnostics. |
|
|
89
|
+
* | `owner` | A resolver answered a request that belongs to another plugin's resolver. |
|
|
90
|
+
* | `pending` | An operation with the same token is still running in the player. The SDK waits and asks again, so it rarely reaches a plugin. |
|
|
91
|
+
* | `producer` | `openStream`: the player refused or lost the generated stream; `message` has the reason. |
|
|
92
|
+
* | `resolution` | A file or web resolver's result could not be opened; `message` has the reason. |
|
|
93
|
+
* | `revisionConflict` | {@link Packages}: the installed revision changed since it was read (another install, rollback or uninstall ran). Read again and retry; the SDK passes the revision it read, so this reaches plugins that act on old data. |
|
|
94
|
+
* | `source-geometry`, `source-geometry-unsupported` | The source's picture size or rotation could not be applied: invalid decoder dimensions / a rotation that is not a multiple of 90°. |
|
|
95
|
+
* | `source-unavailable` | The source is not ready (still loading, or its time or native binding is not available yet). |
|
|
96
|
+
* | `unknown-expired` | The player no longer knows the operation or snapshot (it expired or was released). The SDK maps it to `unknownExpired` results where it can; do not resubmit the operation blindly. |
|
|
84
97
|
*
|
|
85
98
|
* Errors thrown by handlers the SDK invokes go to {@link Scope.onError}. A
|
|
86
99
|
* rejected promise you forgot to `await` is only logged; it never crashes
|
|
@@ -1345,8 +1358,10 @@ export interface SlotState {
|
|
|
1345
1358
|
* - `fullscreen`: the sidebar's fullscreen overlay is collapsed and pops
|
|
1346
1359
|
* out when the pointer reaches the right edge; treat it as "on" for a
|
|
1347
1360
|
* toggle button;
|
|
1348
|
-
* - `idle`: the bottom bar in fullscreen
|
|
1349
|
-
*
|
|
1361
|
+
* - `idle`: the bottom bar in fullscreen while the pointer is outside the
|
|
1362
|
+
* bar's own band at the bottom of the screen (player 0.5.1: keys and
|
|
1363
|
+
* pointer motion elsewhere do not bring it back; before 0.5.1 it hid after
|
|
1364
|
+
* 3 seconds without activity).
|
|
1350
1365
|
*/
|
|
1351
1366
|
reason: "userHidden" | "space" | "fullscreen" | "idle" | null;
|
|
1352
1367
|
/** The sidebar floats in its own window; always `false` for the bottom bar. */
|
|
@@ -1783,8 +1798,11 @@ export interface Panel extends View, Disposable {
|
|
|
1783
1798
|
* Keep the panel on screen while the user works in it.
|
|
1784
1799
|
*
|
|
1785
1800
|
* @remarks
|
|
1786
|
-
*
|
|
1787
|
-
* the
|
|
1801
|
+
* In fullscreen the bottom bar shows only while the pointer is in the bar's
|
|
1802
|
+
* own band at the bottom of the screen: at once when the pointer enters it,
|
|
1803
|
+
* hidden 500 ms after it leaves (player 0.5.1; keys and pointer motion
|
|
1804
|
+
* elsewhere do not reveal it), and the fullscreen sidebar overlay collapses
|
|
1805
|
+
* when the pointer leaves it. A lock keeps the bar shown. Set a
|
|
1788
1806
|
* lock while a text field has focus, a drag is in progress or a popup is
|
|
1789
1807
|
* open, and clear it afterwards. Locks are merged with the earlier ones;
|
|
1790
1808
|
* the last value of each wins. The player already locks a panel while the
|
|
@@ -2696,7 +2714,9 @@ export interface Panels {
|
|
|
2696
2714
|
* - `"bottom"`: under the video, as wide as the video column, as tall as the
|
|
2697
2715
|
* component's preferred height. It may draw above its slot into the video
|
|
2698
2716
|
* area (negative `y`); the player does not clip it. In fullscreen it
|
|
2699
|
-
* floats over the video and
|
|
2717
|
+
* floats over the video and shows only while the pointer is in its band
|
|
2718
|
+
* at the bottom of the screen (hidden 500 ms after the pointer leaves;
|
|
2719
|
+
* {@link Panel.setInteraction} locks keep it).
|
|
2700
2720
|
* - `"sidebar"`: right of the video, the window's full height, as wide as the
|
|
2701
2721
|
* user drags it (at least 317). The user can detach it into a floating
|
|
2702
2722
|
* window titled `title`. Several plugins may mount here (player 0.4.x
|
|
@@ -3491,10 +3511,27 @@ export interface PlaybackStats {
|
|
|
3491
3511
|
backend: string;
|
|
3492
3512
|
/** The playback session number. */
|
|
3493
3513
|
session: number;
|
|
3494
|
-
/**
|
|
3514
|
+
/**
|
|
3515
|
+
* Frames the video renderer produced. Not all of them reach the screen: a
|
|
3516
|
+
* busy window shows only the newest one, so compare
|
|
3517
|
+
* {@link PlaybackStats.presentedFps | presentedFps}.
|
|
3518
|
+
*/
|
|
3495
3519
|
framesShown: number;
|
|
3496
|
-
/** Frames dropped, `null` when unknown. */
|
|
3520
|
+
/** Frames dropped by the backend (mpv), `null` when unknown. */
|
|
3497
3521
|
framesDropped: number | null;
|
|
3522
|
+
/**
|
|
3523
|
+
* New video frames the player window showed per second over the last
|
|
3524
|
+
* second, measured by the player itself: draws of the main window that put
|
|
3525
|
+
* a new picture on screen. Lower than `video.fps` when frames are lost
|
|
3526
|
+
* after decoding and rendering (the window could not keep up with the
|
|
3527
|
+
* source, or the display refreshes slower); `0` while paused. `null` when
|
|
3528
|
+
* the player cannot measure it (no window, the first second, players
|
|
3529
|
+
* before 0.5.1).
|
|
3530
|
+
*
|
|
3531
|
+
* @player 0.5.1
|
|
3532
|
+
* @since 1.5.15
|
|
3533
|
+
*/
|
|
3534
|
+
presentedFps: number | null;
|
|
3498
3535
|
/** Every field is the backend's own value, `null` when it has none. */
|
|
3499
3536
|
video: {
|
|
3500
3537
|
/** Codec name. */
|
|
@@ -3519,8 +3556,15 @@ export interface PlaybackStats {
|
|
|
3519
3556
|
displayFps: number | null;
|
|
3520
3557
|
/** Bits per second, updated per keyframe. */
|
|
3521
3558
|
bitrate: number | null;
|
|
3522
|
-
/** Hardware decoder in use, e.g. "videotoolbox"; "no" = software decoding. */
|
|
3559
|
+
/** Hardware decoder in use, e.g. "videotoolbox", "d3d11va-copy"; "no" = software decoding. */
|
|
3523
3560
|
hwdec: string | null;
|
|
3561
|
+
/**
|
|
3562
|
+
* How the video is decoded, from `hwdec`: `"hardware"` (the method is in
|
|
3563
|
+
* `hwdec`) or `"software"`; `null` before a decoder runs.
|
|
3564
|
+
*
|
|
3565
|
+
* @since 1.5.15 (with older players the SDK derives it from `hwdec`)
|
|
3566
|
+
*/
|
|
3567
|
+
decoding: "hardware" | "software" | null;
|
|
3524
3568
|
/** Transfer characteristic as mpv names it, e.g. "bt.1886", "pq", "hlg". */
|
|
3525
3569
|
transfer: string | null;
|
|
3526
3570
|
} | null;
|
package/dist/subtitles.d.ts
CHANGED
|
@@ -45,7 +45,11 @@ export type SubtitleStyle = {
|
|
|
45
45
|
outline: number;
|
|
46
46
|
/** Bottom margin 2–15 % of the video height. */
|
|
47
47
|
marginPercent: number;
|
|
48
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Timing offset in milliseconds, −600000…600000 (±10 minutes); positive
|
|
50
|
+
* shows the subtitles later. Outside the range the player refuses the
|
|
51
|
+
* style with `invalid`.
|
|
52
|
+
*/
|
|
49
53
|
offsetMs: number;
|
|
50
54
|
/** Bold text; default false. */
|
|
51
55
|
bold?: boolean;
|
package/dist/wire.d.ts
CHANGED
|
@@ -222,6 +222,8 @@ export interface PlaybackStats {
|
|
|
222
222
|
session: number;
|
|
223
223
|
framesShown: number;
|
|
224
224
|
framesDropped: number | null;
|
|
225
|
+
/** Player 0.5.1 and newer; the SDK fills in `null`. */
|
|
226
|
+
presentedFps?: number | null;
|
|
225
227
|
video: {
|
|
226
228
|
codec: string | null;
|
|
227
229
|
width: number | null;
|
|
@@ -235,6 +237,7 @@ export interface PlaybackStats {
|
|
|
235
237
|
displayFps?: number | null;
|
|
236
238
|
bitrate?: number | null;
|
|
237
239
|
hwdec?: string | null;
|
|
240
|
+
decoding?: "hardware" | "software" | null;
|
|
238
241
|
transfer?: string | null;
|
|
239
242
|
} | null;
|
|
240
243
|
audio: {
|
package/llms-full.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @vestra-player/sdk 1.5.
|
|
1
|
+
# @vestra-player/sdk 1.5.15: 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
|
|
|
@@ -488,6 +488,7 @@ Reading it needs `playback.read`; following it needs `events` too:
|
|
|
488
488
|
- The SDK reads the state once before `activate` and, with `events`, keeps `player.state` current and calls onChange listeners after every change. The state **never goes backwards**: a late event that is older than what the plugin already has is dropped.
|
|
489
489
|
- Without `events`, `player.state` stays as it was first read until you call refresh().
|
|
490
490
|
- Some facts are read on demand instead of pushed, because they are large or rarely needed: chapters(), stats() (codecs, frame counts, decoder, bitrates), audioDevices().
|
|
491
|
+
- In `stats()`, the frame counts come from two places. `framesShown` and `framesDropped` are the video renderer's (mpv's) counts. `presentedFps` is what the player window really showed: new frames per second over the last second. When it stays well below `video.fps` while playing, frames are lost after rendering (the window cannot keep up, or the display refreshes slower). `video.decoding` says whether the video is decoded in `"hardware"` (the method in `video.hwdec`) or `"software"`.
|
|
491
492
|
|
|
492
493
|
Because the state is a snapshot, a plugin can keep one and use it later as the condition for a control.
|
|
493
494
|
|
|
@@ -2080,6 +2081,7 @@ The table lists the API whose documentation names a player version, newest last:
|
|
|
2080
2081
|
| 0.4.1 | PluginError, FileResolverOptions, PackageCandidate.install, PluginWarning.code, Packages.validate |
|
|
2081
2082
|
| 0.4.2 | Resolvers.fileTypes, Resolvers.onFileTypesChange |
|
|
2082
2083
|
| 0.4.3 | CommandOptions.path, PropValue, View.set, Appearance.setLanguage, TemplateArgs, Text, ConfirmOptions.args, OsdPanel.set, OsdPanelOptions.maxColumns, Osd.show |
|
|
2084
|
+
| 0.5.1 | SlotState.reason, Panel.setInteraction, PlaybackStats.presentedFps |
|
|
2083
2085
|
|
|
2084
2086
|
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).
|
|
2085
2087
|
|
|
@@ -3059,6 +3061,19 @@ change).
|
|
|
3059
3061
|
| `host` | Any other failure inside the player; `message` is the player's reason. |
|
|
3060
3062
|
| `disabled` | The plugin is being stopped; pending requests fail with it. |
|
|
3061
3063
|
| `unknown`, `rejected`, `expired` | After a transport problem the SDK could not confirm the outcome (does not happen in normal operation). |
|
|
3064
|
+
| `activation` | The plugin opened a tool window while its activation was still pending and the player could not track it. |
|
|
3065
|
+
| `command` | The player could not run or update a command it no longer knows for this plugin (removed meanwhile, or another plugin's). |
|
|
3066
|
+
| `input-overflow` | `openStream` input: the player's queue of physical key transitions was full; the input was revoked and its keys released. |
|
|
3067
|
+
| `internal` | An internal step of the player failed (keeping an operation's result, a subtitle or media job); `message` has the reason. |
|
|
3068
|
+
| `javascript`, `slint` | Packages.validate: the package's entry module does not pass `node --check` / one of its Slint files does not compile; `message` has the diagnostics. |
|
|
3069
|
+
| `owner` | A resolver answered a request that belongs to another plugin's resolver. |
|
|
3070
|
+
| `pending` | An operation with the same token is still running in the player. The SDK waits and asks again, so it rarely reaches a plugin. |
|
|
3071
|
+
| `producer` | `openStream`: the player refused or lost the generated stream; `message` has the reason. |
|
|
3072
|
+
| `resolution` | A file or web resolver's result could not be opened; `message` has the reason. |
|
|
3073
|
+
| `revisionConflict` | Packages: the installed revision changed since it was read (another install, rollback or uninstall ran). Read again and retry; the SDK passes the revision it read, so this reaches plugins that act on old data. |
|
|
3074
|
+
| `source-geometry`, `source-geometry-unsupported` | The source's picture size or rotation could not be applied: invalid decoder dimensions / a rotation that is not a multiple of 90°. |
|
|
3075
|
+
| `source-unavailable` | The source is not ready (still loading, or its time or native binding is not available yet). |
|
|
3076
|
+
| `unknown-expired` | The player no longer knows the operation or snapshot (it expired or was released). The SDK maps it to `unknownExpired` results where it can; do not resubmit the operation blindly. |
|
|
3062
3077
|
|
|
3063
3078
|
Errors thrown by handlers the SDK invokes go to Scope.onError. A
|
|
3064
3079
|
rejected promise you forgot to `await` is only logged; it never crashes
|
|
@@ -3662,8 +3677,10 @@ interface SlotState {
|
|
|
3662
3677
|
* - `fullscreen`: the sidebar's fullscreen overlay is collapsed and pops
|
|
3663
3678
|
* out when the pointer reaches the right edge; treat it as "on" for a
|
|
3664
3679
|
* toggle button;
|
|
3665
|
-
* - `idle`: the bottom bar in fullscreen
|
|
3666
|
-
*
|
|
3680
|
+
* - `idle`: the bottom bar in fullscreen while the pointer is outside the
|
|
3681
|
+
* bar's own band at the bottom of the screen (player 0.5.1: keys and
|
|
3682
|
+
* pointer motion elsewhere do not bring it back; before 0.5.1 it hid after
|
|
3683
|
+
* 3 seconds without activity).
|
|
3667
3684
|
*/
|
|
3668
3685
|
reason: "userHidden" | "space" | "fullscreen" | "idle" | null;
|
|
3669
3686
|
/** The sidebar floats in its own window; always `false` for the bottom bar. */
|
|
@@ -4931,10 +4948,15 @@ interface PlaybackStats {
|
|
|
4931
4948
|
backend: string;
|
|
4932
4949
|
/** The playback session number. */
|
|
4933
4950
|
session: number;
|
|
4934
|
-
/** Frames the
|
|
4951
|
+
/** Frames the video renderer produced. Not all of them reach the screen: a busy window shows only the newest one, so compare presentedFps. */
|
|
4935
4952
|
framesShown: number;
|
|
4936
|
-
/** Frames dropped, `null` when unknown. */
|
|
4953
|
+
/** Frames dropped by the backend (mpv), `null` when unknown. */
|
|
4937
4954
|
framesDropped: number | null;
|
|
4955
|
+
/**
|
|
4956
|
+
* New video frames the player window showed per second over the last second, measured by the player itself: draws of the main window that put a new picture on screen. Lower than `video.fps` when frames are lost after decoding and rendering (the window could not keep up with the source, or the display refreshes slower); `0` while paused. `null` when the player cannot measure it (no window, the first second, players before 0.5.1).
|
|
4957
|
+
* @player 0.5.1
|
|
4958
|
+
*/
|
|
4959
|
+
presentedFps: number | null;
|
|
4938
4960
|
/** Every field is the backend's own value, `null` when it has none. */
|
|
4939
4961
|
video: {
|
|
4940
4962
|
/** Codec name. */
|
|
@@ -4959,8 +4981,10 @@ interface PlaybackStats {
|
|
|
4959
4981
|
displayFps: number | null;
|
|
4960
4982
|
/** Bits per second, updated per keyframe. */
|
|
4961
4983
|
bitrate: number | null;
|
|
4962
|
-
/** Hardware decoder in use, e.g. "videotoolbox"; "no" = software decoding. */
|
|
4984
|
+
/** Hardware decoder in use, e.g. "videotoolbox", "d3d11va-copy"; "no" = software decoding. */
|
|
4963
4985
|
hwdec: string | null;
|
|
4986
|
+
/** How the video is decoded, from `hwdec`: `"hardware"` (the method is in `hwdec`) or `"software"`; `null` before a decoder runs. */
|
|
4987
|
+
decoding: "hardware" | "software" | null;
|
|
4964
4988
|
/** Transfer characteristic as mpv names it, e.g. "bt.1886", "pq", "hlg". */
|
|
4965
4989
|
transfer: string | null;
|
|
4966
4990
|
} | null;
|
|
@@ -6456,7 +6480,9 @@ type SubtitleStyle = {
|
|
|
6456
6480
|
outline: number;
|
|
6457
6481
|
/** Bottom margin 2–15 % of the video height. */
|
|
6458
6482
|
marginPercent: number;
|
|
6459
|
-
/**
|
|
6483
|
+
/**
|
|
6484
|
+
* Timing offset in milliseconds, −600000…600000 (±10 minutes); positive shows the subtitles later. Outside the range the player refuses the style with `invalid`.
|
|
6485
|
+
*/
|
|
6460
6486
|
offsetMs: number;
|
|
6461
6487
|
/** Bold text; default false. */
|
|
6462
6488
|
bold?: boolean;
|
|
@@ -8011,10 +8037,15 @@ interface PlaybackStats {
|
|
|
8011
8037
|
backend: string;
|
|
8012
8038
|
/** The playback session number. */
|
|
8013
8039
|
session: number;
|
|
8014
|
-
/** Frames the
|
|
8040
|
+
/** Frames the video renderer produced. Not all of them reach the screen: a busy window shows only the newest one, so compare presentedFps. */
|
|
8015
8041
|
framesShown: number;
|
|
8016
|
-
/** Frames dropped, `null` when unknown. */
|
|
8042
|
+
/** Frames dropped by the backend (mpv), `null` when unknown. */
|
|
8017
8043
|
framesDropped: number | null;
|
|
8044
|
+
/**
|
|
8045
|
+
* New video frames the player window showed per second over the last second, measured by the player itself: draws of the main window that put a new picture on screen. Lower than `video.fps` when frames are lost after decoding and rendering (the window could not keep up with the source, or the display refreshes slower); `0` while paused. `null` when the player cannot measure it (no window, the first second, players before 0.5.1).
|
|
8046
|
+
* @player 0.5.1
|
|
8047
|
+
*/
|
|
8048
|
+
presentedFps: number | null;
|
|
8018
8049
|
/** Every field is the backend's own value, `null` when it has none. */
|
|
8019
8050
|
video: {
|
|
8020
8051
|
/** Codec name. */
|
|
@@ -8039,8 +8070,10 @@ interface PlaybackStats {
|
|
|
8039
8070
|
displayFps: number | null;
|
|
8040
8071
|
/** Bits per second, updated per keyframe. */
|
|
8041
8072
|
bitrate: number | null;
|
|
8042
|
-
/** Hardware decoder in use, e.g. "videotoolbox"; "no" = software decoding. */
|
|
8073
|
+
/** Hardware decoder in use, e.g. "videotoolbox", "d3d11va-copy"; "no" = software decoding. */
|
|
8043
8074
|
hwdec: string | null;
|
|
8075
|
+
/** How the video is decoded, from `hwdec`: `"hardware"` (the method is in `hwdec`) or `"software"`; `null` before a decoder runs. */
|
|
8076
|
+
decoding: "hardware" | "software" | null;
|
|
8044
8077
|
/** Transfer characteristic as mpv names it, e.g. "bt.1886", "pq", "hlg". */
|
|
8045
8078
|
transfer: string | null;
|
|
8046
8079
|
} | null;
|
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.15: 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:
|
|
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: L2026–2089.
|
|
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: L2090–2132.
|
|
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:
|
|
81
|
+
**Test**: `tests/*.test.ts` with `node:test`, run by `vestra-plugin test`. `startPlugin(activate, { directory: new URL("..", import.meta.url) })` from `@vestra-player/sdk/testing` returns `{ host, stop }`; `host` is a TestHost (an in-memory player): `host.setSource(…)`, `host.command(id).run()`, `host.press(key)`, `await host.settle()`, then assert on `host.osd`, `host.window(id).props`… Guide: L1588–1753; TestHost: L6675.
|
|
82
82
|
|
|
83
83
|
**Command line**
|
|
84
84
|
|
|
@@ -106,40 +106,40 @@ 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 L3029.
|
|
110
110
|
|
|
111
111
|
## Reference
|
|
112
112
|
|
|
113
113
|
- [llms-full.txt](https://vestrasys.github.io/vestra-player-sdk/llms-full.txt), also node_modules/@vestra-player/sdk/llms-full.txt; the pages are on the [site](https://vestrasys.github.io/vestra-player-sdk/).
|
|
114
114
|
- Tutorials: Getting started L9–214
|
|
115
|
-
- Concepts: How a plugin runs L215–364; Commands, menus and key bindings L365–462; Playback state, controls and sources L463–
|
|
116
|
-
- How-to: Keep a slider responsive while dragging
|
|
117
|
-
- Guidelines: Interface guidelines
|
|
118
|
-
- Reference: Manifest
|
|
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):
|
|
115
|
+
- Concepts: How a plugin runs L215–364; Commands, menus and key bindings L365–462; Playback state, controls and sources L463–585; Video and audio processing L586–663; Windows, panels, settings pages, dialogs and the OSD L664–950
|
|
116
|
+
- How-to: Keep a slider responsive while dragging L951–1125; Remember a window's state between runs L1126–1255; Translate a plugin L1256–1439; Migrate a plugin to English source text L1440–1587; Test a plugin L1588–1753; Publish a plugin L1754–1842
|
|
117
|
+
- Guidelines: Interface guidelines L1843–1927; Menu guidelines L1928–2025
|
|
118
|
+
- Reference: Manifest L2026–2089; Capabilities L2090–2132; Limits L2133–2227; Commands, menus and bindings L2228–2696; Platforms L2697–2725; Theme L2726–2930; Command line L2931–2986
|
|
119
|
+
- [API: @vestra-player/sdk](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk.html): L2987–6510
|
|
120
|
+
- [API: @vestra-player/sdk/testing](https://vestrasys.github.io/vestra-player-sdk/modules/_vestra-player_sdk_testing.html): L6511–7835
|
|
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 L3221, Scope L3090, PluginError L3029, Disposable L3002
|
|
127
|
+
- Commands L3433; Windows L3638; Panels L4281; Dialogs L4567; Player L5015; video: VideoFilter L5280, VideoView L5343, RenderOptions L5385; audio: AudioFilter L5304; Subtitles L5483; media: MediaCapture L5643; Resolvers L5748; Packages L5988; Osd L5216; Host L5164; Clipboard L6105; Power L6125; Tools L6158; Storage L6201; System L6224; Secrets L6242; window: MainWindow L4404; App L4485; Bindings L6075; Ui L3525; Timeline L4361; Drops L3937; Appearance L3966; I18n L4108; Settings L4214.
|
|
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. L8259–8348
|
|
134
|
+
- blur: A tool window with one slider that blurs the playing video. L8349–8610
|
|
135
|
+
- signal-generator: Generates its own video and audio: colour bars and a 1 kHz tone. L8611–8943
|
|
136
|
+
- bookmark: A tool window bound to the playback state: remember the position and jump back to it. L8944–9128
|
|
137
|
+
- panel-menu: A sidebar panel with its own right-click menu. L9129–9334
|
|
138
|
+
- menus: Radio menu items, separator groups and a menu item whose title changes. L9335–9494
|
|
139
|
+
- theme-widgets: A tool window drawn with the player's theme and widgets. L9495–9658
|
|
140
|
+
- markdown: A window that shows a Markdown document. L9659–9853
|
|
141
|
+
- i18n: A plugin in the player's language: English source text, a Chinese translation. L9854–10021
|
|
142
142
|
|
|
143
143
|
## Optional
|
|
144
144
|
|
|
145
|
-
- [Changelog](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md); full doc comments in dist/plugin
|
|
145
|
+
- [Changelog](https://github.com/vestrasys/vestra-player-sdk/blob/main/CHANGELOG.md); full doc comments in node_modules/@vestra-player/sdk/dist/plugin/types.d.ts (the API) and dist/plugin/testing.d.ts (TestHost); Slint library in slint/vestra/.
|