@jxgame2020/dsh-token-quota 0.1.24 → 0.1.26
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/lib/client.js +338 -246
- package/lib/index.js +7 -4
- package/lib/types/client/TokenQuotaPanel.d.ts +3 -1
- package/lib/types/client/TokenQuotaPanel.js +3 -2
- package/lib/types/client/index.js +26 -8
- package/lib/types/client/locales.d.ts +4 -0
- package/lib/types/client/locales.js +4 -0
- package/lib/types/client/music.d.ts +43 -34
- package/lib/types/client/music.js +217 -128
- package/lib/types/client/store.d.ts +2 -0
- package/lib/types/client/store.js +2 -0
- package/lib/types/index.js +2 -0
- package/lib/types/types.d.ts +7 -0
- package/lib/types/types.js +1 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -40,6 +40,7 @@ window.__ModuleLoader__.load({
|
|
|
40
40
|
musicEnabled: false,
|
|
41
41
|
musicVolume: .5,
|
|
42
42
|
musicStyle: "major",
|
|
43
|
+
musicOnlyCurrentSession: true,
|
|
43
44
|
upgrade: null,
|
|
44
45
|
upgradeDismissed: false,
|
|
45
46
|
checkingUpdates: false,
|
|
@@ -90,8 +91,11 @@ window.__ModuleLoader__.load({
|
|
|
90
91
|
setMusicStyle: (d, style) => {
|
|
91
92
|
d.musicStyle = style;
|
|
92
93
|
},
|
|
94
|
+
setMusicOnlyCurrentSession: (d, only) => {
|
|
95
|
+
d.musicOnlyCurrentSession = only;
|
|
96
|
+
},
|
|
93
97
|
setUpgrade: (d, upgrade) => {
|
|
94
|
-
const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.
|
|
98
|
+
const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.26" ? upgrade : null;
|
|
95
99
|
if (d.upgrade === null || d.upgrade.latestVersion !== normalized?.latestVersion) d.upgradeDismissed = false;
|
|
96
100
|
d.upgrade = normalized;
|
|
97
101
|
},
|
|
@@ -197,92 +201,92 @@ window.__ModuleLoader__.load({
|
|
|
197
201
|
document.head.appendChild(tag);
|
|
198
202
|
}
|
|
199
203
|
var TokenQuotaPanel_module_css_default = {
|
|
200
|
-
"
|
|
204
|
+
"checkBtn": "NPLLIq_checkBtn",
|
|
205
|
+
"body": "NPLLIq_body",
|
|
206
|
+
"dialogLabel": "NPLLIq_dialogLabel",
|
|
207
|
+
"upgradeBanner": "NPLLIq_upgradeBanner",
|
|
208
|
+
"dialogActions": "NPLLIq_dialogActions",
|
|
201
209
|
"currentBadge": "NPLLIq_currentBadge",
|
|
210
|
+
"dialogBody": "NPLLIq_dialogBody",
|
|
211
|
+
"notice": "NPLLIq_notice",
|
|
212
|
+
"rowMeta": "NPLLIq_rowMeta",
|
|
213
|
+
"title": "NPLLIq_title",
|
|
214
|
+
"logPagerInfo": "NPLLIq_logPagerInfo",
|
|
215
|
+
"headerText": "NPLLIq_headerText",
|
|
216
|
+
"bar": "NPLLIq_bar",
|
|
217
|
+
"noticeError": "NPLLIq_noticeError",
|
|
218
|
+
"tab": "NPLLIq_tab",
|
|
219
|
+
"logScroll": "NPLLIq_logScroll",
|
|
220
|
+
"dialogTitle": "NPLLIq_dialogTitle",
|
|
221
|
+
"selectBtn": "NPLLIq_selectBtn",
|
|
222
|
+
"monitorList": "NPLLIq_monitorList",
|
|
223
|
+
"switch": "NPLLIq_switch",
|
|
224
|
+
"monitorRow": "NPLLIq_monitorRow",
|
|
225
|
+
"resetSelect": "NPLLIq_resetSelect",
|
|
226
|
+
"dialogBtn": "NPLLIq_dialogBtn",
|
|
227
|
+
"logHeader": "NPLLIq_logHeader",
|
|
202
228
|
"panelDim": "NPLLIq_panelDim",
|
|
203
|
-
"
|
|
204
|
-
"
|
|
205
|
-
"
|
|
206
|
-
"
|
|
229
|
+
"logToolbar": "NPLLIq_logToolbar",
|
|
230
|
+
"upgradeCommands": "NPLLIq_upgradeCommands",
|
|
231
|
+
"upgradeHint": "NPLLIq_upgradeHint",
|
|
232
|
+
"logDayCol": "NPLLIq_logDayCol",
|
|
233
|
+
"settingsBtn": "NPLLIq_settingsBtn",
|
|
234
|
+
"tabLabel": "NPLLIq_tabLabel",
|
|
235
|
+
"dialogClose": "NPLLIq_dialogClose",
|
|
236
|
+
"fillOver": "NPLLIq_fillOver",
|
|
237
|
+
"rowHeader": "NPLLIq_rowHeader",
|
|
238
|
+
"upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
|
|
239
|
+
"copyBtn": "NPLLIq_copyBtn",
|
|
240
|
+
"upgradeClose": "NPLLIq_upgradeClose",
|
|
207
241
|
"logModelCol": "NPLLIq_logModelCol",
|
|
208
|
-
"
|
|
209
|
-
"
|
|
242
|
+
"upgradeCommandRow": "NPLLIq_upgradeCommandRow",
|
|
243
|
+
"logPagerBtn": "NPLLIq_logPagerBtn",
|
|
244
|
+
"upgradeBannerText": "NPLLIq_upgradeBannerText",
|
|
245
|
+
"checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
|
|
246
|
+
"fillWarn": "NPLLIq_fillWarn",
|
|
247
|
+
"headerActions": "NPLLIq_headerActions",
|
|
248
|
+
"save": "NPLLIq_save",
|
|
210
249
|
"checkUpdatesRow": "NPLLIq_checkUpdatesRow",
|
|
211
|
-
"resetRow": "NPLLIq_resetRow",
|
|
212
|
-
"monitorName": "NPLLIq_monitorName",
|
|
213
|
-
"resetSelect": "NPLLIq_resetSelect",
|
|
214
250
|
"settingsBtnActive": "NPLLIq_settingsBtnActive",
|
|
215
|
-
"upgradeBannerText": "NPLLIq_upgradeBannerText",
|
|
216
|
-
"upgradeClose": "NPLLIq_upgradeClose",
|
|
217
|
-
"fullNotice": "NPLLIq_fullNotice",
|
|
218
251
|
"radioRow": "NPLLIq_radioRow",
|
|
252
|
+
"logClearBtn": "NPLLIq_logClearBtn",
|
|
253
|
+
"logPageSizeSelect": "NPLLIq_logPageSizeSelect",
|
|
219
254
|
"dialogHint": "NPLLIq_dialogHint",
|
|
220
|
-
"
|
|
221
|
-
"
|
|
222
|
-
"selectBtn": "NPLLIq_selectBtn",
|
|
223
|
-
"upgradeCommands": "NPLLIq_upgradeCommands",
|
|
224
|
-
"fillWarn": "NPLLIq_fillWarn",
|
|
225
|
-
"upgradeCommand": "NPLLIq_upgradeCommand",
|
|
226
|
-
"checkBtn": "NPLLIq_checkBtn",
|
|
227
|
-
"dialog": "NPLLIq_dialog",
|
|
228
|
-
"logDayCol": "NPLLIq_logDayCol",
|
|
255
|
+
"logClearDialog": "NPLLIq_logClearDialog",
|
|
256
|
+
"monitorName": "NPLLIq_monitorName",
|
|
229
257
|
"dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
|
|
230
258
|
"logPager": "NPLLIq_logPager",
|
|
259
|
+
"logClearDate": "NPLLIq_logClearDate",
|
|
260
|
+
"rowName": "NPLLIq_rowName",
|
|
261
|
+
"logDialog": "NPLLIq_logDialog",
|
|
231
262
|
"dialogOverlay": "NPLLIq_dialogOverlay",
|
|
232
|
-
"
|
|
233
|
-
"
|
|
234
|
-
"
|
|
235
|
-
"
|
|
236
|
-
"
|
|
237
|
-
"
|
|
263
|
+
"logUsedCol": "NPLLIq_logUsedCol",
|
|
264
|
+
"input": "NPLLIq_input",
|
|
265
|
+
"gearBtn": "NPLLIq_gearBtn",
|
|
266
|
+
"row": "NPLLIq_row",
|
|
267
|
+
"monitorHint": "NPLLIq_monitorHint",
|
|
268
|
+
"header": "NPLLIq_header",
|
|
269
|
+
"logPagerPages": "NPLLIq_logPagerPages",
|
|
270
|
+
"versionNew": "NPLLIq_versionNew",
|
|
238
271
|
"subtitle": "NPLLIq_subtitle",
|
|
239
|
-
"logClearDate": "NPLLIq_logClearDate",
|
|
240
|
-
"headerActions": "NPLLIq_headerActions",
|
|
241
|
-
"dialogTitle": "NPLLIq_dialogTitle",
|
|
242
|
-
"logClearBtn": "NPLLIq_logClearBtn",
|
|
243
|
-
"dialogBody": "NPLLIq_dialogBody",
|
|
244
|
-
"title": "NPLLIq_title",
|
|
245
|
-
"upgradeHint": "NPLLIq_upgradeHint",
|
|
246
272
|
"version": "NPLLIq_version",
|
|
247
|
-
"
|
|
248
|
-
"
|
|
249
|
-
"
|
|
250
|
-
"
|
|
251
|
-
"copyBtnDone": "NPLLIq_copyBtnDone",
|
|
252
|
-
"tab": "NPLLIq_tab",
|
|
253
|
-
"monitorHint": "NPLLIq_monitorHint",
|
|
254
|
-
"settingsBtn": "NPLLIq_settingsBtn",
|
|
255
|
-
"panelDimStrong": "NPLLIq_panelDimStrong",
|
|
256
|
-
"logToolbar": "NPLLIq_logToolbar",
|
|
257
|
-
"logPagerInfo": "NPLLIq_logPagerInfo",
|
|
258
|
-
"logScroll": "NPLLIq_logScroll",
|
|
273
|
+
"fullNotice": "NPLLIq_fullNotice",
|
|
274
|
+
"resetRow": "NPLLIq_resetRow",
|
|
275
|
+
"logTable": "NPLLIq_logTable",
|
|
276
|
+
"fillIdle": "NPLLIq_fillIdle",
|
|
259
277
|
"checkErrorHint": "NPLLIq_checkErrorHint",
|
|
260
|
-
"rowMeta": "NPLLIq_rowMeta",
|
|
261
|
-
"logPagerBtn": "NPLLIq_logPagerBtn",
|
|
262
|
-
"logPageSizeSelect": "NPLLIq_logPageSizeSelect",
|
|
263
|
-
"bar": "NPLLIq_bar",
|
|
264
|
-
"input": "NPLLIq_input",
|
|
265
|
-
"panel": "NPLLIq_panel",
|
|
266
|
-
"gearBtn": "NPLLIq_gearBtn",
|
|
267
278
|
"tabIcon": "NPLLIq_tabIcon",
|
|
268
|
-
"
|
|
269
|
-
"noticeError": "NPLLIq_noticeError",
|
|
270
|
-
"upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
|
|
271
|
-
"copyBtn": "NPLLIq_copyBtn",
|
|
272
|
-
"switch": "NPLLIq_switch",
|
|
279
|
+
"logPagerControls": "NPLLIq_logPagerControls",
|
|
273
280
|
"collapse": "NPLLIq_collapse",
|
|
274
|
-
"
|
|
275
|
-
"
|
|
276
|
-
"
|
|
277
|
-
"
|
|
278
|
-
"
|
|
279
|
-
"
|
|
280
|
-
"
|
|
281
|
-
"fillIdle": "NPLLIq_fillIdle",
|
|
281
|
+
"upgradeCommand": "NPLLIq_upgradeCommand",
|
|
282
|
+
"copyBtnDone": "NPLLIq_copyBtnDone",
|
|
283
|
+
"dialogSection": "NPLLIq_dialogSection",
|
|
284
|
+
"controls": "NPLLIq_controls",
|
|
285
|
+
"panel": "NPLLIq_panel",
|
|
286
|
+
"panelDimStrong": "NPLLIq_panelDimStrong",
|
|
287
|
+
"logSearch": "NPLLIq_logSearch",
|
|
282
288
|
"dialogHeader": "NPLLIq_dialogHeader",
|
|
283
|
-
"
|
|
284
|
-
"checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
|
|
285
|
-
"header": "NPLLIq_header"
|
|
289
|
+
"dialog": "NPLLIq_dialog"
|
|
286
290
|
};
|
|
287
291
|
//#endregion
|
|
288
292
|
//#region lib/types/client/TokenQuotaPanel.js
|
|
@@ -369,7 +373,7 @@ window.__ModuleLoader__.load({
|
|
|
369
373
|
* @param props - composed slot props.
|
|
370
374
|
* @returns the panel element tree.
|
|
371
375
|
*/
|
|
372
|
-
function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored, setOnFull, setReset, setCheckUpdates, checkUpdatesNow, clearLogBefore, setDimWhenIdle, setMusicEnabled, setMusicVolume, setMusicStyle, useStore, actions, useSessions }) {
|
|
376
|
+
function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored, setOnFull, setReset, setCheckUpdates, checkUpdatesNow, clearLogBefore, setDimWhenIdle, setMusicEnabled, setMusicVolume, setMusicStyle, setMusicOnlyCurrentSession, useStore, actions, useSessions }) {
|
|
373
377
|
const [collapsed, setCollapsed] = (0, react.useState)(false);
|
|
374
378
|
const [drafts, setDrafts] = (0, react.useState)({});
|
|
375
379
|
const [editingKey, setEditingKey] = (0, react.useState)(null);
|
|
@@ -403,6 +407,7 @@ window.__ModuleLoader__.load({
|
|
|
403
407
|
const musicEnabled = useStore((s) => s.musicEnabled);
|
|
404
408
|
const musicVolume = useStore((s) => s.musicVolume);
|
|
405
409
|
const musicStyle = useStore((s) => s.musicStyle);
|
|
410
|
+
const musicOnlyCurrentSession = useStore((s) => s.musicOnlyCurrentSession);
|
|
406
411
|
const upgrade = useStore((s) => s.upgrade);
|
|
407
412
|
const upgradeDismissed = useStore((s) => s.upgradeDismissed);
|
|
408
413
|
const checkingUpdates = useStore((s) => s.checkingUpdates);
|
|
@@ -587,13 +592,13 @@ window.__ModuleLoader__.load({
|
|
|
587
592
|
title: t("upgradeAvailableHint"),
|
|
588
593
|
children: [
|
|
589
594
|
"v",
|
|
590
|
-
"0.1.
|
|
595
|
+
"0.1.26",
|
|
591
596
|
" → v",
|
|
592
597
|
upgrade.latestVersion
|
|
593
598
|
]
|
|
594
599
|
}) : (0, react_jsx_runtime.jsxs)("span", {
|
|
595
600
|
className: TokenQuotaPanel_module_css_default.version,
|
|
596
|
-
children: ["v", "0.1.
|
|
601
|
+
children: ["v", "0.1.26"]
|
|
597
602
|
})]
|
|
598
603
|
}), (0, react_jsx_runtime.jsx)("div", {
|
|
599
604
|
className: TokenQuotaPanel_module_css_default.subtitle,
|
|
@@ -956,41 +961,58 @@ window.__ModuleLoader__.load({
|
|
|
956
961
|
className: TokenQuotaPanel_module_css_default.dialogHint,
|
|
957
962
|
children: t("musicHint")
|
|
958
963
|
}),
|
|
959
|
-
musicEnabled && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
964
|
+
musicEnabled && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
965
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
966
|
+
className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
|
|
967
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("musicVolume") }), (0, react_jsx_runtime.jsx)("input", {
|
|
968
|
+
type: "range",
|
|
969
|
+
min: 0,
|
|
970
|
+
max: 1,
|
|
971
|
+
step: .05,
|
|
972
|
+
value: musicVolume,
|
|
973
|
+
onChange: (event) => {
|
|
974
|
+
setMusicVolume(Number(event.target.value));
|
|
975
|
+
}
|
|
976
|
+
})]
|
|
977
|
+
}),
|
|
978
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
979
|
+
className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
|
|
980
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("musicStyle") }), (0, react_jsx_runtime.jsxs)("select", {
|
|
981
|
+
value: musicStyle,
|
|
982
|
+
onChange: (event) => {
|
|
983
|
+
setMusicStyle(event.target.value);
|
|
984
|
+
},
|
|
985
|
+
children: [
|
|
986
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
987
|
+
value: "major",
|
|
988
|
+
children: t("musicStyleMajor")
|
|
989
|
+
}),
|
|
990
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
991
|
+
value: "minor",
|
|
992
|
+
children: t("musicStyleMinor")
|
|
993
|
+
}),
|
|
994
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
995
|
+
value: "pentatonic",
|
|
996
|
+
children: t("musicStylePentatonic")
|
|
997
|
+
})
|
|
998
|
+
]
|
|
999
|
+
})]
|
|
1000
|
+
}),
|
|
1001
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
1002
|
+
className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
|
|
1003
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
1004
|
+
type: "checkbox",
|
|
1005
|
+
checked: musicOnlyCurrentSession,
|
|
1006
|
+
onChange: (event) => {
|
|
1007
|
+
setMusicOnlyCurrentSession(event.target.checked);
|
|
1008
|
+
}
|
|
1009
|
+
}), (0, react_jsx_runtime.jsx)("span", { children: t("musicOnlyCurrentSessionLabel") })]
|
|
1010
|
+
}),
|
|
1011
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
1012
|
+
className: TokenQuotaPanel_module_css_default.dialogHint,
|
|
1013
|
+
children: t("musicOnlyCurrentSessionHint")
|
|
1014
|
+
})
|
|
1015
|
+
] })
|
|
994
1016
|
]
|
|
995
1017
|
}),
|
|
996
1018
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1210,16 +1232,19 @@ window.__ModuleLoader__.load({
|
|
|
1210
1232
|
//#endregion
|
|
1211
1233
|
//#region lib/types/client/music.js
|
|
1212
1234
|
/**
|
|
1213
|
-
* Live-composed soundtrack driven by host actions (turns, steps,
|
|
1214
|
-
* etc.).
|
|
1215
|
-
* sends MIDI NoteOn/NoteOff to the first available MIDI output when one is
|
|
1216
|
-
* detected (both play simultaneously when MIDI is present — use the panel
|
|
1217
|
-
* volume for overall level, the MIDI output has its own gain on the receiver).
|
|
1235
|
+
* Live-composed ambient soundtrack driven by host actions (turns, steps,
|
|
1236
|
+
* tool calls, etc.). Three layers:
|
|
1218
1237
|
*
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1221
|
-
*
|
|
1222
|
-
*
|
|
1238
|
+
* - **Pad**: a sustained three-note chord (triangle waves) that fades in when
|
|
1239
|
+
* a request starts and crossfades to the next chord on every step.
|
|
1240
|
+
* - **Bass**: one long root note per beat (lower octave), keeps the pulse.
|
|
1241
|
+
* - **Melody**: an eighth-note scale line that dances inside the current
|
|
1242
|
+
* chord — always in key, never a wrong note.
|
|
1243
|
+
*
|
|
1244
|
+
* Outputs through Web Audio (built-in synthesis) by default, and also sends
|
|
1245
|
+
* MIDI NoteOn/NoteOff to the first available MIDI output when one is detected
|
|
1246
|
+
* (both play simultaneously when MIDI is present — use the panel volume for
|
|
1247
|
+
* overall level, the MIDI output has its own gain on the receiver).
|
|
1223
1248
|
*
|
|
1224
1249
|
* @module @jxgame2020/dsh-token-quota/music
|
|
1225
1250
|
*/
|
|
@@ -1295,14 +1320,26 @@ window.__ModuleLoader__.load({
|
|
|
1295
1320
|
"major"
|
|
1296
1321
|
]
|
|
1297
1322
|
};
|
|
1298
|
-
/**
|
|
1299
|
-
* Turn a MIDI note number into a frequency (Hz) using equal temperament at
|
|
1300
|
-
* A4 = 440 Hz.
|
|
1301
|
-
*/
|
|
1323
|
+
/** Turn a MIDI note number into a frequency (equal temperament, A4 = 440). */
|
|
1302
1324
|
function midiToFreq(midi) {
|
|
1303
1325
|
return 440 * Math.pow(2, (midi - 69) / 12);
|
|
1304
1326
|
}
|
|
1305
|
-
/**
|
|
1327
|
+
/** Interval in semitones from the root for each chord-tone. */
|
|
1328
|
+
function chordIntervals(quality) {
|
|
1329
|
+
return [
|
|
1330
|
+
0,
|
|
1331
|
+
quality === "major" ? 4 : quality === "minor" ? 3 : 3,
|
|
1332
|
+
quality === "dim" ? 6 : 7
|
|
1333
|
+
];
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Live-composed music engine driven by host actions.
|
|
1337
|
+
*
|
|
1338
|
+
* The engine is idle until `ensureStarted()` is called from a user gesture
|
|
1339
|
+
* (the panel switch), and only produces sound while `enabled` is true AND a
|
|
1340
|
+
* request is in flight (pad + bass + melody are gated by `startPad` /
|
|
1341
|
+
* `stopPad`).
|
|
1342
|
+
*/
|
|
1306
1343
|
var TokenQuotaMusic = class TokenQuotaMusic {
|
|
1307
1344
|
audio = null;
|
|
1308
1345
|
midiOutput = null;
|
|
@@ -1310,26 +1347,23 @@ window.__ModuleLoader__.load({
|
|
|
1310
1347
|
enabled = false;
|
|
1311
1348
|
volume = .5;
|
|
1312
1349
|
style = "major";
|
|
1313
|
-
/** Current position in the chord progression (advances per step). */
|
|
1314
1350
|
chordIndex = 0;
|
|
1315
|
-
/** Step counter — used for melody degree selection. */
|
|
1316
1351
|
stepCount = 0;
|
|
1317
|
-
/** Tool counter — used for tool-note pitch. */
|
|
1318
1352
|
toolCount = 0;
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
/** Base MIDI note of the
|
|
1353
|
+
padOscs = [];
|
|
1354
|
+
padGain = null;
|
|
1355
|
+
padTarget = 0;
|
|
1356
|
+
padActive = false;
|
|
1357
|
+
beatTimer;
|
|
1358
|
+
beatIndex = 0;
|
|
1359
|
+
melodyDirection = 1;
|
|
1360
|
+
melodyDegree = 0;
|
|
1361
|
+
currentRoot = 60;
|
|
1362
|
+
currentQuality = "major";
|
|
1363
|
+
/** Base MIDI note of the key. C4 = middle C. */
|
|
1330
1364
|
static BASE_MIDI = 60;
|
|
1331
|
-
/**
|
|
1332
|
-
static
|
|
1365
|
+
/** Beat length in ms — eighth note = beat / 2. */
|
|
1366
|
+
static BEAT_MS = 640;
|
|
1333
1367
|
/** True once the audio context has been started (needs a user gesture). */
|
|
1334
1368
|
get started() {
|
|
1335
1369
|
return this.audio !== null;
|
|
@@ -1365,44 +1399,16 @@ window.__ModuleLoader__.load({
|
|
|
1365
1399
|
}
|
|
1366
1400
|
setEnabled(value) {
|
|
1367
1401
|
this.enabled = value;
|
|
1368
|
-
if (!value) this.
|
|
1402
|
+
if (!value) this.stopAll();
|
|
1369
1403
|
}
|
|
1370
1404
|
setVolume(value) {
|
|
1371
1405
|
this.volume = Math.max(0, Math.min(1, value));
|
|
1406
|
+
if (this.padGain !== null && this.audio !== null) this.padGain.gain.setValueAtTime(this.volume * this.padTarget, this.audio.currentTime);
|
|
1372
1407
|
}
|
|
1373
1408
|
setStyle(value) {
|
|
1374
1409
|
this.style = value;
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
startProgress() {
|
|
1378
|
-
if (!this.audio || !this.enabled) return;
|
|
1379
|
-
if (this.progressTimer !== void 0) return;
|
|
1380
|
-
this.progressDegree = 0;
|
|
1381
|
-
this.progressDir = 1;
|
|
1382
|
-
const tick = () => {
|
|
1383
|
-
if (!this.audio || !this.enabled) return;
|
|
1384
|
-
const scale = SCALES[this.style];
|
|
1385
|
-
const degree = this.progressDegree % scale.length;
|
|
1386
|
-
const note = TokenQuotaMusic.BASE_MIDI + 12 + (scale[degree] ?? 0);
|
|
1387
|
-
this.playNote(note, .18, .22);
|
|
1388
|
-
const next = this.progressDegree + this.progressDir;
|
|
1389
|
-
if (next >= scale.length) {
|
|
1390
|
-
this.progressDir = -1;
|
|
1391
|
-
this.progressDegree = scale.length - 2;
|
|
1392
|
-
} else if (next < 0) {
|
|
1393
|
-
this.progressDir = 1;
|
|
1394
|
-
this.progressDegree = 0;
|
|
1395
|
-
} else this.progressDegree = next;
|
|
1396
|
-
};
|
|
1397
|
-
tick();
|
|
1398
|
-
this.progressTimer = setInterval(tick, TokenQuotaMusic.PROGRESS_TICK_MS);
|
|
1399
|
-
}
|
|
1400
|
-
/** Stop the in-flight background loop. */
|
|
1401
|
-
stopProgress() {
|
|
1402
|
-
if (this.progressTimer !== void 0) {
|
|
1403
|
-
clearInterval(this.progressTimer);
|
|
1404
|
-
this.progressTimer = void 0;
|
|
1405
|
-
}
|
|
1410
|
+
this.melodyDegree = 0;
|
|
1411
|
+
this.melodyDirection = 1;
|
|
1406
1412
|
}
|
|
1407
1413
|
/** Handle one incoming host action and turn it into sound. */
|
|
1408
1414
|
onAction(action) {
|
|
@@ -1410,92 +1416,177 @@ window.__ModuleLoader__.load({
|
|
|
1410
1416
|
const base = TokenQuotaMusic.BASE_MIDI;
|
|
1411
1417
|
switch (action.type) {
|
|
1412
1418
|
case "turn/start":
|
|
1413
|
-
this.
|
|
1419
|
+
this.stopAll();
|
|
1414
1420
|
this.chordIndex = 0;
|
|
1415
1421
|
this.stepCount = 0;
|
|
1416
1422
|
this.toolCount = 0;
|
|
1417
|
-
this.
|
|
1423
|
+
this.currentRoot = base;
|
|
1424
|
+
this.currentQuality = CHORD_QUALITIES[this.style][0] ?? "major";
|
|
1425
|
+
this.playChord(base, this.currentQuality, 1.6, .6);
|
|
1418
1426
|
break;
|
|
1419
1427
|
case "step/start": {
|
|
1420
1428
|
this.chordIndex = (this.chordIndex + 1) % CHORD_PROGRESSIONS[this.style].length;
|
|
1421
1429
|
this.stepCount += 1;
|
|
1422
|
-
this.
|
|
1423
|
-
const
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
setTimeout(() => this.playNote(root + d3, .35, .4), 160);
|
|
1430
|
+
const root = base + (CHORD_PROGRESSIONS[this.style][this.chordIndex] ?? 0);
|
|
1431
|
+
const quality = CHORD_QUALITIES[this.style][this.chordIndex] ?? "major";
|
|
1432
|
+
this.currentRoot = root;
|
|
1433
|
+
this.currentQuality = quality;
|
|
1434
|
+
if (this.padActive) this.crossfadePad(root, quality);
|
|
1428
1435
|
break;
|
|
1429
1436
|
}
|
|
1430
1437
|
case "request/header": {
|
|
1431
|
-
this.
|
|
1438
|
+
this.startPad(this.currentRoot, this.currentQuality);
|
|
1439
|
+
this.startBeatClock();
|
|
1432
1440
|
const degree = (this.stepCount * 2 + this.toolCount) % SCALES[this.style].length;
|
|
1433
|
-
const note = base + 12 + SCALES[this.style][degree];
|
|
1434
|
-
this.playNote(note, .
|
|
1441
|
+
const note = base + 12 + (SCALES[this.style][degree] ?? 0);
|
|
1442
|
+
this.playNote(note, .25, .4);
|
|
1435
1443
|
break;
|
|
1436
1444
|
}
|
|
1437
1445
|
case "tool/call":
|
|
1438
1446
|
this.toolCount += 1;
|
|
1439
1447
|
this.playNote(base + 24 + this.toolCount % 3 * 2, .12, .45);
|
|
1440
|
-
this.playNote(base - 12, .08, .
|
|
1448
|
+
this.playNote(base - 12, .08, .3);
|
|
1441
1449
|
break;
|
|
1442
1450
|
case "tool/result":
|
|
1443
1451
|
if (action.error) {
|
|
1444
1452
|
this.playNote(base + 13, .18, .4);
|
|
1445
1453
|
setTimeout(() => this.playNote(base + 12, .25, .4), 90);
|
|
1446
1454
|
} else {
|
|
1447
|
-
this.playNote(base + 9, .14, .
|
|
1448
|
-
setTimeout(() => this.playNote(base + 11, .22, .
|
|
1455
|
+
this.playNote(base + 9, .14, .35);
|
|
1456
|
+
setTimeout(() => this.playNote(base + 11, .22, .35), 70);
|
|
1449
1457
|
}
|
|
1450
1458
|
break;
|
|
1451
1459
|
case "assistant/attempt":
|
|
1452
|
-
this.stopProgress();
|
|
1453
1460
|
this.playNote(base + 8, .18, .4);
|
|
1454
1461
|
setTimeout(() => this.playNote(base + 7, .2, .4), 100);
|
|
1455
|
-
setTimeout(() => this.playNote(base + 5, .
|
|
1462
|
+
setTimeout(() => this.playNote(base + 5, .3, .4), 200);
|
|
1456
1463
|
break;
|
|
1457
1464
|
case "assistant/message":
|
|
1458
|
-
this.
|
|
1459
|
-
|
|
1460
|
-
|
|
1465
|
+
this.stopBeatClock();
|
|
1466
|
+
this.stopPad();
|
|
1467
|
+
if (action.interrupted) this.playChord(base + 7, "dim", .9, .55);
|
|
1468
|
+
else this.playChord(this.currentRoot, this.currentQuality, 1.1, .6);
|
|
1461
1469
|
break;
|
|
1462
1470
|
case "turn/end":
|
|
1463
|
-
this.
|
|
1464
|
-
this.playChord(base, this.style === "minor" ? "minor" : "major", 2.
|
|
1471
|
+
this.stopAll();
|
|
1472
|
+
this.playChord(base, this.style === "minor" ? "minor" : "major", 2.4, .7);
|
|
1465
1473
|
this.chordIndex = 0;
|
|
1466
1474
|
break;
|
|
1467
1475
|
}
|
|
1468
1476
|
}
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1477
|
+
/** Start the pad from silence, fading in to the target level. */
|
|
1478
|
+
startPad(rootMidi, quality) {
|
|
1479
|
+
if (!this.audio) return;
|
|
1480
|
+
if (this.padActive) return;
|
|
1481
|
+
const now = this.audio.currentTime;
|
|
1482
|
+
const gain = this.audio.createGain();
|
|
1483
|
+
gain.gain.setValueAtTime(0, now);
|
|
1484
|
+
gain.connect(this.audio.destination);
|
|
1485
|
+
const intervals = chordIntervals(quality);
|
|
1486
|
+
const oscs = [];
|
|
1487
|
+
for (const interval of intervals) {
|
|
1488
|
+
const osc = this.audio.createOscillator();
|
|
1489
|
+
osc.type = "triangle";
|
|
1490
|
+
osc.frequency.value = midiToFreq(rootMidi + interval);
|
|
1491
|
+
osc.connect(gain);
|
|
1492
|
+
osc.start(now);
|
|
1493
|
+
oscs.push(osc);
|
|
1494
|
+
}
|
|
1495
|
+
this.padOscs = oscs;
|
|
1496
|
+
this.padGain = gain;
|
|
1497
|
+
this.padTarget = .18;
|
|
1498
|
+
gain.gain.linearRampToValueAtTime(this.volume * this.padTarget, now + .6);
|
|
1499
|
+
this.padActive = true;
|
|
1500
|
+
}
|
|
1501
|
+
/** Smoothly morph the pad to a new root + quality. */
|
|
1502
|
+
crossfadePad(rootMidi, quality) {
|
|
1503
|
+
if (!this.audio || !this.padActive || this.padGain === null) return;
|
|
1504
|
+
const now = this.audio.currentTime;
|
|
1505
|
+
const intervals = chordIntervals(quality);
|
|
1506
|
+
this.padOscs.forEach((osc, i) => {
|
|
1507
|
+
const interval = intervals[i] ?? 0;
|
|
1508
|
+
osc.frequency.setValueAtTime(osc.frequency.value, now);
|
|
1509
|
+
osc.frequency.exponentialRampToValueAtTime(midiToFreq(rootMidi + interval), now + .5);
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
/** Fade the pad to silence, then stop the oscillators. */
|
|
1513
|
+
stopPad() {
|
|
1514
|
+
if (!this.audio || !this.padActive || this.padGain === null) return;
|
|
1515
|
+
const now = this.audio.currentTime;
|
|
1516
|
+
const gain = this.padGain;
|
|
1517
|
+
gain.gain.cancelScheduledValues(now);
|
|
1518
|
+
gain.gain.setValueAtTime(gain.gain.value, now);
|
|
1519
|
+
gain.gain.linearRampToValueAtTime(0, now + .8);
|
|
1520
|
+
const oscs = this.padOscs;
|
|
1521
|
+
setTimeout(() => {
|
|
1522
|
+
for (const osc of oscs) {
|
|
1523
|
+
try {
|
|
1524
|
+
osc.stop();
|
|
1525
|
+
} catch {}
|
|
1526
|
+
try {
|
|
1527
|
+
osc.disconnect();
|
|
1528
|
+
} catch {}
|
|
1529
|
+
}
|
|
1530
|
+
try {
|
|
1531
|
+
gain.disconnect();
|
|
1532
|
+
} catch {}
|
|
1533
|
+
}, 850);
|
|
1534
|
+
this.padActive = false;
|
|
1535
|
+
this.padOscs = [];
|
|
1536
|
+
this.padGain = null;
|
|
1537
|
+
}
|
|
1538
|
+
/** Start the per-beat clock that drives bass and melody. */
|
|
1539
|
+
startBeatClock() {
|
|
1540
|
+
if (this.beatTimer !== void 0) return;
|
|
1541
|
+
this.beatIndex = 0;
|
|
1542
|
+
this.melodyDegree = 0;
|
|
1543
|
+
this.melodyDirection = 1;
|
|
1544
|
+
const tick = () => {
|
|
1545
|
+
if (!this.audio || !this.enabled) return;
|
|
1546
|
+
if (this.beatIndex % 2 === 0) this.playNote(this.currentRoot - 12, .45, .3);
|
|
1547
|
+
const scale = SCALES[this.style];
|
|
1548
|
+
const chordTones = new Set(chordIntervals(this.currentQuality));
|
|
1549
|
+
let degree = this.melodyDegree;
|
|
1550
|
+
let next = degree + this.melodyDirection;
|
|
1551
|
+
if (next >= scale.length) {
|
|
1552
|
+
this.melodyDirection = -1;
|
|
1553
|
+
next = scale.length - 2;
|
|
1554
|
+
} else if (next < 0) {
|
|
1555
|
+
this.melodyDirection = 1;
|
|
1556
|
+
next = 0;
|
|
1557
|
+
}
|
|
1558
|
+
this.melodyDegree = next;
|
|
1559
|
+
degree = next;
|
|
1560
|
+
if (this.beatIndex % 2 === 0) {
|
|
1561
|
+
const rootRel = (scale[degree] ?? 0) % 12;
|
|
1562
|
+
if (!chordTones.has(rootRel)) {
|
|
1563
|
+
this.melodyDegree += this.melodyDirection;
|
|
1564
|
+
degree = this.melodyDegree;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
const note = this.currentRoot + 12 + (scale[degree] ?? 0);
|
|
1568
|
+
this.playNote(note, .22, .28);
|
|
1569
|
+
this.beatIndex = (this.beatIndex + 1) % 4;
|
|
1570
|
+
};
|
|
1571
|
+
tick();
|
|
1572
|
+
this.beatTimer = setInterval(tick, TokenQuotaMusic.BEAT_MS);
|
|
1472
1573
|
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1574
|
+
stopBeatClock() {
|
|
1575
|
+
if (this.beatTimer !== void 0) {
|
|
1576
|
+
clearInterval(this.beatTimer);
|
|
1577
|
+
this.beatTimer = void 0;
|
|
1578
|
+
}
|
|
1476
1579
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
0,
|
|
1481
|
-
7,
|
|
1482
|
-
12
|
|
1483
|
-
] : this.currentChordQuality() === "major" ? [
|
|
1484
|
-
0,
|
|
1485
|
-
4,
|
|
1486
|
-
7
|
|
1487
|
-
] : [
|
|
1488
|
-
0,
|
|
1489
|
-
3,
|
|
1490
|
-
7
|
|
1491
|
-
];
|
|
1580
|
+
stopAll() {
|
|
1581
|
+
this.stopBeatClock();
|
|
1582
|
+
this.stopPad();
|
|
1492
1583
|
}
|
|
1493
1584
|
/** Play one note: Web Audio + MIDI simultaneously when available. */
|
|
1494
1585
|
playNote(midi, durationSec, velocity) {
|
|
1495
1586
|
if (!this.audio) return;
|
|
1496
|
-
const now = this.audio.currentTime;
|
|
1497
1587
|
const peak = this.volume * velocity * .5;
|
|
1498
1588
|
if (peak <= 0) return;
|
|
1589
|
+
const now = this.audio.currentTime;
|
|
1499
1590
|
const osc = this.audio.createOscillator();
|
|
1500
1591
|
osc.type = "sine";
|
|
1501
1592
|
osc.frequency.value = midiToFreq(midi);
|
|
@@ -1525,12 +1616,9 @@ window.__ModuleLoader__.load({
|
|
|
1525
1616
|
}
|
|
1526
1617
|
/** Play a three-note chord plus a bass octave below. */
|
|
1527
1618
|
playChord(rootMidi, quality, durationSec, velocity) {
|
|
1528
|
-
const
|
|
1529
|
-
const
|
|
1530
|
-
this.playNote(rootMidi, durationSec, velocity * .
|
|
1531
|
-
this.playNote(rootMidi + third, durationSec, velocity * .35);
|
|
1532
|
-
this.playNote(rootMidi + fifth, durationSec, velocity * .35);
|
|
1533
|
-
this.playNote(rootMidi - 12, durationSec * 1.15, velocity * .45);
|
|
1619
|
+
const intervals = chordIntervals(quality);
|
|
1620
|
+
for (const interval of intervals) this.playNote(rootMidi + interval, durationSec, velocity * .45);
|
|
1621
|
+
this.playNote(rootMidi - 12, durationSec * 1.1, velocity * .5);
|
|
1534
1622
|
}
|
|
1535
1623
|
};
|
|
1536
1624
|
//#endregion
|
|
@@ -1610,6 +1698,8 @@ window.__ModuleLoader__.load({
|
|
|
1610
1698
|
musicStyleMajor: "大调",
|
|
1611
1699
|
musicStyleMinor: "小调",
|
|
1612
1700
|
musicStylePentatonic: "五声",
|
|
1701
|
+
musicOnlyCurrentSessionLabel: "只播当前会话",
|
|
1702
|
+
musicOnlyCurrentSessionHint: "开启后仅当前窗口的会话有音乐,后台子任务静音;关闭则所有会话都参与作曲",
|
|
1613
1703
|
checkUpdatesNow: "立即检查",
|
|
1614
1704
|
checkingUpdates: "检查中…",
|
|
1615
1705
|
checkUpToDate: "已是最新",
|
|
@@ -1684,6 +1774,8 @@ window.__ModuleLoader__.load({
|
|
|
1684
1774
|
musicStyleMajor: "Major",
|
|
1685
1775
|
musicStyleMinor: "Minor",
|
|
1686
1776
|
musicStylePentatonic: "Pentatonic",
|
|
1777
|
+
musicOnlyCurrentSessionLabel: "Current session only",
|
|
1778
|
+
musicOnlyCurrentSessionHint: "When on, only the visible session drives the soundtrack (background tasks stay silent); when off, every session contributes.",
|
|
1687
1779
|
checkUpdatesNow: "Check now",
|
|
1688
1780
|
checkingUpdates: "Checking…",
|
|
1689
1781
|
checkUpToDate: "Up to date",
|
|
@@ -1728,6 +1820,7 @@ window.__ModuleLoader__.load({
|
|
|
1728
1820
|
let lastMonitored = null;
|
|
1729
1821
|
let lastOnFull = "stop";
|
|
1730
1822
|
let lastReset = null;
|
|
1823
|
+
let lastOnlyCurrentSession = true;
|
|
1731
1824
|
const music = new TokenQuotaMusic();
|
|
1732
1825
|
const sse = new EventSource("/token-quota/events");
|
|
1733
1826
|
sse.addEventListener("action", (event) => {
|
|
@@ -1737,12 +1830,19 @@ window.__ModuleLoader__.load({
|
|
|
1737
1830
|
} catch {
|
|
1738
1831
|
return;
|
|
1739
1832
|
}
|
|
1740
|
-
if (lastSessionId !== void 0 && action.sessionId !== String(lastSessionId)) return;
|
|
1833
|
+
if (lastOnlyCurrentSession && lastSessionId !== void 0 && action.sessionId !== String(lastSessionId)) return;
|
|
1741
1834
|
music.onAction(action);
|
|
1742
1835
|
});
|
|
1743
1836
|
ctx.effect(() => () => {
|
|
1744
1837
|
sse.close();
|
|
1745
1838
|
}, "token-quota-ui: music SSE");
|
|
1839
|
+
/** Build a writable music-settings clone with defaults applied. */
|
|
1840
|
+
const musicDefaults = (raw) => ({
|
|
1841
|
+
enabled: raw?.enabled ?? false,
|
|
1842
|
+
volume: raw?.volume ?? .5,
|
|
1843
|
+
style: raw?.style ?? "major",
|
|
1844
|
+
onlyCurrentSession: raw?.onlyCurrentSession ?? true
|
|
1845
|
+
});
|
|
1746
1846
|
const keyOf = (selection) => {
|
|
1747
1847
|
if (selection === null) return void 0;
|
|
1748
1848
|
return `${selection.provider}/${selection.model}`;
|
|
@@ -1852,18 +1952,15 @@ window.__ModuleLoader__.load({
|
|
|
1852
1952
|
bound?.setCheckUpdates(doc?.checkUpdates ?? true);
|
|
1853
1953
|
bound?.setDimWhenIdle(doc?.dimWhenIdle ?? false);
|
|
1854
1954
|
bound?.setReset(lastReset);
|
|
1855
|
-
const musicSettings =
|
|
1856
|
-
|
|
1857
|
-
volume: .5,
|
|
1858
|
-
style: "major",
|
|
1859
|
-
...doc?.music ?? {}
|
|
1860
|
-
};
|
|
1955
|
+
const musicSettings = musicDefaults(doc?.music);
|
|
1956
|
+
lastOnlyCurrentSession = musicSettings.onlyCurrentSession;
|
|
1861
1957
|
music.setEnabled(musicSettings.enabled);
|
|
1862
1958
|
music.setVolume(musicSettings.volume);
|
|
1863
1959
|
music.setStyle(musicSettings.style);
|
|
1864
1960
|
bound?.setMusicEnabled(musicSettings.enabled);
|
|
1865
1961
|
bound?.setMusicVolume(musicSettings.volume);
|
|
1866
1962
|
bound?.setMusicStyle(musicSettings.style);
|
|
1963
|
+
bound?.setMusicOnlyCurrentSession(musicSettings.onlyCurrentSession);
|
|
1867
1964
|
fetch("/token-quota", { headers: { accept: "application/json" } }).then((response) => {
|
|
1868
1965
|
if (!response.ok) {
|
|
1869
1966
|
bound?.setError(`quota route: ${String(response.status)}`);
|
|
@@ -1934,36 +2031,30 @@ window.__ModuleLoader__.load({
|
|
|
1934
2031
|
scope.set("dimWhenIdle", enabled);
|
|
1935
2032
|
};
|
|
1936
2033
|
const setMusicEnabled = (enabled) => {
|
|
1937
|
-
const
|
|
1938
|
-
|
|
1939
|
-
volume: .5,
|
|
1940
|
-
style: "major",
|
|
1941
|
-
...scope.getSnapshot().value?.music ?? {}
|
|
1942
|
-
};
|
|
2034
|
+
const doc = scope.getSnapshot().value;
|
|
2035
|
+
const current = musicDefaults(doc?.music);
|
|
1943
2036
|
current.enabled = enabled;
|
|
1944
2037
|
scope.set("music", current);
|
|
1945
2038
|
if (enabled) music.ensureStarted();
|
|
1946
2039
|
};
|
|
1947
2040
|
const setMusicVolume = (volume) => {
|
|
1948
|
-
const
|
|
1949
|
-
|
|
1950
|
-
volume: .5,
|
|
1951
|
-
style: "major",
|
|
1952
|
-
...scope.getSnapshot().value?.music ?? {}
|
|
1953
|
-
};
|
|
2041
|
+
const doc = scope.getSnapshot().value;
|
|
2042
|
+
const current = musicDefaults(doc?.music);
|
|
1954
2043
|
current.volume = Math.max(0, Math.min(1, volume));
|
|
1955
2044
|
scope.set("music", current);
|
|
1956
2045
|
};
|
|
1957
2046
|
const setMusicStyle = (style) => {
|
|
1958
|
-
const
|
|
1959
|
-
|
|
1960
|
-
volume: .5,
|
|
1961
|
-
style: "major",
|
|
1962
|
-
...scope.getSnapshot().value?.music ?? {}
|
|
1963
|
-
};
|
|
2047
|
+
const doc = scope.getSnapshot().value;
|
|
2048
|
+
const current = musicDefaults(doc?.music);
|
|
1964
2049
|
current.style = style;
|
|
1965
2050
|
scope.set("music", current);
|
|
1966
2051
|
};
|
|
2052
|
+
const setMusicOnlyCurrentSession = (only) => {
|
|
2053
|
+
const doc = scope.getSnapshot().value;
|
|
2054
|
+
const current = musicDefaults(doc?.music);
|
|
2055
|
+
current.onlyCurrentSession = only;
|
|
2056
|
+
scope.set("music", current);
|
|
2057
|
+
};
|
|
1967
2058
|
/** Ask the Host to check the registry right now, then refresh the snapshot. */
|
|
1968
2059
|
const checkUpdatesNow = () => {
|
|
1969
2060
|
bound?.setCheckingUpdates(true);
|
|
@@ -2050,7 +2141,8 @@ window.__ModuleLoader__.load({
|
|
|
2050
2141
|
setDimWhenIdle,
|
|
2051
2142
|
setMusicEnabled,
|
|
2052
2143
|
setMusicVolume,
|
|
2053
|
-
setMusicStyle
|
|
2144
|
+
setMusicStyle,
|
|
2145
|
+
setMusicOnlyCurrentSession
|
|
2054
2146
|
};
|
|
2055
2147
|
};
|
|
2056
2148
|
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|