Skip to content

v1.11.0

Latest

Choose a tag to compare

@NereaFantasia NereaFantasia released this 27 Jul 16:05

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 emit tray:menuItemClicked. Valid only on a type:'normal' leaf; 'exit' is not accepted. Prefer this (or built-in showPlaybackControls) for background-reliable tray playback while the page is hidden.
  • dsp.* and output.* 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.getMainMenu accepts locale (default 'auto'), i18n, and withAvailability (default true). The SDK signature is now getMainMenu(root?, opts?).
  • Discovery entries gain path, isDynamic, isDynamicParent, subGuid, and flags; getMainMenuCommands echoes expandDynamic and dynamicCount, and discovery.getAllServices adds mainMenuDynamicCommands. discovery.executeMainMenuCommand accepts an optional subGuid for commands expanded from a dynamic submenu.
  • metadata.read and metadata.readByPath accept cueIndex to address a track explicitly, matching metadata.readRaw. It takes precedence over a |subsong:N path suffix.
  • SDK-only additive binary adapters: fb.file.readBinary(), fb.file.writeBinary(), fb.file.writeDataUrl(), fb.metadata.embedArtworkBytes(), and fb.metadata.embedArtworkFromDataUrl(), plus FileBinaryWriteOptions and MetadataArtworkBytesOptions. They add no new Bridge endpoints.
  • Optional trailing opts arguments on five wrappers whose host handlers already read the corresponding keys: fb.file.delete(path, opts?) (moveToTrash), fb.file.copy(source, destination, opts?) (overwrite), and fb.metadata.write(path, tags, opts?) / removeField(path, field, opts?) / removeTag(path, tags, opts?) (cueIndex). metadata.write gaining cueIndex closes a real gap: this release wired cueIndex into 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.
  • windowId parameter typings for window.getBackdropPolicy and window.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.moveDsp moving 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 returned to now reports the real final index.
  • Fixed metadata.read, metadata.readByPath, and metadata.readBatch ignoring the track index inside a container. A |subsong:N suffix 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.getPresets reports selectedIndex: -1 when no preset is selected, instead of the internal sentinel 18446744073709551615, which is not representable as a JavaScript number.
  • dsp.getChain always includes activePreset and activePresetIndex, using null / -1 when 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() and ui.isAlwaysOnTop() were wrong and now match the wire contract: isMinimized resolves with { minimized } (there is no isMinimized alias), and isAlwaysOnTop resolves 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.setChain takes a required dsps array of { guid } objects (it was typed dsps?: string[]), and the playlist:created / playlist:renamed payloads keep name: string.
  • fb.metadata.readByPath() now resolves with MetadataReadByPathResponse instead of a bare JsonObject.
  • fb.http.request() now dispatches through the documented http.get endpoint; a stale internal parameter could previously forward a mismatched method name.
  • fb.playcount.set() no longer sends the count key, which the host never read.

Changed

  • dsp.setChain rejects 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 report success: 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.getMainMenuCommands and discovery.searchCommands now 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, and playback:timeHighRes are 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 as http:response, library:getAllResult, and audio:fullWaveformReady. Themes that draw a spectrum or a seek position should read a gap as "page hidden", not as "playback stopped".
  • tray:menuItemClicked covers ordinary user items and rich value controls only. Built-in playback / system injections and items declaring playbackAction execute natively without the click event; reflect button state from playback:*.

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 / setChainoutput.getDevices / getEntries / getSettings)此前虽有文档,但其源文件从未被加入编译,所以任何调用都会因方法未注册而失败。自本版起已编译并注册。
  • menu.getMainMenu 新增 locale(默认 'auto')、i18nwithAvailability(默认 true)三个选项,SDK 侧签名变为 getMainMenu(root?, opts?)
  • Discovery 命令条目新增 pathisDynamicisDynamicParentsubGuidflags;响应新增 expandDynamicdynamicCountdiscovery.getAllServices 新增 mainMenuDynamicCommandsdiscovery.executeMainMenuCommand 新增可选参数 subGuid,用于执行由动态子菜单展开出的命令。
  • metadata.readmetadata.readByPath 新增 cueIndex 参数,可显式指定轨道,与 metadata.readRaw 一致,优先级高于路径中的 |subsong:N 后缀。
  • 新增仅 SDK 层的 additive 二进制适配 helper:fb.file.readBinary()fb.file.writeBinary()fb.file.writeDataUrl()fb.metadata.embedArtworkBytes()fb.metadata.embedArtworkFromDataUrl(),以及公开类型 FileBinaryWriteOptionsMetadataArtworkBytesOptions。不新增 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.readmetadata.readByPathmetadata.readBatch 忽略容器内轨道编号的问题。路径里的 |subsong:N 后缀既没有被剥离也没有被采用,因此从 CUE、ISO 镜像或多轨文件里读取单条轨道时,要么直接失败,要么返回首轨的标签。这正是这类文件在 foobar2000 界面里能读、经 API 读不到的原因。
  • dsp.getPresets 在无选中预设时返回 selectedIndex: -1,不再返回无法用 JavaScript number 表示的内部哨兵值 18446744073709551615
  • dsp.getChain 始终包含 activePresetactivePresetIndex,无选中预设时为 null / -1。此前这两个键完全缺失。
  • 修复自定义菜单的 UTF-8 序列化与上下文模式选择。
  • 收敛 WebView2 崩溃后的僵尸态:进程失败后按重载次数上限决定重载或重建,不再停留在无响应页面。
  • 改进封面获取:修正了换曲或改标签后可能返回上一首封面的缓存问题,并把解码移出 UI 线程。artwork.* 的请求与响应结构未变。
  • 破坏性类型修正 —— 修正两处错误的返回类型声明:ui.isMinimized(){ minimized }(不存在 isMinimized 别名)、ui.isAlwaysOnTop(){ enabled, isAlwaysOnTop }。运行时行为未变,按旧声明编写的 TypeScript 代码需要相应调整
  • 修正两处与宿主契约不符的公开类型声明:dsp.setChaindsps必填{ 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 objectdsps[0]: guid is requireddsps[0]: Invalid GUID format: …dsps[0]: DSP not found or no default preset: …)。任何调用被拒绝时链都保持不变。
  • discovery.getMainMenuCommandsdiscovery.searchCommands 现在默认展开运行时构建子菜单的组件(mainmenu_commands_v2,例如 ESLyric),这会改变既有返回结果:除父级槽位外还会含其子命令。传 { expandDynamic: false } 可回到仅静态注册表的旧行为。
  • 页面不可见期间(最小化、被遮挡、托盘隐藏或锁屏),高频可再生流在生产侧即停止:audio:spectrumplayback:timeplayback:timeHighRes 不再产生,恢复可见后下一拍自然到达。其余事件一律可靠按序投递,不丢弃也不合并,包括 http:responselibrary:getAllResultaudio: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 · 文档