Skip to content

Queues, Discovery, and Keyboard Shortcuts

This page covers the fb.queue, fb.jitQueue, fb.discovery, and fb.keyboard namespaces.

fb.queue Play Queue

fb.queue controls foobar2000's play queue. It is independent of the adaptive streaming queue exposed as fb.jitQueue.

get()

fb.queue.get(): Promise<QueueGetResponse> returns { items, count }. Each QueueItem extends TrackInfo and may include the source playlist and playlistItem indices.

javascript
const queue = await fb.queue.get();
for (const item of queue.items) {
	console.log(item.path, item.playlist, item.playlistItem);
}

getCount()

fb.queue.getCount(): Promise<{ count: number }> returns the current queue length.

add(options)

fb.queue.add(options: QueueAddParams) adds playlist tracks to the queue. The generated contract accepts a playlist selector and a tracks array. The response can include addedCount and queueCount.

javascript
await fb.queue.add({ playlist: 0, tracks: [3, 5] });

addPaths(paths, options?)

fb.queue.addPaths(paths, options?) adds paths or URLs. options is Omit<QueueAddPathsParams, 'paths'> and forwards the generated useQueuePlaylist and playlist fields when supplied.

Each path or URL is limited to 2048 characters. Over-length entries are skipped and reported through invalidCount.

javascript
const result = await fb.queue.addPaths(
	['E:\\Music\\song.flac'],
	{ useQueuePlaylist: true },
);

remove(index)

fb.queue.remove(index: number) removes one queue entry and can return removedIndex, removedCount, and queueCount.

javascript
await fb.queue.remove(0);

moveToTop(index)

fb.queue.moveToTop(index: number) moves an entry to the front of the queue and can return movedIndex and queueCount.

javascript
await fb.queue.moveToTop(3);

flush()

fb.queue.flush() clears the host queue through queue.flush and can return clearedCount.

clear()

fb.queue.clear() clears the play queue and can return clearedCount.

javascript
await fb.queue.clear();

fb.jitQueue Just-in-time Queue

fb.jitQueue is the adaptive playback queue used to preload and switch tracks at runtime. Its item contract uses trackId, title, and url, not playlist indices.

getState()

fb.jitQueue.getState(): Promise<JitQueueStateInfo> returns isActive, state, currentTrackId, nextTrackId, bufferSize, and shadowPlaylist.

javascript
const state = await fb.jitQueue.getState();

enqueueNext(options)

fb.jitQueue.enqueueNext(options: JitQueueEnqueueNextParams) queues a track to play next. URLs are limited to 2048 characters; an over-length URL resolves with { success: false }.

javascript
await fb.jitQueue.enqueueNext({
	trackId: 'next-track',
	title: 'Next track',
	url: 'https://example.invalid/audio/next.flac',
});

playNow(options)

fb.jitQueue.playNow(options: JitQueuePlayNowParams) starts a track immediately and may return shadowPlaylist. The same 2048-character URL limit applies.

javascript
await fb.jitQueue.playNow({
	trackId: 'current-track',
	title: 'Current track',
	url: 'https://example.invalid/audio/current.flac',
});

preloadBatch(options)

fb.jitQueue.preloadBatch(options: JitQueuePreloadBatchParams) preloads urls from an optional startIndex. Set replace to control whether the existing preload buffer is replaced. Over-length URLs are skipped and counted in invalidCount.

javascript
await fb.jitQueue.preloadBatch({
	urls: ['https://example.invalid/audio/one.flac'],
	startIndex: 0,
	replace: true,
});

skip(), stop(), clear(), and notifyEmpty()

  • skip() advances past the current JIT item and may return currentTrackId.
  • stop() invokes jitQueue.stop with the facade's no-argument default behavior.
  • clear() empties the JIT queue.
  • notifyEmpty() notifies the host that the producer has no more tracks.

JIT Queue Events

