Library Handler
A LibraryHandler is the plugin component that exposes a music source to Pipe Bomb. It is responsible for discovering tracks, verifying they still exist, and producing audio for playback.
Registration
ctx.registerLibraryHandler({
id: "my-library",
enable(apiCtx) {
/* called once */
},
getName() {
return "My Music Library";
},
async scan(taskCtx) {
/* discover tracks */
},
async doTracksExist(trackIds) {
/* verify */ return trackIds;
},
async getAudioProducer(trackId, type) {
/* return producer */
},
});
One plugin can call registerLibraryHandler multiple times to expose multiple libraries.
Interface
id
Unique string within the plugin. Combined with the plugin ID to form a (pluginId, libraryId) pair that identifies every track in the database.
enable(apiCtx)
Called once when the library is registered. The LibraryHandlerApiContext gives you:
| Method | Purpose |
|---|---|
addTrack(track, runId) |
Register a track with the server during a scan |
removeTrack(id) |
Remove a track by its track ID |
useAttributeSource(source) |
Register an inline attribute source scoped to this library |
registerPluginTask(task) |
Register a task specific to this library |
getName()
Returns the human-readable name shown in the Libraries settings page. This can be static or read from plugin config.
scan(taskCtx)
Called by the server when a library scan is triggered. Your implementation should walk the source (filesystem, API, etc.) and call addTrack() for every track it finds.
async scan(taskCtx) {
const tracks = await discoverMyTracks();
for (const [i, track] of tracks.entries()) {
await apiCtx.addTrack({
id: track.uniqueId,
/* Track fields */
}, taskCtx.getRunId());
taskCtx.update(i / tracks.length);
}
}
The runId passed to addTrack is stored on the track record. After scanning, the server uses it to detect tracks that weren't reported in this run and calls doTracksExist on them.
doTracksExist(trackIds)
Given a list of track IDs that were not seen in the latest scan, return the subset that still exist. Tracks not returned are deleted from the database.
async doTracksExist(trackIds) {
return trackIds.filter(id => mySource.has(id));
}
getAudioProducer(trackId, type)
Called when a user plays a track. Return an AudioProducer matching the requested type, or null if the type cannot be served.
See development/Streaming for AudioProducer details and the difference between stream and HLS modes.
Track object
The Track passed to addTrack is a plain object:
{
id: string; // your unique ID for this track within this library
// any other fields your attribute source will use
}
Metadata (title, duration, album art) comes from development/Attribute-Source, not from addTrack. The track id is all the server stores from the scan itself.
Related pages
- users/Libraries — user-facing explanation of libraries and scanning
- development/Streaming — implementing
AudioProducer - development/Attribute-Source — providing metadata for scanned tracks
- development/Plugin-Development — plugin entry point and SDK overview