@vestra-player/sdk 1.6.1 → 1.6.3
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/docs-tree.json.gz +0 -0
- package/dist/i18n.js +0 -1
- package/dist/plugin/testing.d.ts +17 -11
- package/dist/plugin/testing.js +25 -20
- package/dist/plugin/types.d.ts +46 -26
- package/llms.txt +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.6.3
|
|
4
|
+
|
|
5
|
+
**Who must change: nobody.** Documentation only: no change to the TypeScript API, the wire or `TestHost`, `apiVersion` stays `vestra/1`, no new capability, no player version needed.
|
|
6
|
+
|
|
7
|
+
- **Examples name window handles after the window they name (its Slint file where there is one).** The API examples, guides, tutorials and example plugins no longer call a window handle `window`: `readmeWindow` for `ui/readme.slint`, `presetsWindow`, `thumbnailWindow`, `bookmarkWindow`, `blurWindow` and so on, in `plugin.windows.create(…)` and `host.window(…)` alike.
|
|
8
|
+
|
|
9
|
+
## 1.6.2
|
|
10
|
+
|
|
11
|
+
**Who must change: nobody, but check `TestHost` tests of a full sidebar or of `keepsRunning` with a background tab.** No change to the TypeScript API or the wire, `apiVersion` stays `vestra/1`, no new capability, no player version needed. `TestHost` follows player 0.7.3: it no longer refuses a ninth sidebar tab, and `keepsRunning` lists a sidebar panel only while its tab is the current tab, as `"its sidebar tab is the current tab"`. A test that expected `conflict` for a ninth tab, or `"a mounted panel"` for a sidebar panel, now fails.
|
|
12
|
+
|
|
13
|
+
- **Sidebar tabs without a limit** (player 0.7.3; the player's [sidebar tabs design](https://github.com/vestrasys/vestra-player/blob/main/doc/architecture/sidebar-tabs.md)). The sidebar takes any number of tabs: the strip shows the tabs that fit and a `»` menu at its end lists all of them, the current one checked. Players 0.4.x to 0.7.2 refused a ninth tab with `conflict` (「侧栏最多 8 个页签」); player 0.7.3 never refuses a sidebar mount for that. `Panel.ready`, [Windows, panels, settings pages, dialogs and the OSD](docs/explanation/ui.md#shared-space) and `TestHost` say so. The SDK's copy of the player's Chinese texts (`HOST_ZH_HANS`) drops "The sidebar holds at most {} tabs", which the player no longer has.
|
|
14
|
+
- **A background tab does not keep its plugin running** (player 0.7.3). The current tab keeps its plugin running as busy work; a sidebar panel never makes a plugin resident. A plugin whose sidebar panel is in a background tab, and that holds nothing else that keeps it running, goes to standby after the idle time like any idle plugin (stop reason `idle`); the player keeps its tab, with its title, in the strip and the `»` menu. Showing the tab starts the plugin again: `activate` runs and mounts the same panel (same file and component), which takes the tab over, and `Panel.ready` resolves again. The new process mounts with the properties its `activate` passes, so keep what the panel shows in session storage, the only state that survives standby, and restore it in `activate`. `Panel.state`, [Windows, panels…](docs/explanation/ui.md#panel), [How a plugin runs › Idle plugins are stopped](docs/explanation/plugins.md#idle-plugins-are-stopped) and [How the player runs and talks to plugins](docs/explanation/host-and-node.md) (the recorded `ui.mount`, the `panel_shown` wake) describe it. `TestHost.keepsRunning` lists `"its sidebar tab is the current tab"` while it is, and nothing for a background tab; `"a mounted panel"` is now for the bottom bar and the backdrop only.
|
|
15
|
+
|
|
3
16
|
## 1.6.1
|
|
4
17
|
|
|
5
18
|
**Who must change: nobody.** Docs only: no change to the TypeScript API, the wire or `TestHost`, `apiVersion` stays `vestra/1`, no new capability.
|
package/dist/docs-tree.json.gz
CHANGED
|
Binary file
|
package/dist/i18n.js
CHANGED
|
@@ -943,7 +943,6 @@ export const HOST_ZH_HANS = {
|
|
|
943
943
|
sidebar: "侧栏",
|
|
944
944
|
"video backdrop": "视频背景",
|
|
945
945
|
"The {} is used by {}": "{}已被 {} 使用",
|
|
946
|
-
"The sidebar holds at most {} tabs": "侧栏最多 {} 个页签",
|
|
947
946
|
"{} is resolved by {}": "{} 已由 {} 解析",
|
|
948
947
|
"File type .{}": "文件类型 .{}",
|
|
949
948
|
"Not available in fullscreen": "全屏时不可用",
|
package/dist/plugin/testing.d.ts
CHANGED
|
@@ -115,7 +115,7 @@ type Call = {
|
|
|
115
115
|
* import assert from "node:assert/strict";
|
|
116
116
|
* declare const host: TestHost;
|
|
117
117
|
* // ---cut---
|
|
118
|
-
* await host.command("open-picture").run(); // the plugin calls
|
|
118
|
+
* await host.command("open-picture").run(); // the plugin calls pictureWindow.show()
|
|
119
119
|
* const picture = host.window("picture");
|
|
120
120
|
* assert.equal(picture.visible, true);
|
|
121
121
|
* picture.emit("adjust", "brightness", 40); // fire a Slint callback
|
|
@@ -2746,11 +2746,11 @@ export declare class TestHost implements Transport {
|
|
|
2746
2746
|
* declare const host: TestHost;
|
|
2747
2747
|
* declare const expected: string;
|
|
2748
2748
|
* // ---cut---
|
|
2749
|
-
* const
|
|
2750
|
-
*
|
|
2751
|
-
* for (let i = 0; i < 100 &&
|
|
2749
|
+
* const importWindow = host.window("import");
|
|
2750
|
+
* importWindow.emit("load-file"); // the plugin reads and parses the file itself
|
|
2751
|
+
* for (let i = 0; i < 100 && importWindow.props["status-text"] !== expected; i++)
|
|
2752
2752
|
* await host.settle(20);
|
|
2753
|
-
* assert.equal(
|
|
2753
|
+
* assert.equal(importWindow.props["status-text"], expected);
|
|
2754
2754
|
* ```
|
|
2755
2755
|
*
|
|
2756
2756
|
* @capability None.
|
|
@@ -2782,12 +2782,18 @@ export declare class TestHost implements Transport {
|
|
|
2782
2782
|
close(): void;
|
|
2783
2783
|
/**
|
|
2784
2784
|
* Why the player would keep this plugin running while nothing uses it
|
|
2785
|
-
* (lazy activation, player 0.5.21), one line per reason
|
|
2786
|
-
*
|
|
2787
|
-
*
|
|
2788
|
-
* its open windows
|
|
2789
|
-
*
|
|
2790
|
-
*
|
|
2785
|
+
* (lazy activation, player 0.5.21), one line per reason: an event it
|
|
2786
|
+
* listens to that is not one the player wakes it for (with what listens
|
|
2787
|
+
* and where it was added), its panel in the bottom bar or the backdrop,
|
|
2788
|
+
* its open windows (these as the player's log says them), and, from
|
|
2789
|
+
* player 0.7.3, its sidebar tab while that is the current tab. The
|
|
2790
|
+
* player counts the current tab as busy work, not as something live: it
|
|
2791
|
+
* keeps the plugin running only while the tab is shown, and a sidebar
|
|
2792
|
+
* panel in a background tab is no reason at all (the plugin may go to
|
|
2793
|
+
* standby; showing the tab starts it again). Empty: the player may stop
|
|
2794
|
+
* it while idle and start it again on its next use. Filter chains,
|
|
2795
|
+
* streams, jobs and the like (which also keep a plugin running) are not
|
|
2796
|
+
* listed.
|
|
2791
2797
|
*
|
|
2792
2798
|
* @capability None.
|
|
2793
2799
|
* @since 1.5.40
|
package/dist/plugin/testing.js
CHANGED
|
@@ -314,8 +314,6 @@ const TEST_ZH_HANS = {
|
|
|
314
314
|
"External SRT": "外部 SRT",
|
|
315
315
|
"External ASS": "外部 ASS",
|
|
316
316
|
};
|
|
317
|
-
/** The player's limit of sidebar tabs. */
|
|
318
|
-
const MAX_SIDEBAR_TABS = 8;
|
|
319
317
|
/**
|
|
320
318
|
* The player's refusal of a declaration (commands.rs `CommandError`): code
|
|
321
319
|
* `invalid`, `conflict` or `limit`, its message prefixed as the player's.
|
|
@@ -3481,11 +3479,11 @@ export class TestHost {
|
|
|
3481
3479
|
* declare const host: TestHost;
|
|
3482
3480
|
* declare const expected: string;
|
|
3483
3481
|
* // ---cut---
|
|
3484
|
-
* const
|
|
3485
|
-
*
|
|
3486
|
-
* for (let i = 0; i < 100 &&
|
|
3482
|
+
* const importWindow = host.window("import");
|
|
3483
|
+
* importWindow.emit("load-file"); // the plugin reads and parses the file itself
|
|
3484
|
+
* for (let i = 0; i < 100 && importWindow.props["status-text"] !== expected; i++)
|
|
3487
3485
|
* await host.settle(20);
|
|
3488
|
-
* assert.equal(
|
|
3486
|
+
* assert.equal(importWindow.props["status-text"], expected);
|
|
3489
3487
|
* ```
|
|
3490
3488
|
*
|
|
3491
3489
|
* @capability None.
|
|
@@ -3983,12 +3981,18 @@ export class TestHost {
|
|
|
3983
3981
|
}
|
|
3984
3982
|
/**
|
|
3985
3983
|
* Why the player would keep this plugin running while nothing uses it
|
|
3986
|
-
* (lazy activation, player 0.5.21), one line per reason
|
|
3987
|
-
*
|
|
3988
|
-
*
|
|
3989
|
-
* its open windows
|
|
3990
|
-
*
|
|
3991
|
-
*
|
|
3984
|
+
* (lazy activation, player 0.5.21), one line per reason: an event it
|
|
3985
|
+
* listens to that is not one the player wakes it for (with what listens
|
|
3986
|
+
* and where it was added), its panel in the bottom bar or the backdrop,
|
|
3987
|
+
* its open windows (these as the player's log says them), and, from
|
|
3988
|
+
* player 0.7.3, its sidebar tab while that is the current tab. The
|
|
3989
|
+
* player counts the current tab as busy work, not as something live: it
|
|
3990
|
+
* keeps the plugin running only while the tab is shown, and a sidebar
|
|
3991
|
+
* panel in a background tab is no reason at all (the plugin may go to
|
|
3992
|
+
* standby; showing the tab starts it again). Empty: the player may stop
|
|
3993
|
+
* it while idle and start it again on its next use. Filter chains,
|
|
3994
|
+
* streams, jobs and the like (which also keep a plugin running) are not
|
|
3995
|
+
* listed.
|
|
3992
3996
|
*
|
|
3993
3997
|
* @capability None.
|
|
3994
3998
|
* @since 1.5.40
|
|
@@ -4012,7 +4016,13 @@ export class TestHost {
|
|
|
4012
4016
|
if (!WAKE_EVENTS.includes(event))
|
|
4013
4017
|
for (const why of this.listeningWhy.get(event) ?? ["a listener"])
|
|
4014
4018
|
reasons.push(`listens to ${event}: ${why}`);
|
|
4015
|
-
|
|
4019
|
+
// A sidebar panel is never live (player 0.7.3): the current tab keeps
|
|
4020
|
+
// the plugin running as busy work, a background tab not at all.
|
|
4021
|
+
if (this.panel?.slot === "sidebar") {
|
|
4022
|
+
if (this.layout.sidebar?.owner === 1)
|
|
4023
|
+
reasons.push("its sidebar tab is the current tab");
|
|
4024
|
+
}
|
|
4025
|
+
else if (this.panel)
|
|
4016
4026
|
reasons.push("a mounted panel");
|
|
4017
4027
|
for (const [id, window] of this.windows)
|
|
4018
4028
|
if (window.visible)
|
|
@@ -4234,8 +4244,8 @@ export class TestHost {
|
|
|
4234
4244
|
"ui.mount": (p) => {
|
|
4235
4245
|
if (this.panel)
|
|
4236
4246
|
throw new HostError("conflict", "owner already mounted");
|
|
4237
|
-
// Like the player: one panel in the bottom bar and the backdrop,
|
|
4238
|
-
// in the sidebar (
|
|
4247
|
+
// Like the player: one panel in the bottom bar and the backdrop, any
|
|
4248
|
+
// number of tabs in the sidebar (player 0.7.3; 0.4.x to 0.7.2 took 8).
|
|
4239
4249
|
const holder = p.slot === "backdrop"
|
|
4240
4250
|
? this.backdrop?.owner
|
|
4241
4251
|
: p.slot === "bottom"
|
|
@@ -4246,11 +4256,6 @@ export class TestHost {
|
|
|
4246
4256
|
this.#hostText(SLOT_LABELS[String(p.slot)]),
|
|
4247
4257
|
String(holder),
|
|
4248
4258
|
]));
|
|
4249
|
-
if (p.slot === "sidebar" &&
|
|
4250
|
-
(this.layout.sidebar?.panels?.length ?? 0) >= MAX_SIDEBAR_TABS)
|
|
4251
|
-
throw taken(this.#hostText("The sidebar holds at most {} tabs", [
|
|
4252
|
-
MAX_SIDEBAR_TABS,
|
|
4253
|
-
]));
|
|
4254
4259
|
const properties = this.#initialValues(this.#shownValues(p.properties));
|
|
4255
4260
|
this.#seeImages(properties);
|
|
4256
4261
|
this.#resetWrites("$mount");
|
package/dist/plugin/types.d.ts
CHANGED
|
@@ -367,10 +367,10 @@ export interface Scope extends Disposable {
|
|
|
367
367
|
* return;
|
|
368
368
|
* }
|
|
369
369
|
* live = plugin.scope();
|
|
370
|
-
* const
|
|
370
|
+
* const statsWindow = live.windows.create("ui/stats.slint");
|
|
371
371
|
* const timer = setInterval(() => live?.update(), 1000);
|
|
372
372
|
* live.onDispose(() => clearInterval(timer));
|
|
373
|
-
* await
|
|
373
|
+
* await statsWindow.show();
|
|
374
374
|
* },
|
|
375
375
|
* });
|
|
376
376
|
* ```
|
|
@@ -487,12 +487,12 @@ export interface Scope extends Disposable {
|
|
|
487
487
|
* promise settles; state changed between the awaits of a long handler
|
|
488
488
|
* shows only after an explicit `update()`.
|
|
489
489
|
* ```ts
|
|
490
|
-
* declare const
|
|
490
|
+
* declare const downloadWindow: Window;
|
|
491
491
|
* declare function downloadPart(part: number): Promise<void>;
|
|
492
492
|
* // ---cut---
|
|
493
493
|
* let done = 0;
|
|
494
|
-
*
|
|
495
|
-
*
|
|
494
|
+
* downloadWindow.bind(() => ({ progress: done }));
|
|
495
|
+
* downloadWindow.on("start", async () => {
|
|
496
496
|
* for (let part = 0; part < 10; part++) {
|
|
497
497
|
* await downloadPart(part);
|
|
498
498
|
* done = part + 1;
|
|
@@ -1682,11 +1682,11 @@ export interface Ui {
|
|
|
1682
1682
|
* calls `image()` again after rewriting it, because the SDK does not send
|
|
1683
1683
|
* a value that did not change.
|
|
1684
1684
|
* ```ts
|
|
1685
|
-
* const
|
|
1685
|
+
* const thumbnailWindow = plugin.windows.create("ui/thumbnail.slint");
|
|
1686
1686
|
* const file = `${plugin.dataDirectory}/thumbnail.png`;
|
|
1687
1687
|
* // … write the PNG to `file` (for example with plugin.tools.run("ffmpeg", …)) …
|
|
1688
|
-
*
|
|
1689
|
-
* await
|
|
1688
|
+
* thumbnailWindow.set({ thumbnail: plugin.ui.image(file) });
|
|
1689
|
+
* await thumbnailWindow.show();
|
|
1690
1690
|
* ```
|
|
1691
1691
|
*
|
|
1692
1692
|
* @since 1.0.0
|
|
@@ -1850,11 +1850,11 @@ export interface Ui {
|
|
|
1850
1850
|
* const response = await fetch(readmeUrl);
|
|
1851
1851
|
* if (!response.ok) throw new Error(`README: HTTP ${response.status}`);
|
|
1852
1852
|
* const text = await response.text();
|
|
1853
|
-
* const
|
|
1853
|
+
* const readmeWindow = plugin.windows.create("ui/readme.slint");
|
|
1854
1854
|
* // Bound before the first `show`, as a tool window requires.
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
1857
|
-
* await
|
|
1855
|
+
* readmeWindow.on("openLink", (url: string) => plugin.system.openUrl(url));
|
|
1856
|
+
* readmeWindow.set({ doc: await plugin.ui.markdown(text, { base: readmeUrl }) });
|
|
1857
|
+
* await readmeWindow.show();
|
|
1858
1858
|
* ```
|
|
1859
1859
|
*
|
|
1860
1860
|
* @since 1.1.0
|
|
@@ -1999,10 +1999,10 @@ export interface View {
|
|
|
1999
1999
|
* sends the value even though it equals the one sent before, which is
|
|
2000
2000
|
* what pulls a control the user moved back to the plugin's value.
|
|
2001
2001
|
* ```ts
|
|
2002
|
-
* const
|
|
2002
|
+
* const presetsWindow = plugin.windows.create("ui/presets.slint");
|
|
2003
2003
|
* let presetIndex = 0;
|
|
2004
|
-
*
|
|
2005
|
-
* if (index > 2)
|
|
2004
|
+
* presetsWindow.on("presetChosen", (index: number) => {
|
|
2005
|
+
* if (index > 2) presetsWindow.set({ presetIndex }); // "Custom" is not a preset
|
|
2006
2006
|
* else presetIndex = index;
|
|
2007
2007
|
* });
|
|
2008
2008
|
* ```
|
|
@@ -2165,9 +2165,9 @@ export interface Window extends View, Disposable {
|
|
|
2165
2165
|
* window; it rejects with a code, such as `host` for a Slint file that
|
|
2166
2166
|
* does not compile or `unavailable` without a user interface.
|
|
2167
2167
|
* ```ts
|
|
2168
|
-
* const
|
|
2168
|
+
* const inspectorWindow = plugin.windows.create("ui/inspector.slint");
|
|
2169
2169
|
* try {
|
|
2170
|
-
* await
|
|
2170
|
+
* await inspectorWindow.show();
|
|
2171
2171
|
* } catch (error) {
|
|
2172
2172
|
* // The code is data; `message` has the details for the log.
|
|
2173
2173
|
* await plugin.osd.show("Cannot open the inspector ({})", [(error as PluginError).code]);
|
|
@@ -2276,8 +2276,8 @@ export interface Window extends View, Disposable {
|
|
|
2276
2276
|
* store writes the change to `window.json` shortly after.
|
|
2277
2277
|
* ```ts
|
|
2278
2278
|
* const store = plugin.storage.json("window", { defaults: { open: false } });
|
|
2279
|
-
* const
|
|
2280
|
-
*
|
|
2279
|
+
* const notesWindow = plugin.windows.create("ui/notes.slint");
|
|
2280
|
+
* notesWindow.onClose(() => store.save({ open: false }));
|
|
2281
2281
|
* ```
|
|
2282
2282
|
*
|
|
2283
2283
|
* @see [Remember a window's state between runs](../../docs/how-to/window-state.md)
|
|
@@ -2732,15 +2732,22 @@ export interface Panel extends View, Disposable {
|
|
|
2732
2732
|
* A second sidebar panel is not refused: it resolves as another tab
|
|
2733
2733
|
* (see {@link Panel.state}). Built-in plugins mount first at start-up,
|
|
2734
2734
|
* so the playlist's tab is first and a built-in panel keeps its position.
|
|
2735
|
+
* Behaviour from player 0.7.3: the sidebar takes any number of tabs; the
|
|
2736
|
+
* strip shows the tabs that fit and a `»` menu lists all of them.
|
|
2737
|
+
* Players 0.4.x to 0.7.2 refused a ninth tab with `conflict`. A plugin
|
|
2738
|
+
* whose sidebar tab is in the background, and that holds nothing else
|
|
2739
|
+
* that keeps it running, goes to standby when idle; showing the tab
|
|
2740
|
+
* starts it again (see {@link Panel.state}).
|
|
2735
2741
|
*
|
|
2736
2742
|
* @throws `ui-prepare` (rejects) The Slint file does not compile, or a
|
|
2737
2743
|
* bound property is not declared on the bridge global; `message` has the
|
|
2738
2744
|
* diagnostics. (Players 0.4.0 and older also answer a taken bottom bar
|
|
2739
2745
|
* or sidebar with it.)
|
|
2740
2746
|
* @throws `conflict` (rejects) Another plugin's panel holds the bottom bar
|
|
2741
|
-
* or the backdrop (shown, or being mounted)
|
|
2742
|
-
*
|
|
2743
|
-
*
|
|
2747
|
+
* or the backdrop (shown, or being mounted); `message` names the
|
|
2748
|
+
* position and the holder (「底栏已被 vestra.playback 使用」). Not an
|
|
2749
|
+
* activation failure. Never for the sidebar (behaviour from player
|
|
2750
|
+
* 0.7.3); players 0.4.x to 0.7.2 also refused a ninth sidebar tab.
|
|
2744
2751
|
* @throws `busy` (rejects) The player is still preparing this plugin's
|
|
2745
2752
|
* previous mount, or its queue of mounts is full.
|
|
2746
2753
|
* @throws `invalid` (rejects) `title` is longer than 128 bytes or has
|
|
@@ -2761,6 +2768,19 @@ export interface Panel extends View, Disposable {
|
|
|
2761
2768
|
* only this plugin's own changes. A sidebar panel in a background tab
|
|
2762
2769
|
* has `active: false`, `effective: false` and `reason: "otherTab"`.
|
|
2763
2770
|
*
|
|
2771
|
+
* Behaviour from player 0.7.3: a background tab does not keep the plugin
|
|
2772
|
+
* running.
|
|
2773
|
+
* If the panel is all that keeps it running, the plugin goes to standby
|
|
2774
|
+
* after the idle time (stop reason `idle`): the player keeps its tab, with
|
|
2775
|
+
* its title, in the strip and the `»` menu. When the user shows the tab,
|
|
2776
|
+
* the player starts the plugin again; `activate` runs and mounts the same
|
|
2777
|
+
* panel (same file and component), which takes the tab over, and
|
|
2778
|
+
* {@link Panel.ready} resolves again. Anything the plugin kept only in
|
|
2779
|
+
* memory is gone: restore the view from storage (session storage
|
|
2780
|
+
* survives standby). While it is in the background, the player may also
|
|
2781
|
+
* drop the panel's component and build it again from the bridge
|
|
2782
|
+
* properties last written, as it does on any rebuild.
|
|
2783
|
+
*
|
|
2764
2784
|
* @throws Never; `null` stands for "not mounted".
|
|
2765
2785
|
*
|
|
2766
2786
|
* @since 1.5.2
|
|
@@ -5370,9 +5390,9 @@ export interface Stream extends Disposable {
|
|
|
5370
5390
|
* connection; it resolves once both are closed.
|
|
5371
5391
|
* ```ts
|
|
5372
5392
|
* declare const stream: Stream;
|
|
5373
|
-
* declare const
|
|
5393
|
+
* declare const generatorWindow: Window;
|
|
5374
5394
|
* // ---cut---
|
|
5375
|
-
*
|
|
5395
|
+
* generatorWindow.onClose(() => stream.stop());
|
|
5376
5396
|
* ```
|
|
5377
5397
|
*
|
|
5378
5398
|
* @since 1.0.0
|
|
@@ -9640,10 +9660,10 @@ export interface JsonStore<T> extends Disposable {
|
|
|
9640
9660
|
* writes the file only once the user stops for 300 ms. Each `save`
|
|
9641
9661
|
* replaces the value and restarts the debounce timer.
|
|
9642
9662
|
* ```ts
|
|
9643
|
-
* declare const
|
|
9663
|
+
* declare const volumeWindow: Window;
|
|
9644
9664
|
* // ---cut---
|
|
9645
9665
|
* const store = plugin.storage.json("prefs", { defaults: { volume: 100 } });
|
|
9646
|
-
*
|
|
9666
|
+
* volumeWindow.on("volumeChanged", (volume: number) => store.save({ ...store.value, volume }));
|
|
9647
9667
|
* ```
|
|
9648
9668
|
*
|
|
9649
9669
|
* @since 1.0.0
|
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vestra Player SDK
|
|
2
2
|
|
|
3
|
-
> @vestra-player/sdk 1.6.
|
|
3
|
+
> @vestra-player/sdk 1.6.3: 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. The documentation is a tree of short pages read by path, like `go doc`: the same pages and API as https://vestrasys.github.io/vestra-player-sdk/.
|
|
4
4
|
|
|
5
5
|
## Read the documentation
|
|
6
6
|
|