foo_ui_webview2 v1.11.0
Added
TrayMenuItem.playbackAction('play-pause' | 'previous' | 'next' | 'stop') lets a custom tray item declare a playback action the plugin runs natively. Appearance stays caller-controlled; declared items do not emittray:menuItemClicked. Valid only on atype:'normal'leaf;'exit'is not accepted. Prefer this (or built-inshowPlaybackControls) for background-reliable tray playback while the page is hidden.dsp.*andoutput.*now actually work. Eleven handlers (dsp.getChain/getPresets/getAvailable/addDsp/removeDsp/moveDsp/applyPreset/setChain,output.getDevices/getEntries/getSettings) were documented but their source files had never been added to the build, so every call failed as an unregistered method. They are compiled and registered from this release on.menu.getMainMenuacceptslocale(default'auto'),i18n, andwithAvailability(defaulttrue). The SDK signature is nowgetMainMenu(root?, opts?).- Discovery entries gain
path,isDynamic,isDynamicParent,subGuid, andflags;getMainMenuCommandsechoesexpandDynamicanddynamicCount, anddiscovery.getAllServicesaddsmainMenuDynamicCommands.discovery.executeMainMenuCommandaccepts an optionalsubGuidfor commands expanded from a dynamic submenu. metadata.readandmetadata.readByPathacceptcueIndexto address a track explicitly, matchingmetadata.readRaw. It takes precedence over a|subsong:Npath suffix.- SDK-only additive binary adapters:
fb.file.readBinary(),fb.file.writeBinary(),fb.file.writeDataUrl(),fb.metadata.embedArtworkBytes(), andfb.metadata.embedArtworkFromDataUrl(), plusFileBinaryWriteOptionsandMetadataArtworkBytesOptions. They add no new Bridge endpoints. - Optional trailing
optsarguments on five wrappers whose host handlers already read the corresponding keys:fb.file.delete(path, opts?)(moveToTrash),fb.file.copy(source, destination, opts?)(overwrite), andfb.metadata.write(path, tags, opts?)/removeField(path, field, opts?)/removeTag(path, tags, opts?)(cueIndex).metadata.writegainingcueIndexcloses a real gap: this release wiredcueIndexinto the metadata read path only, so writing a tag to a single track inside a CUE sheet or image file was not expressible through the SDK. Every new argument is optional. - Advanced-preferences option Deep-suspend WebView when hidden (TrySuspend; frees renderer memory) (default on) freezes renderer timers and animations while minimized, covered, locked, or tray-hidden.
- Advanced-preferences option Keep WebView active in background while CDP remote debugging is on (default on), so screenshot and timing automation over the DevTools Protocol stays stable.
windowIdparameter typings forwindow.getBackdropPolicyandwindow.setBackdropPolicy.
Fixed
- Fixed a crash in
output.getDevices. Some output backends report a device name with a "length unknown" sentinel instead of a real length; the handler used that value verbatim and read far past the end of the string, terminating foobar2000. - Fixed
dsp.moveDspmoving items to the wrong slot. Upward moves landed one position short, so moving an item up by one did nothing and no item could reach the end of the chain. The returnedtonow reports the real final index. - Fixed
metadata.read,metadata.readByPath, andmetadata.readBatchignoring the track index inside a container. A|subsong:Nsuffix was neither stripped nor honored, so reading a single track out of a CUE sheet, ISO image, or multi-track file either failed outright or returned the first track's tags. This is why such files could be read in the foobar2000 UI but not through the API. dsp.getPresetsreportsselectedIndex: -1when no preset is selected, instead of the internal sentinel18446744073709551615, which is not representable as a JavaScript number.dsp.getChainalways includesactivePresetandactivePresetIndex, usingnull/-1when no preset is selected. The keys were previously absent in those cases.- Fixed UTF-8 serialization and context-mode selection for custom menus.
- Hardened recovery after a WebView2 crash: a failed render process no longer leaves an unresponsive blank window.
- Improved album-art delivery: fixed cache entries that could serve another track's image, tightened request and parameter validation, and moved image decoding off the interface thread.
artwork.*request and response shapes are unchanged. - Breaking type fix — the published response types for
ui.isMinimized()andui.isAlwaysOnTop()were wrong and now match the wire contract:isMinimizedresolves with{ minimized }(there is noisMinimizedalias), andisAlwaysOnTopresolves with{ enabled, isAlwaysOnTop }. Runtime behavior is unchanged; TypeScript code written against the old declarations must be updated. - Corrected two published type declarations that did not match the host contract:
dsp.setChaintakes a requireddspsarray of{ guid }objects (it was typeddsps?: string[]), and theplaylist:created/playlist:renamedpayloads keepname: string. fb.metadata.readByPath()now resolves withMetadataReadByPathResponseinstead of a bareJsonObject.fb.http.request()now dispatches through the documentedhttp.getendpoint; a stale internal parameter could previously forward a mismatched method name.fb.playcount.set()no longer sends thecountkey, which the host never read.
Changed
dsp.setChainrejects a call that contains any unusable entry instead of silently skipping it. Previously a chain built from three entries could apply only two and still reportsuccess: true. Each per-entry failure now returns an index-tagged reason (dsps[0] must be an object,dsps[0]: guid is required,dsps[0]: Invalid GUID format: …,dsps[0]: DSP not found or no default preset: …). The chain is left untouched whenever a call is rejected.discovery.getMainMenuCommandsanddiscovery.searchCommandsnow expand components that build their submenu at runtime (mainmenu_commands_v2, e.g. ESLyric), so results include child commands in addition to the parent slot. Pass{ expandDynamic: false }for the previous static-registry-only result.- While the page is hidden (minimized, covered, tray-hidden, or locked), high-rate regenerable streams stop at the source:
audio:spectrum,playback:time, andplayback:timeHighResare not produced, and resume on the next tick once the page is visible again. Every other event is delivered reliably and in order — nothing is dropped or merged — including async replies such ashttp:response,library:getAllResult, andaudio:fullWaveformReady. Themes that draw a spectrum or a seek position should read a gap as "page hidden", not as "playback stopped". tray:menuItemClickedcovers ordinary user items and rich value controls only. Built-in playback / system injections and items declaringplaybackActionexecute natively without the click event; reflect button state fromplayback:*.
1.11.0 中文说明
新增功能
- 新增
TrayMenuItem.playbackAction('play-pause' | 'previous' | 'next' | 'stop'):自定义托盘项可声明由插件原生执行的播放动作。外观仍由调用方控制;声明项不发tray:menuItemClicked。仅可用于type:'normal'的叶子项,不接受'exit'。主页面深挂起时要后台可靠的托盘播放控制,请用本字段或内置showPlaybackControls。 dsp.*与output.*现在真正可用。 这 11 个处理器(dsp.getChain/getPresets/getAvailable/addDsp/removeDsp/moveDsp/applyPreset/setChain,output.getDevices/getEntries/getSettings)此前虽有文档,但其源文件从未被加入编译,所以任何调用都会因方法未注册而失败。自本版起已编译并注册。menu.getMainMenu新增locale(默认'auto')、i18n、withAvailability(默认true)三个选项,SDK 侧签名变为getMainMenu(root?, opts?)。- Discovery 命令条目新增
path、isDynamic、isDynamicParent、subGuid、flags;响应新增expandDynamic、dynamicCount,discovery.getAllServices新增mainMenuDynamicCommands。discovery.executeMainMenuCommand新增可选参数subGuid,用于执行由动态子菜单展开出的命令。 metadata.read与metadata.readByPath新增cueIndex参数,可显式指定轨道,与metadata.readRaw一致,优先级高于路径中的|subsong:N后缀。- 新增仅 SDK 层的 additive 二进制适配 helper:
fb.file.readBinary()、fb.file.writeBinary()、fb.file.writeDataUrl()、fb.metadata.embedArtworkBytes()、fb.metadata.embedArtworkFromDataUrl(),以及公开类型FileBinaryWriteOptions、MetadataArtworkBytesOptions。不新增 Bridge endpoint。 - 为五个 wrapper 补上可选的末位
opts参数,对应的键宿主 handler 早已读取:fb.file.delete(path, opts?)(moveToTrash)、fb.file.copy(source, destination, opts?)(overwrite),以及fb.metadata.write(path, tags, opts?)/removeField(path, field, opts?)/removeTag(path, tags, opts?)(cueIndex)。其中metadata.write支持cueIndex补上了一处真实缺口:本版只把cueIndex接进了元数据读取侧,因此此前无法通过 SDK 向 CUE 或镜像文件中的单曲写标签。所有新增参数均为可选,既有调用点不受影响。 - 新增高级设置项
Deep-suspend WebView when hidden (TrySuspend; frees renderer memory)(默认开启):最小化 / 被遮挡 / 锁屏 / 托盘隐藏时冻结渲染进程计时器与动画,便于系统回收内存。 - 新增高级设置项
Keep WebView active in background while CDP remote debugging is on(默认开启):开启 CDP 远程调试时保持 WebView 后台活跃,保证截图与时序类自动化工具稳定。 window.getBackdropPolicy/window.setBackdropPolicy补齐windowId参数类型声明。
Bug 修复
- 修复
output.getDevices崩溃。部分输出后端在回调里用「长度未知」哨兵值代替真实长度,原实现直接采用该值,导致读取远超字符串末尾并使 foobar2000 终止。 - 修复
dsp.moveDsp移动到错误位置。升序移动会少一格,因此向上移动一位等于无操作,且任何项都无法移到链尾。返回的to现在是真实的最终索引。 - 修复
metadata.read、metadata.readByPath、metadata.readBatch忽略容器内轨道编号的问题。路径里的|subsong:N后缀既没有被剥离也没有被采用,因此从 CUE、ISO 镜像或多轨文件里读取单条轨道时,要么直接失败,要么返回首轨的标签。这正是这类文件在 foobar2000 界面里能读、经 API 读不到的原因。 dsp.getPresets在无选中预设时返回selectedIndex: -1,不再返回无法用 JavaScript number 表示的内部哨兵值18446744073709551615。dsp.getChain始终包含activePreset与activePresetIndex,无选中预设时为null/-1。此前这两个键完全缺失。- 修复自定义菜单的 UTF-8 序列化与上下文模式选择。
- 收敛 WebView2 崩溃后的僵尸态:进程失败后按重载次数上限决定重载或重建,不再停留在无响应页面。
- 改进封面获取:修正了换曲或改标签后可能返回上一首封面的缓存问题,并把解码移出 UI 线程。
artwork.*的请求与响应结构未变。 - 破坏性类型修正 —— 修正两处错误的返回类型声明:
ui.isMinimized()为{ minimized }(不存在isMinimized别名)、ui.isAlwaysOnTop()为{ enabled, isAlwaysOnTop }。运行时行为未变,按旧声明编写的 TypeScript 代码需要相应调整。 - 修正两处与宿主契约不符的公开类型声明:
dsp.setChain的dsps是必填的{ guid }对象数组(原声明为dsps?: string[]);playlist:created/playlist:renamed的 payload 保持name: string。 fb.metadata.readByPath()的返回类型由裸JsonObject收窄为MetadataReadByPathResponse。fb.http.request()现在经由文档声明的http.get端点派发;此前一个失效的内部参数可能转发错配的方法名。fb.playcount.set()不再发送宿主从未读取的count键。
行为变更
dsp.setChain遇到任何不可用条目时整体拒绝,不再静默跳过。此前用三个条目构造的链可能只应用两个却仍返回success: true。每个条目级失败都返回带索引的原因(dsps[0] must be an object、dsps[0]: guid is required、dsps[0]: Invalid GUID format: …、dsps[0]: DSP not found or no default preset: …)。任何调用被拒绝时链都保持不变。discovery.getMainMenuCommands与discovery.searchCommands现在默认展开运行时构建子菜单的组件(mainmenu_commands_v2,例如 ESLyric),这会改变既有返回结果:除父级槽位外还会含其子命令。传{ expandDynamic: false }可回到仅静态注册表的旧行为。- 页面不可见期间(最小化、被遮挡、托盘隐藏或锁屏),高频可再生流在生产侧即停止:
audio:spectrum、playback:time、playback:timeHighRes不再产生,恢复可见后下一拍自然到达。其余事件一律可靠按序投递,不丢弃也不合并,包括http:response、library:getAllResult、audio:fullWaveformReady等异步应答。绘制频谱或播放进度的主题应把数据中断理解为「页面隐藏」而非「播放停止」。 tray:menuItemClicked仅覆盖普通用户项与富值控件;内置播放 / 系统注入项与声明了playbackAction的项原生执行且不发点击事件,按钮态从playback:*反映。
📥 Installation · 安装
Download foo_ui_webview2-1.11.0.fb2k-component below (x86 + x64 bundled), double-click it (or Preferences → Components → Install…), then restart foobar2000.
下载下方 foo_ui_webview2-1.11.0.fb2k-component(含 x86/x64),双击安装(或 选项 → Components → Install…),重启 foobar2000。
SDK (npm): npm install foo-webview-sdk@1.11.0
MCP (npm): npm install foo-ui-webview2-mcp@0.1.1
📚 Documentation · 文档
- Online · 在线:https://nereafantasia.github.io/foo_ui_webview2/ (English · 中文)
- Offline · 离线:download
foo_ui_webview2-docs-1.11.0.zip, unzip, runopen-docs.cmd— Windows 10/11 built-in PowerShell only, no Node.js / npm / admin / Internet required
下载foo_ui_webview2-docs-1.11.0.zip解压后运行open-docs.cmd,仅需 Windows 10/11 内置 PowerShell,无需 Node.js、npm、管理员权限或联网 - README:https://github.com/NereaFantasia/foo_ui_webview2#readme