@vestra-player/sdk 1.5.9 → 1.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/commands.d.ts +7 -4
- package/dist/i18n-tools.js +59 -3
- package/dist/i18n.d.ts +92 -0
- package/dist/i18n.js +299 -0
- package/dist/player-runtime.d.ts +2 -1
- package/dist/player-runtime.js +2 -1
- package/dist/plugin/bindings.js +1 -0
- package/dist/plugin/commands.js +24 -4
- package/dist/plugin/index.js +9 -1
- package/dist/plugin/language.d.ts +6 -2
- package/dist/plugin/language.js +74 -0
- package/dist/plugin/osd.d.ts +10 -2
- package/dist/plugin/osd.js +35 -16
- package/dist/plugin/subtitles.js +9 -1
- package/dist/plugin/testing.d.ts +54 -5
- package/dist/plugin/testing.js +199 -49
- package/dist/plugin/timeline.js +3 -1
- package/dist/plugin/types.d.ts +338 -43
- package/dist/plugin/ui.js +26 -10
- package/dist/plugin/values.d.ts +55 -0
- package/dist/plugin/values.js +117 -0
- package/dist/source-resolvers.d.ts +0 -1
- package/dist/source-resolvers.js +9 -1
- package/dist/subtitles.d.ts +3 -1
- package/dist/wire.d.ts +17 -9
- package/dist/wire.js +2 -1
- package/llms-full.txt +295 -47
- package/llms.txt +41 -41
- package/package.json +1 -1
package/dist/plugin/types.d.ts
CHANGED
|
@@ -73,11 +73,11 @@ export interface Disposable {
|
|
|
73
73
|
* | `timeout` | A time limit ran out (`openStream` start-up, `tools.run`, `system.*` after 10 s). |
|
|
74
74
|
* | `stream`, `device` | `openStream`: the producer failed / the audio device is not ready. |
|
|
75
75
|
* | `backend-uncertain` | The player's backend blocked a filter stage; call `retry()`. |
|
|
76
|
-
* | `limit` | A player-wide limit was reached (for example the number of commands). |
|
|
76
|
+
* | `limit` | A player-wide limit was reached (for example the number of commands), a property value is over the limits of {@link PropValue}, or a request is longer than the player's 1 MiB message. |
|
|
77
77
|
* | `reserved` | {@link Packages.validate}, {@link PackageCandidate.install}: the id is `vestra` or starts with `vestra.` (any case), which only the player's built-in plugins use (player 0.4.1). |
|
|
78
78
|
* | `versionMismatch` | The package needs a newer player (`minPlayerVersion`) or another `apiVersion`. |
|
|
79
79
|
* | `ui-prepare` | The player could not prepare a mounted panel or a settings page (its Slint file does not compile, a bound property is not declared, or another plugin's panel holds the slot); `message` has the diagnostics. |
|
|
80
|
-
* | `ui` | The player could not apply a property to a tool window or a settings page, or could not build the Options window (a property the Slint file does not declare, a value of the wrong type); `message` has Slint's reason. |
|
|
80
|
+
* | `ui` | The player could not apply a property to a tool window or a settings page, or could not build the Options window (a property the Slint file does not declare, a value of the wrong type); `message` has Slint's reason. Also reported to {@link Scope.onError} without a request: a callback whose arguments the player could not convert, a property it could not show again when it rebuilt a view (an image file removed since). |
|
|
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). |
|
|
@@ -341,8 +341,11 @@ export interface CommandState {
|
|
|
341
341
|
checked: boolean | null;
|
|
342
342
|
/** Shown as busy; like `enabled: false`, the player does not call `run`. Default false. */
|
|
343
343
|
busy: boolean;
|
|
344
|
-
/**
|
|
345
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Shown when the command is disabled or busy: English source text the
|
|
346
|
+
* player translates, or a {@link Text} (SDK 1.5.11).
|
|
347
|
+
*/
|
|
348
|
+
reason: TextValue | null;
|
|
346
349
|
}
|
|
347
350
|
/**
|
|
348
351
|
* A value, or a function the SDK re-evaluates on every update pass (see
|
|
@@ -419,17 +422,28 @@ export interface CommandOptions {
|
|
|
419
422
|
* menu of its own, so plugins for those players write `@video`; player
|
|
420
423
|
* 0.4.3 still accepts the old Chinese titles of its own menus.
|
|
421
424
|
*
|
|
425
|
+
* A segment that mixes words with data (a track number, a count) is a
|
|
426
|
+
* {@link Text} (SDK 1.5.11, player 0.4.3): `plugin.i18n.text("Track {}
|
|
427
|
+
* ({})", [n, codec])`. The menu shows it translated and filled in; it
|
|
428
|
+
* merges by its English rendering ("Track 2 (opus)").
|
|
429
|
+
*
|
|
422
430
|
* @example
|
|
423
431
|
* ```ts
|
|
424
432
|
* plugin.commands.add({ id: "blur", path: ["@video", "Blur"], run: toggle });
|
|
433
|
+
* const { text } = plugin.i18n;
|
|
434
|
+
* plugin.commands.add({
|
|
435
|
+
* id: "track-2",
|
|
436
|
+
* path: ["@audio", "Audio Track", text("Track {} ({})", [2, "opus"])],
|
|
437
|
+
* run: select,
|
|
438
|
+
* });
|
|
425
439
|
* ```
|
|
426
440
|
*/
|
|
427
|
-
path?: string[];
|
|
441
|
+
path?: (string | Text)[];
|
|
428
442
|
/**
|
|
429
|
-
* Menu label (English source text, shown translated
|
|
430
|
-
* last path segment.
|
|
443
|
+
* Menu label (English source text, shown translated, or a {@link Text});
|
|
444
|
+
* defaults to the last path segment.
|
|
431
445
|
*/
|
|
432
|
-
title?: string;
|
|
446
|
+
title?: string | Text;
|
|
433
447
|
/**
|
|
434
448
|
* Sibling order in the menu, ascending (integer, default 0). A submenu sits
|
|
435
449
|
* where its first command sits, except a built-in menu, which keeps its
|
|
@@ -475,8 +489,11 @@ export interface CommandOptions {
|
|
|
475
489
|
checked?: Bindable<boolean | null>;
|
|
476
490
|
/** Busy state (default false); the player does not call `run` while busy. */
|
|
477
491
|
busy?: Bindable<boolean>;
|
|
478
|
-
/**
|
|
479
|
-
|
|
492
|
+
/**
|
|
493
|
+
* Why the command is disabled or busy (shown to the user): English
|
|
494
|
+
* source text, or a {@link Text} for one with data in it (SDK 1.5.11).
|
|
495
|
+
*/
|
|
496
|
+
reason?: Bindable<TextValue | null>;
|
|
480
497
|
/**
|
|
481
498
|
* Run the command (menu item, binding, panel menu or
|
|
482
499
|
* `host.command(id).run()` in tests). It may return a promise; errors
|
|
@@ -643,15 +660,31 @@ export interface MarkdownOptions {
|
|
|
643
660
|
* is refused (Slint treats `_` and `-` as the same, so use camelCase or
|
|
644
661
|
* kebab-case).
|
|
645
662
|
*
|
|
663
|
+
* A {@link Text} or {@link TextList} goes where the Slint type is `string`,
|
|
664
|
+
* at any depth (SDK 1.5.11, player 0.4.3): the player shows it translated
|
|
665
|
+
* with the plugin's catalog, so a `[string]` model (a ComboBox) can mix
|
|
666
|
+
* words and data. The limits below count it as the string it becomes.
|
|
667
|
+
*
|
|
646
668
|
* A {@link MarkdownRef} goes where the Slint type is `[MarkdownBlock]`: the
|
|
647
669
|
* whole value, or a field at any depth (SDK 1.5.4; older players refuse a
|
|
648
670
|
* nested one). An {@link ImageRef} only as the whole value: nested in an
|
|
649
671
|
* array or object it is `invalid`.
|
|
650
672
|
*
|
|
651
|
-
* Limits per value
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
673
|
+
* Limits per value (`UI_VALUE_LIMITS` in `@vestra-player/sdk/testing`,
|
|
674
|
+
* player 0.4.3; older players: 4096 values and 1024 rows): nesting depth 8,
|
|
675
|
+
* 16384 values in total (every array, object, string, number, boolean and
|
|
676
|
+
* null counts, the value itself included; a document is one), 4096 rows
|
|
677
|
+
* per array, 64 KiB per string or field name and 1 MiB of text in total,
|
|
678
|
+
* field names and the text of its Markdown documents included (256 KB per
|
|
679
|
+
* document). A list of rows with 8 fields is 9 values per row, so about
|
|
680
|
+
* 1800 rows fit. The whole request must also fit the player's 1 MiB
|
|
681
|
+
* message. A value over a limit is refused with code `limit` and the
|
|
682
|
+
* property keeps what it showed (see {@link View.set}); `TestHost` refuses
|
|
683
|
+
* it the same way.
|
|
684
|
+
*
|
|
685
|
+
* The limits bound the work of one write, not the size of your data: for
|
|
686
|
+
* a list that can grow without bound, send the rows near the view and the
|
|
687
|
+
* row count, and move that window as the user scrolls.
|
|
655
688
|
*
|
|
656
689
|
* @since 1.0.0
|
|
657
690
|
* @category UI
|
|
@@ -671,7 +704,7 @@ export type PropValue = PropData | ImageRef;
|
|
|
671
704
|
* @since 1.5.4
|
|
672
705
|
* @category UI
|
|
673
706
|
*/
|
|
674
|
-
export type PropData = null | boolean | number | string | MarkdownRef | PropData[] | {
|
|
707
|
+
export type PropData = null | boolean | number | string | MarkdownRef | Text | TextList | PropData[] | {
|
|
675
708
|
[key: string]: PropData;
|
|
676
709
|
};
|
|
677
710
|
/**
|
|
@@ -914,7 +947,13 @@ export interface View {
|
|
|
914
947
|
* the next update pass replaces the set value with the bound one.
|
|
915
948
|
*
|
|
916
949
|
* Never throws. A write that fails is retried with back-off and reported
|
|
917
|
-
* to {@link Scope.onError}
|
|
950
|
+
* to {@link Scope.onError} (the first failure of a run of failures; the
|
|
951
|
+
* message names the property). A value over the limits of
|
|
952
|
+
* {@link PropValue} fails with `limit`. As an initial property (written
|
|
953
|
+
* while the view is not open) it makes {@link Window.show} reject; a
|
|
954
|
+
* panel or settings page still opens without it (the property keeps its
|
|
955
|
+
* default) and the failure goes to the plugin's `onError` (player 0.4.3;
|
|
956
|
+
* older players left it out silently).
|
|
918
957
|
*
|
|
919
958
|
* @capability That of the view: `ui.window`, `ui.mount` or `ui.settings`.
|
|
920
959
|
*
|
|
@@ -947,7 +986,9 @@ export interface View {
|
|
|
947
986
|
* run. A view can have several bindings; when two return the same name,
|
|
948
987
|
* the one bound later wins.
|
|
949
988
|
*
|
|
950
|
-
* Never throws. Writes that fail are not repeated until the value
|
|
989
|
+
* Never throws. Writes that fail are not repeated until the value
|
|
990
|
+
* changes, and are reported to {@link Scope.onError} like a failed
|
|
991
|
+
* {@link View.set} (a value over the limits of {@link PropValue}: `limit`).
|
|
951
992
|
*
|
|
952
993
|
* @capability That of the view: `ui.window`, `ui.mount` or `ui.settings`.
|
|
953
994
|
*
|
|
@@ -2018,14 +2059,92 @@ export type Locale = "en" | "zh-Hans" | "ja" | "ko" | "de" | "fr" | "es";
|
|
|
2018
2059
|
export type LanguagePreference = "system" | Locale;
|
|
2019
2060
|
/**
|
|
2020
2061
|
* Arguments of a template sentence ({@link Osd.show},
|
|
2021
|
-
* {@link OsdPanel.set}, {@link ConfirmOptions.args}): an
|
|
2022
|
-
* `{0}`, `{1}` placeholders, or an object for `{name}`
|
|
2023
|
-
* 16
|
|
2062
|
+
* {@link OsdPanel.set}, {@link ConfirmOptions.args}, {@link I18n.text}): an
|
|
2063
|
+
* array for `{}` and `{0}`, `{1}` placeholders, or an object for `{name}`
|
|
2064
|
+
* placeholders. At most 16. Strings and finite numbers are data, shown as
|
|
2065
|
+
* they are (whole numbers without a fraction); a {@link Text} or
|
|
2066
|
+
* {@link TextList} argument (SDK 1.5.11, player 0.4.3) is translated too,
|
|
2067
|
+
* so a sentence can be built from translated parts.
|
|
2024
2068
|
*
|
|
2025
2069
|
* @since 1.5.9
|
|
2026
2070
|
* @category UI
|
|
2027
2071
|
*/
|
|
2028
|
-
export type TemplateArgs = readonly
|
|
2072
|
+
export type TemplateArgs = readonly TextArg[] | Readonly<Record<string, TextArg>>;
|
|
2073
|
+
/**
|
|
2074
|
+
* A text the player translates with the plugin's catalog and fills in:
|
|
2075
|
+
* English source text with its arguments. Made by {@link I18n.text}; plain
|
|
2076
|
+
* data, not a translation (the plugin never sees the translated string).
|
|
2077
|
+
*
|
|
2078
|
+
* @remarks
|
|
2079
|
+
* Accepted wherever the player shows a plugin's text: command titles, path
|
|
2080
|
+
* segments and reasons, {@link Osd.show} and {@link OsdPanel.set} (as the
|
|
2081
|
+
* text or an argument), the texts of {@link Dialogs.confirm}, file dialog
|
|
2082
|
+
* titles and `saveFile`'s `fileName`, and property values where Slint
|
|
2083
|
+
* expects a `string` (at any depth: a `[string]` model, a struct field).
|
|
2084
|
+
* Nested in another text's arguments it is translated too. Requires player
|
|
2085
|
+
* 0.4.3. Limits: `TEXT_LIMITS` in `@vestra-player/sdk/testing`.
|
|
2086
|
+
*
|
|
2087
|
+
* The wire form `{ $vestraText, args }` is what the player reads; write it
|
|
2088
|
+
* with {@link I18n.text}, so that `vestra-plugin i18n extract` finds the
|
|
2089
|
+
* source text.
|
|
2090
|
+
*
|
|
2091
|
+
* @since 1.5.11
|
|
2092
|
+
* @category UI
|
|
2093
|
+
*/
|
|
2094
|
+
export interface Text {
|
|
2095
|
+
/** The English source text: a template with `{}`, `{0}` or `{name}`. */
|
|
2096
|
+
readonly $vestraText: string;
|
|
2097
|
+
/** Values for its placeholders. */
|
|
2098
|
+
readonly args?: TemplateArgs;
|
|
2099
|
+
}
|
|
2100
|
+
/**
|
|
2101
|
+
* Values joined the way the interface language joins them ("a, b" in
|
|
2102
|
+
* English, "a、b" in Chinese). Made by {@link I18n.list}; accepted where a
|
|
2103
|
+
* {@link Text} is.
|
|
2104
|
+
*
|
|
2105
|
+
* @since 1.5.11
|
|
2106
|
+
* @category UI
|
|
2107
|
+
*/
|
|
2108
|
+
export interface TextList {
|
|
2109
|
+
/** The items: data, or texts the player translates. */
|
|
2110
|
+
readonly $vestraList: readonly TextArg[];
|
|
2111
|
+
/** How they are joined; `"list"` by default. */
|
|
2112
|
+
readonly style?: ListStyle;
|
|
2113
|
+
}
|
|
2114
|
+
/**
|
|
2115
|
+
* How a {@link TextList} is joined, per interface language:
|
|
2116
|
+
*
|
|
2117
|
+
* | style | English | 简体中文 | 日本語 |
|
|
2118
|
+
* | --- | --- | --- | --- |
|
|
2119
|
+
* | `list` (enumeration) | `, ` | `、` | `、` |
|
|
2120
|
+
* | `clauses` (parts of one sentence) | `, ` | `,` | `、` |
|
|
2121
|
+
* | `semicolons` | `; ` | `;` | `;` |
|
|
2122
|
+
* | `sentences` (no final full stop) | `. ` | `。` | `。` |
|
|
2123
|
+
* | `lines` | line break | line break | line break |
|
|
2124
|
+
*
|
|
2125
|
+
* Korean, German and Spanish join as English; French puts a narrow space
|
|
2126
|
+
* before `;`.
|
|
2127
|
+
*
|
|
2128
|
+
* @since 1.5.11
|
|
2129
|
+
* @category UI
|
|
2130
|
+
*/
|
|
2131
|
+
export type ListStyle = "list" | "clauses" | "semicolons" | "sentences" | "lines";
|
|
2132
|
+
/**
|
|
2133
|
+
* An argument of a template: data (a string or a finite number, shown as it
|
|
2134
|
+
* is) or a {@link Text} or {@link TextList} (translated).
|
|
2135
|
+
*
|
|
2136
|
+
* @since 1.5.11
|
|
2137
|
+
* @category UI
|
|
2138
|
+
*/
|
|
2139
|
+
export type TextArg = string | number | Text | TextList;
|
|
2140
|
+
/**
|
|
2141
|
+
* A text the player shows: English source text (translated as a whole), a
|
|
2142
|
+
* {@link Text} or a {@link TextList}.
|
|
2143
|
+
*
|
|
2144
|
+
* @since 1.5.11
|
|
2145
|
+
* @category UI
|
|
2146
|
+
*/
|
|
2147
|
+
export type TextValue = string | Text | TextList;
|
|
2029
2148
|
/**
|
|
2030
2149
|
* The interface language of this run. `plugin.i18n`.
|
|
2031
2150
|
*
|
|
@@ -2043,6 +2162,11 @@ export type TemplateArgs = readonly (string | number)[] | Readonly<Record<string
|
|
|
2043
2162
|
* its arguments (`osd.show("Speed {}×", [rate])`), never a sentence
|
|
2044
2163
|
* composed in TypeScript.
|
|
2045
2164
|
*
|
|
2165
|
+
* Where words and data cannot be separated that way (a menu item with a
|
|
2166
|
+
* number, a `[string]` model, a sentence made of translated parts), the
|
|
2167
|
+
* plugin passes a text value ({@link I18n.text}, {@link I18n.list}; SDK
|
|
2168
|
+
* 1.5.11): data the player translates, never a translated string.
|
|
2169
|
+
*
|
|
2046
2170
|
* The language is fixed when the player starts: {@link I18n.locale} never
|
|
2047
2171
|
* changes during a run. Read it for what is not text, such as the order of
|
|
2048
2172
|
* names or a date format. `vestra-plugin i18n extract` collects the texts
|
|
@@ -2067,6 +2191,132 @@ export interface I18n {
|
|
|
2067
2191
|
* neither names a {@link Locale}. Players before 0.4.3 report `"en"`.
|
|
2068
2192
|
*/
|
|
2069
2193
|
readonly locale: Locale;
|
|
2194
|
+
/**
|
|
2195
|
+
* A text that mixes words with data, for the player to translate: the
|
|
2196
|
+
* English source text (a template) and its arguments. It returns a plain
|
|
2197
|
+
* {@link Text} value, not a translation; pass it where the player shows
|
|
2198
|
+
* text (see {@link Text}) and the player shows it translated with this
|
|
2199
|
+
* plugin's catalog. `vestra-plugin i18n extract` collects `source` from
|
|
2200
|
+
* every call, so write it as a literal (or a conditional of literals, or
|
|
2201
|
+
* an `as const` table entry).
|
|
2202
|
+
*
|
|
2203
|
+
* Arguments are data unless they are texts themselves, so a sentence can
|
|
2204
|
+
* be built from translated parts without composing it in TypeScript.
|
|
2205
|
+
* `text` does not use `this`: `const { text, list } = plugin.i18n` works.
|
|
2206
|
+
*
|
|
2207
|
+
* @param source - English source text; `{}`, `{0}` or `{name}` for the
|
|
2208
|
+
* arguments, `{{` and `}}` for braces.
|
|
2209
|
+
* @param args - Values for its placeholders.
|
|
2210
|
+
* @throws `invalid` A malformed or over-limit value (`TEXT_LIMITS`).
|
|
2211
|
+
*
|
|
2212
|
+
* @example A ComboBox model with fixed words and data
|
|
2213
|
+
* ```ts
|
|
2214
|
+
* const { text } = plugin.i18n;
|
|
2215
|
+
* const picker = plugin.windows.create("ui/clip.slint");
|
|
2216
|
+
* const tracks = [{ id: 7, title: "en" }];
|
|
2217
|
+
* picker.set({
|
|
2218
|
+
* labels: [text("No Audio"), ...tracks.map((t) => text("Track {} · {}", [t.id, t.title]))],
|
|
2219
|
+
* });
|
|
2220
|
+
* ```
|
|
2221
|
+
*
|
|
2222
|
+
* @example A message built from translated parts
|
|
2223
|
+
* ```ts
|
|
2224
|
+
* await plugin.osd.show("Download failed: {}", [plugin.i18n.text("Connection timed out")]);
|
|
2225
|
+
* ```
|
|
2226
|
+
*
|
|
2227
|
+
* @capability None.
|
|
2228
|
+
*
|
|
2229
|
+
* @since 1.5.11
|
|
2230
|
+
*/
|
|
2231
|
+
text(source: string, args?: TemplateArgs): Text;
|
|
2232
|
+
/**
|
|
2233
|
+
* Items joined the way the interface language joins them (see
|
|
2234
|
+
* {@link ListStyle}): `list(["a.glsl", "b.glsl"])` shows "a.glsl, b.glsl"
|
|
2235
|
+
* in English and "a.glsl、b.glsl" in Chinese. Items are data, or texts the
|
|
2236
|
+
* player translates. Accepted where a {@link Text} is.
|
|
2237
|
+
*
|
|
2238
|
+
* @param items - At most 256.
|
|
2239
|
+
* @param style - `"list"` by default.
|
|
2240
|
+
* @throws `invalid` A malformed or over-limit value.
|
|
2241
|
+
*
|
|
2242
|
+
* @example
|
|
2243
|
+
* ```ts
|
|
2244
|
+
* const missing = ["a.glsl", "b.glsl"];
|
|
2245
|
+
* await plugin.osd.show("Removed missing shaders: {}", [plugin.i18n.list(missing)]);
|
|
2246
|
+
* ```
|
|
2247
|
+
*
|
|
2248
|
+
* @capability None.
|
|
2249
|
+
*
|
|
2250
|
+
* @since 1.5.11
|
|
2251
|
+
*/
|
|
2252
|
+
list(items: readonly TextArg[], style?: ListStyle): TextList;
|
|
2253
|
+
/**
|
|
2254
|
+
* An `Error` whose words the player shows translated: throw it where the
|
|
2255
|
+
* player shows a plugin's failure to the user, such as from a
|
|
2256
|
+
* file or web resolver's `resolve` ({@link FileResolverOptions}, {@link WebResolverOptions}) (also when a stream
|
|
2257
|
+
* fails while it starts). The player shows `text` translated with this
|
|
2258
|
+
* plugin's catalog (as `player.state.error` and the failure message);
|
|
2259
|
+
* `message` is the English rendering, for logs and older players.
|
|
2260
|
+
* Elsewhere it is an ordinary `Error`.
|
|
2261
|
+
*
|
|
2262
|
+
* @param source - English source text, as {@link I18n.text}'s.
|
|
2263
|
+
* @param args - Values for its placeholders.
|
|
2264
|
+
* @throws `invalid` A malformed or over-limit value.
|
|
2265
|
+
*
|
|
2266
|
+
* @example
|
|
2267
|
+
* ```ts
|
|
2268
|
+
* plugin.resolvers.add({
|
|
2269
|
+
* id: "nes",
|
|
2270
|
+
* extensions: ["nes"],
|
|
2271
|
+
* async resolve() {
|
|
2272
|
+
* throw plugin.i18n.error("The ROM file was not found.");
|
|
2273
|
+
* },
|
|
2274
|
+
* });
|
|
2275
|
+
* ```
|
|
2276
|
+
*
|
|
2277
|
+
* @capability None.
|
|
2278
|
+
*
|
|
2279
|
+
* @since 1.5.11
|
|
2280
|
+
*/
|
|
2281
|
+
error(source: string, args?: TemplateArgs): TextError;
|
|
2282
|
+
/**
|
|
2283
|
+
* The string a text shows in this run's language, for text that leaves
|
|
2284
|
+
* the player: what the plugin copies to the clipboard or writes to a file
|
|
2285
|
+
* ("Copy info", "Save as…"). Translated with this plugin's catalog (a
|
|
2286
|
+
* string as a whole, a {@link Text} or {@link TextList} with its
|
|
2287
|
+
* arguments), the way the player would show it.
|
|
2288
|
+
*
|
|
2289
|
+
* Only for text leaving the player. Never use it for the interface (a
|
|
2290
|
+
* window, the menu, the OSD, a dialog): pass the value itself there, so
|
|
2291
|
+
* the player translates it and `vestra-plugin i18n check` can see the
|
|
2292
|
+
* sentence is whole.
|
|
2293
|
+
*
|
|
2294
|
+
* @param value - Source text, or a text value.
|
|
2295
|
+
* @returns The translated string.
|
|
2296
|
+
* @throws `invalid` A malformed value.
|
|
2297
|
+
*
|
|
2298
|
+
* @example
|
|
2299
|
+
* ```ts
|
|
2300
|
+
* const { text, list, resolve } = plugin.i18n;
|
|
2301
|
+
* const lines = list([text("Version {}", ["1.0"]), text("Cores: {}", [8])], "lines");
|
|
2302
|
+
* await plugin.clipboard.writeText(resolve(lines));
|
|
2303
|
+
* ```
|
|
2304
|
+
*
|
|
2305
|
+
* @capability None.
|
|
2306
|
+
*
|
|
2307
|
+
* @since 1.5.11
|
|
2308
|
+
*/
|
|
2309
|
+
resolve(value: TextValue): string;
|
|
2310
|
+
}
|
|
2311
|
+
/**
|
|
2312
|
+
* An `Error` the player shows translated ({@link I18n.error}).
|
|
2313
|
+
*
|
|
2314
|
+
* @since 1.5.11
|
|
2315
|
+
* @category UI
|
|
2316
|
+
*/
|
|
2317
|
+
export interface TextError extends Error {
|
|
2318
|
+
/** What the player shows. */
|
|
2319
|
+
readonly text: Text;
|
|
2070
2320
|
}
|
|
2071
2321
|
/**
|
|
2072
2322
|
* The categories of the Options window. The tree shows them in this order:
|
|
@@ -2479,6 +2729,9 @@ export interface TimelineLayer extends Disposable {
|
|
|
2479
2729
|
* Replace the layer (last write wins; `[]` clears it). At most 1000 marks,
|
|
2480
2730
|
* titles ≤ 100 characters, times within the media. Failures go to `onError`;
|
|
2481
2731
|
* with `ifCurrent`, a write for another source is dropped silently.
|
|
2732
|
+
* A title is data (a chapter's or bookmark's own name), or a {@link Text}
|
|
2733
|
+
* the player translates (`text("Chapter {}", [n])`, SDK 1.5.11); other
|
|
2734
|
+
* plugins read the shown string.
|
|
2482
2735
|
*
|
|
2483
2736
|
* @example
|
|
2484
2737
|
* ```ts
|
|
@@ -2493,7 +2746,7 @@ export interface TimelineLayer extends Disposable {
|
|
|
2493
2746
|
set(marks: {
|
|
2494
2747
|
time: number;
|
|
2495
2748
|
kind: MarkKind;
|
|
2496
|
-
title?: string;
|
|
2749
|
+
title?: string | Text;
|
|
2497
2750
|
}[], options?: {
|
|
2498
2751
|
ifCurrent?: PlayerState;
|
|
2499
2752
|
}): void;
|
|
@@ -2687,17 +2940,17 @@ export interface DisplayInfo {
|
|
|
2687
2940
|
*/
|
|
2688
2941
|
export interface ConfirmOptions {
|
|
2689
2942
|
/** The question, shown in bold; 1–200 characters. */
|
|
2690
|
-
message:
|
|
2943
|
+
message: TextValue;
|
|
2691
2944
|
/** More text under the message; at most 2000 characters. */
|
|
2692
|
-
detail?:
|
|
2945
|
+
detail?: TextValue;
|
|
2693
2946
|
/** The confirm button's text (the default button: Enter picks it); 1–40 characters. */
|
|
2694
|
-
confirm:
|
|
2947
|
+
confirm: TextValue;
|
|
2695
2948
|
/**
|
|
2696
2949
|
* The cancel button's text (Escape picks it); 1–40 characters.
|
|
2697
2950
|
*
|
|
2698
2951
|
* @defaultValue "Cancel", in the player's language
|
|
2699
2952
|
*/
|
|
2700
|
-
cancel?:
|
|
2953
|
+
cancel?: TextValue;
|
|
2701
2954
|
/**
|
|
2702
2955
|
* Mark the confirm button as destructive: red text on macOS, a warning
|
|
2703
2956
|
* icon on Windows.
|
|
@@ -2706,9 +2959,11 @@ export interface ConfirmOptions {
|
|
|
2706
2959
|
*/
|
|
2707
2960
|
destructive?: boolean;
|
|
2708
2961
|
/** A checkbox under the text, such as "Don't ask again"; 1–40 characters. */
|
|
2709
|
-
checkbox?:
|
|
2962
|
+
checkbox?: TextValue;
|
|
2710
2963
|
/**
|
|
2711
2964
|
* Values for the placeholders of `message` and `detail` (player 0.4.3).
|
|
2965
|
+
* Any of the texts may instead be a {@link Text} (SDK 1.5.11), which
|
|
2966
|
+
* carries its own arguments; `args` only fills the string ones.
|
|
2712
2967
|
* Every text of the dialog is English source text that the player shows
|
|
2713
2968
|
* translated from the plugin's catalog; `message` and `detail` are
|
|
2714
2969
|
* templates like {@link Osd.show}'s. The length limits apply to the shown
|
|
@@ -2827,8 +3082,8 @@ export interface Dialogs {
|
|
|
2827
3082
|
* @since 1.0.0
|
|
2828
3083
|
*/
|
|
2829
3084
|
openFile(options?: {
|
|
2830
|
-
/** The dialog's title, at most 256 bytes. */
|
|
2831
|
-
title?:
|
|
3085
|
+
/** The dialog's title (English source text or a {@link Text}), at most 256 bytes. */
|
|
3086
|
+
title?: TextValue;
|
|
2832
3087
|
}): Promise<string | null>;
|
|
2833
3088
|
/**
|
|
2834
3089
|
* Ask the user for one or more files to open.
|
|
@@ -2852,8 +3107,8 @@ export interface Dialogs {
|
|
|
2852
3107
|
* @since 1.0.0
|
|
2853
3108
|
*/
|
|
2854
3109
|
openFiles(options?: {
|
|
2855
|
-
/** The dialog's title, at most 256 bytes. */
|
|
2856
|
-
title?:
|
|
3110
|
+
/** The dialog's title (English source text or a {@link Text}), at most 256 bytes. */
|
|
3111
|
+
title?: TextValue;
|
|
2857
3112
|
}): Promise<string[]>;
|
|
2858
3113
|
/**
|
|
2859
3114
|
* Ask the user for a folder.
|
|
@@ -2877,8 +3132,8 @@ export interface Dialogs {
|
|
|
2877
3132
|
* @since 1.0.0
|
|
2878
3133
|
*/
|
|
2879
3134
|
openDirectory(options?: {
|
|
2880
|
-
/** The dialog's title, at most 256 bytes. */
|
|
2881
|
-
title?:
|
|
3135
|
+
/** The dialog's title (English source text or a {@link Text}), at most 256 bytes. */
|
|
3136
|
+
title?: TextValue;
|
|
2882
3137
|
}): Promise<string | null>;
|
|
2883
3138
|
/**
|
|
2884
3139
|
* Ask the user where to save a file.
|
|
@@ -2908,10 +3163,15 @@ export interface Dialogs {
|
|
|
2908
3163
|
* @since 1.0.0
|
|
2909
3164
|
*/
|
|
2910
3165
|
saveFile(options?: {
|
|
2911
|
-
/** The dialog's title, at most 256 bytes. */
|
|
2912
|
-
title?:
|
|
2913
|
-
/**
|
|
2914
|
-
|
|
3166
|
+
/** The dialog's title (English source text or a {@link Text}), at most 256 bytes. */
|
|
3167
|
+
title?: TextValue;
|
|
3168
|
+
/**
|
|
3169
|
+
* The proposed file name: a plain name, at most 256 bytes. A string is
|
|
3170
|
+
* data (not translated); a {@link Text} (SDK 1.5.11) is shown
|
|
3171
|
+
* translated, `text("Playlist.m3u8")` (a `/` or `\\` in a translation
|
|
3172
|
+
* becomes `-`).
|
|
3173
|
+
*/
|
|
3174
|
+
fileName?: TextValue;
|
|
2915
3175
|
}): Promise<string | null>;
|
|
2916
3176
|
}
|
|
2917
3177
|
/** One audio track of the current media ({@link PlayerState.audioTracks}). */
|
|
@@ -3488,7 +3748,9 @@ export interface OsdPanel extends Disposable {
|
|
|
3488
3748
|
* @param text - The text, with `\n` between lines: at most 32 lines and
|
|
3489
3749
|
* 4096 bytes once translated and formatted. `null` hides the block. A
|
|
3490
3750
|
* template, like {@link Osd.show}'s.
|
|
3491
|
-
* @param args - Values for its placeholders (player 0.4.3)
|
|
3751
|
+
* @param args - Values for its placeholders (player 0.4.3); `null` or
|
|
3752
|
+
* omitted for none.
|
|
3753
|
+
* @param options - `maxColumns`: cut long lines (SDK 1.5.11).
|
|
3492
3754
|
*
|
|
3493
3755
|
* @example
|
|
3494
3756
|
* ```ts
|
|
@@ -3499,7 +3761,23 @@ export interface OsdPanel extends Disposable {
|
|
|
3499
3761
|
*
|
|
3500
3762
|
* @since 1.0.0
|
|
3501
3763
|
*/
|
|
3502
|
-
set(text:
|
|
3764
|
+
set(text: TextValue | null, args?: TemplateArgs | null, options?: OsdPanelOptions): void;
|
|
3765
|
+
}
|
|
3766
|
+
/**
|
|
3767
|
+
* Options of {@link OsdPanel.set}.
|
|
3768
|
+
*
|
|
3769
|
+
* @since 1.5.11
|
|
3770
|
+
* @category UI
|
|
3771
|
+
*/
|
|
3772
|
+
export interface OsdPanelOptions {
|
|
3773
|
+
/**
|
|
3774
|
+
* Cut every line longer than this many columns, after translation and
|
|
3775
|
+
* formatting, ending it with `…`: a wide character (Chinese, Japanese,
|
|
3776
|
+
* Korean, full-width forms) is two columns, a combining mark none, any
|
|
3777
|
+
* other one. An integer from 8 to 1000 (player 0.4.3; older players show
|
|
3778
|
+
* whole lines). Measure the video area to choose it.
|
|
3779
|
+
*/
|
|
3780
|
+
maxColumns?: number;
|
|
3503
3781
|
}
|
|
3504
3782
|
/**
|
|
3505
3783
|
* Text the player draws over the video: short messages and an information
|
|
@@ -3543,6 +3821,9 @@ export interface Osd {
|
|
|
3543
3821
|
* shows as it is (braces included). Untranslated, the English template is
|
|
3544
3822
|
* formatted. Never compose the sentence in TypeScript
|
|
3545
3823
|
* (`` `Speed ${rate}×` ``): translators can only translate whole templates.
|
|
3824
|
+
* An argument that is itself words is a {@link Text} (SDK 1.5.11), and a
|
|
3825
|
+
* message made of a varying number of parts is a {@link TextList} of
|
|
3826
|
+
* texts; `text` may also be a `Text` (then without `args`).
|
|
3546
3827
|
*
|
|
3547
3828
|
* @capability ui.osd
|
|
3548
3829
|
*
|
|
@@ -3565,7 +3846,7 @@ export interface Osd {
|
|
|
3565
3846
|
*
|
|
3566
3847
|
* @since 1.0.0
|
|
3567
3848
|
*/
|
|
3568
|
-
show(text:
|
|
3849
|
+
show(text: TextValue, args?: TemplateArgs): Promise<void>;
|
|
3569
3850
|
/**
|
|
3570
3851
|
* Create this plugin's information block.
|
|
3571
3852
|
*
|
|
@@ -3870,7 +4151,9 @@ export interface Subtitles {
|
|
|
3870
4151
|
/**
|
|
3871
4152
|
* Upload a subtitle file's bytes (UTF-8 SRT, or ASS/SSA with
|
|
3872
4153
|
* `format: "ass"`) for the current source; select it unless
|
|
3873
|
-
* `select: "none"`. `title` (1–200 characters) names the track
|
|
4154
|
+
* `select: "none"`. `title` (1–200 characters) names the track: data, or
|
|
4155
|
+
* a {@link Text} the player translates (`text("{} · {}", [text("Simplified
|
|
4156
|
+
* Chinese"), file])`, SDK 1.5.11). Aborting
|
|
3874
4157
|
* `signal` before the commit discards the upload (rejects with AbortError);
|
|
3875
4158
|
* once the commit was sent it completes.
|
|
3876
4159
|
*
|
|
@@ -3880,7 +4163,7 @@ export interface Subtitles {
|
|
|
3880
4163
|
*/
|
|
3881
4164
|
load(bytes: Uint8Array, options?: SubtitleConditional & {
|
|
3882
4165
|
format?: "srt" | "ass";
|
|
3883
|
-
title?: string;
|
|
4166
|
+
title?: string | Text;
|
|
3884
4167
|
select?: "primary" | "secondary" | "none";
|
|
3885
4168
|
signal?: AbortSignal;
|
|
3886
4169
|
}): Promise<SubtitleTrack>;
|
|
@@ -4467,8 +4750,20 @@ export interface BindingRef {
|
|
|
4467
4750
|
export interface BindingInfo extends BindingRef {
|
|
4468
4751
|
/** Menu title. */
|
|
4469
4752
|
title: string;
|
|
4470
|
-
/** Menu path; `null` for a command outside the menu. */
|
|
4753
|
+
/** Menu path as shown; `null` for a command outside the menu. */
|
|
4471
4754
|
path: string[] | null;
|
|
4755
|
+
/**
|
|
4756
|
+
* The menu path's keys: the English text menus merge by, the same in
|
|
4757
|
+
* every interface language (`["Playback", "Seek", "Back 5 s"]`; a
|
|
4758
|
+
* built-in menu by its key, `"Video"`, also when declared as `@video`).
|
|
4759
|
+
* `null` for a command outside the menu, and from players before 0.4.3.
|
|
4760
|
+
* Find a command by where it is in the menu with this, not with `path`.
|
|
4761
|
+
* Always set by `list()`; optional so that test fakes written for older
|
|
4762
|
+
* SDKs still type-check.
|
|
4763
|
+
*
|
|
4764
|
+
* @since 1.5.11
|
|
4765
|
+
*/
|
|
4766
|
+
key?: string[] | null;
|
|
4472
4767
|
/** Global, or only while the plugin's panel has focus. */
|
|
4473
4768
|
scope: "global" | "panel";
|
|
4474
4769
|
/** The command's own bindings. */
|
package/dist/plugin/ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Tool windows, docked panels and system dialogs. */
|
|
2
|
-
import { templateArgs } from "./osd.js";
|
|
2
|
+
import { shownText, templateArgs } from "./osd.js";
|
|
3
|
+
import { isTextValue } from "../i18n.js";
|
|
3
4
|
import { readFileSync } from "node:fs";
|
|
4
5
|
import { basename, extname, resolve } from "node:path";
|
|
5
6
|
import { failure, Latest, quiet } from "./runtime.js";
|
|
@@ -647,16 +648,27 @@ export const panels = (scope) => ({
|
|
|
647
648
|
});
|
|
648
649
|
export const dialogs = (scope) => {
|
|
649
650
|
const open = async (kind, options = {}) => {
|
|
650
|
-
const result = await scope.runtime.host.dialogs.open({
|
|
651
|
+
const result = await scope.runtime.host.dialogs.open({
|
|
652
|
+
kind,
|
|
653
|
+
...(options.title === undefined
|
|
654
|
+
? {}
|
|
655
|
+
: { title: shownText(options.title, undefined, "title") }),
|
|
656
|
+
...(options.fileName === undefined
|
|
657
|
+
? {}
|
|
658
|
+
: { fileName: shownText(options.fileName, undefined, "fileName") }),
|
|
659
|
+
});
|
|
651
660
|
return result.cancelled ? [] : result.paths;
|
|
652
661
|
};
|
|
653
662
|
return {
|
|
654
663
|
async confirm(options) {
|
|
655
664
|
const { message, detail, confirm, cancel, destructive, checkbox, args } = options ?? {};
|
|
656
665
|
const values = templateArgs(args);
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
666
|
+
// A string's length is checked here; a text value's (shown) length by
|
|
667
|
+
// the player.
|
|
668
|
+
const length = (text, min, max) => isTextValue(text) ||
|
|
669
|
+
(typeof text === "string" &&
|
|
670
|
+
[...text].length >= min &&
|
|
671
|
+
[...text].length <= max);
|
|
660
672
|
if (!length(message, 1, 200) ||
|
|
661
673
|
!length(confirm, 1, 40) ||
|
|
662
674
|
(detail !== undefined && !length(detail, 0, 2000)) ||
|
|
@@ -664,13 +676,17 @@ export const dialogs = (scope) => {
|
|
|
664
676
|
(checkbox !== undefined && !length(checkbox, 1, 40)) ||
|
|
665
677
|
(destructive !== undefined && typeof destructive !== "boolean"))
|
|
666
678
|
throw failure("invalid", "confirm needs message 1–200, confirm/cancel/checkbox 1–40, detail ≤ 2000 characters");
|
|
679
|
+
// `args` fills the string templates; a text value carries its own.
|
|
680
|
+
const shown = (text, what) => shownText(text, undefined, what);
|
|
667
681
|
const answer = await scope.runtime.host.dialogs.confirm({
|
|
668
|
-
message,
|
|
669
|
-
confirm,
|
|
670
|
-
...(detail === undefined ? {} : { detail }),
|
|
671
|
-
...(cancel === undefined ? {} : { cancel }),
|
|
682
|
+
message: shown(message, "message"),
|
|
683
|
+
confirm: shown(confirm, "confirm"),
|
|
684
|
+
...(detail === undefined ? {} : { detail: shown(detail, "detail") }),
|
|
685
|
+
...(cancel === undefined ? {} : { cancel: shown(cancel, "cancel") }),
|
|
672
686
|
...(destructive === undefined ? {} : { destructive }),
|
|
673
|
-
...(checkbox === undefined
|
|
687
|
+
...(checkbox === undefined
|
|
688
|
+
? {}
|
|
689
|
+
: { checkbox: shown(checkbox, "checkbox") }),
|
|
674
690
|
...(values === undefined ? {} : { args: values }),
|
|
675
691
|
});
|
|
676
692
|
return {
|