Subscribe through fb.on() to jitQueue:needNext, jitQueue:trackChanged, jitQueue:listExhausted, jitQueue:preloadComplete, and jitQueue:error. The published payload types are available from the package root.

javascript
const off = fb.on('jitQueue:needNext', ({ currentTrackId, reason }) => {
	console.log(currentTrackId, reason);
});

fb.discovery Service Discovery

fb.discovery enumerates foobar2000 services, menu commands, components, input formats, DSP entries, output devices, UI elements, and preference pages.

MethodContract
getMainMenuCommands(options?)Returns { commands, count, dynamicCount }. Each command includes name, description, guid, parentGuid, and index. Runtime submenus (mainmenu_commands_v2) are expanded by default; expanded children add subGuid, isDynamic, and path. Pass { expandDynamic: false } for the static registry only.
getMainMenuGroups()Returns { groups, count }. Only statically registered mainmenu_group services are listed; runtime submenus are command-node trees, so use getMainMenuCommands() for those.
executeMainMenuCommand(guid, subGuid?)Invokes a main-menu command by GUID; pass subGuid for an entry expanded from a dynamic submenu.
getContextMenuCommands()Returns { commands, count }.
executeContextMenuCommand(options)Accepts DiscoveryExecuteContextMenuCommandParams; the facade forwards guid.
executeContextMenuByPath(options)Accepts path and optional trackPath, then may return foundName and itemCount.
getContextMenuTree()Returns the current context-menu tree and optional itemCount.
searchCommands(query, options?)Searches main-menu command names, descriptions, and paths; returns optional results and count. Dynamic submenus are expanded by default.
javascript
const commands = await fb.discovery.getMainMenuCommands();
await fb.discovery.executeMainMenuCommand(commands.commands[0].guid);

await fb.discovery.executeContextMenuByPath({
	path: 'Properties',
	trackPath: 'E:\\Music\\song.flac',
});

Service Inventories

MethodResponse data
getAllServices(){ services, totalServices }, where services contains aggregate counts.
getInputFormats(){ fileTypes, count }.
getComponents(){ components, count }.
getUIElements(){ elements, count }.
getDspEntries(){ entries, count }.
getOutputDevices(){ devices, count }.
getPreferencePages(){ pages, count }.
javascript
const formats = await fb.discovery.getInputFormats();
const components = await fb.discovery.getComponents();

fb.keyboard Hotkeys and Shortcuts

registerHotkey(key, action, options?)

fb.keyboard.registerHotkey(key, action, options?) invokes keyboard.registerHotkey. options is Omit<KeyboardRegisterHotkeyParams, 'key' | 'action'> and can set global. The facade currently types the optional response id as string; getRegisteredHotkeys() exposes each registered HotkeyInfo.id as number.

javascript
const result = await fb.keyboard.registerHotkey(
	'Ctrl+Shift+P',
	'playPause',
	{ global: true },
);

registerShortcut(key, action)

fb.keyboard.registerShortcut(key, action) registers a shortcut without the extended options object.

javascript
await fb.keyboard.registerShortcut('Space', 'toggle');

unregisterHotkey(options)

fb.keyboard.unregisterHotkey(options: KeyboardUnregisterHotkeyParams) unregisters by key, id, or the supported combination.

javascript
await fb.keyboard.unregisterHotkey({ key: 'Ctrl+Shift+P' });

getRegisteredHotkeys()

fb.keyboard.getRegisteredHotkeys(): Promise<KeyboardGetRegisteredHotkeysResponse> returns { success, hotkeys }. Each HotkeyInfo contains id, key, action, and global.

javascript
const { hotkeys } = await fb.keyboard.getRegisteredHotkeys();

keyboard:hotkey

The keyboard:hotkey event carries KeyboardHotkeyPayload with id, key, and action.

javascript
fb.on('keyboard:hotkey', ({ id, key, action }) => {
	console.log(id, key, action);
});