Skip to content

Providing playlists from other plugins

AF-1 edited this page Sep 20, 2026 · 1 revision

This page explains how any other LMS plugin can supply its own dynamic playlists to Dynamic Playlists (DPL), so that they show up in the DPL menu and can be started and queued exactly like DPL's own built-in and custom playlists.

How it works

DPL does not require your plugin to "register" itself anywhere. Instead, every time DPL needs to (re)build its list of available dynamic playlists, it iterates over all currently enabled LMS plugins and checks, for each one, whether its Plugin.pm package implements both of the following subroutines:

  • getDynamicPlaylists
  • getNextDynamicPlaylistTracks

If (and only if) both subs exist, DPL calls getDynamicPlaylists to obtain the playlist definitions and treats your plugin as a dynamic-playlist provider. So, to hook into DPL, you only need to implement these two subs at package level in your plugin's Plugin.pm - no explicit registration call, no dependency declaration, nothing else is required.

Your plugin does not need to use or depend on the DPL plugin at all — you can implement these two subs unconditionally. If the user does not have DPL installed or enabled, nothing goes wrong: DPL's plugin-scanning code simply never runs, your subs are never called, and no error or warning occurs. Your dynamic-playlist feature just won't appear anywhere, until (and unless) the user installs and enables DPL.


1. getDynamicPlaylists($client)

Called by DPL whenever it (re)builds its menu of available dynamic playlists (e.g. when the DPL menu is opened, or a client's power/sync state changes).

sub getDynamicPlaylists {
	my ($client) = @_;

	return \%myDynamicPlaylists;
}

This sub takes a single argument, $client: the currently active Squeezebox client, or undef if no client context is available (e.g. web UI without a selected player).

Return value

A hashref, keyed by a unique, plugin-specific playlist ID (a plain string, e.g. 'dynamicmixartist'). Each value is itself a hashref describing one dynamic playlist. Prefix your IDs with something unique to your plugin to avoid collisions with other plugins' playlist IDs.

Required keys per playlist entry

Key Type Description
id string Must be identical to the hash key used above.
name string Display name shown in the DPL menu. Should normally come from string(...) so it is localized.

Commonly used optional keys

Key Type Description
url string Relative URL of a settings/info page for this playlist (used by the web UI, e.g. 'plugins/MyPlugin/settings/basic.html?').
groups arrayref of arrayrefs Defines where the playlist appears in the DPL menu tree, e.g. [['My Plugin'], ['Songs']]. If omitted, DPL falls back to playlistcategory, or lists the playlist as "Not classified".
playlistcategory string Flat category name used for sorting/grouping when groups is not used.
menulisttype string Set to 'contextmenu' if this playlist should only be offered as a context-menu action on a track/album/artist/genre (see parameters below) rather than as a normal top-level menu entry.
minlmsversion string Minimum required LMS server version (e.g. '8.4.0'). DPL hides the playlist if the running server is older.
parameters hashref See "The parameters key" below. Omit entirely if the playlist needs no user input.

The parameters key

If your dynamic playlist needs user input before it can produce tracks (e.g. "pick an artist first"), describe it via the parameters key. This is a hashref keyed by parameter position (1, 2, ...); each value is a hashref with:

Key Description
id Same as the hash key (the parameter's position, 1, 2, ...).
type Parameter type. Common built-in types: artist, album, genre, track, year, playlist, list (custom value list), multiplegenres, multipledecades, multipleyears.
name Label shown to the user when asking for this parameter.
definition Only for type => 'list': a hashref mapping each selectable value to its display label, e.g. { 'value1' => 'Label 1', 'value2' => 'Label 2' }.

When menulisttype => 'contextmenu' is combined with a single artist/album/genre/track parameter, DPL automatically offers your playlist as a context-menu entry on matching items (artist/album/genre/track screens), and pre-fills that parameter's value with the item the user was browsing.



2. getNextDynamicPlaylistTracks($client, $dynamicplaylist, $limit, $offset, $parameters)

Called by DPL whenever it needs a (further) batch of tracks for one of your playlists.

sub getNextDynamicPlaylistTracks {
	my ($client, $dynamicplaylist, $limit, $offset, $parameters) = @_;

	my @trackIDs = ();
	my %tracksCompleteInfo = ();

	# ... build @trackIDs here ...

	return \@trackIDs, \%tracksCompleteInfo;
}

Arguments

Name Description
$client The (master, in case of sync groups) client this playlist is being played on.
$dynamicplaylist The same hashref your plugin returned from getDynamicPlaylists for this playlist ID, with dynamicplaylistid and dynamicplaylistplugin added by DPL. Use $dynamicplaylist->{'id'} (or {'dynamicplaylistid'}) to tell which of your playlists is being requested if you registered more than one.
$limit Number of tracks DPL would like returned in this batch.
$offset 0 on the very first call for a freshly-started playlist; incremented by DPL on subsequent calls (used, for instance, if you need to page through a result set). Many plugins can ignore this and just return one/a few tracks per call, reacting only to whether $offset is 0 (first call, pick a fresh seed) or non-zero (continue from previous seed/state).
$parameters Hashref keyed by parameter position (matching the parameters you declared in getDynamicPlaylists), containing only the parameters the user actually set. Each entry is { 'id' => ..., 'value' => ... }.

Return value

A two-element list ($trackIDs, $tracksCompleteInfo):

  1. $trackIDs - an arrayref of numeric track IDs (see Slim::Schema::Track->id), in the order they should be added to the playlist. Return an empty arrayref if no tracks could be found for this call (DPL will retry a limited number of times). Instead of an arrayref, you may return the plain scalar string 'error' to tell DPL that the playlist definition itself is broken (DPL logs an error and stops requesting further tracks for this playlist for the current session).

  2. $tracksCompleteInfo - a hashref, keyed by the same track IDs, for optional extra per-track metadata DPL cannot derive by itself from the track ID alone. In practice this is mainly used to supply primary_artist (the contributor ID), which DPL uses for balanced/varied-artist shuffling. Return an empty hashref ({}) if you have nothing to add here.




Minimal example

The following is a simplified, self-contained pattern/example:

sub getDynamicPlaylists {
	my ($client) = @_;

	my %myDynamicPlaylists = (
		'myplugin_byartist' => {
			'id' => 'myplugin_byartist',
			'name' => string('PLUGIN_MYPLUGIN_TRACKS_BASED_ON_SELECTED_ARTISTS'),
			'menulisttype' => 'contextmenu',
			'playlistcategory' => 'artists',
			'parameters' => {
				1 => {
					'id' => 1,
					'type' => 'artist',
					'name' => 'Choose artist',
				},
			},
		},
	);

	return \%myDynamicPlaylists;
}

sub getNextDynamicPlaylistTracks {
	my ($client, $dynamicplaylist, $limit, $offset, $parameters) = @_;

	my $dynamicplaylistId = $dynamicplaylist->{'id'};
	my @trackIDs = ();
	my %tracksCompleteInfo = ();

	if (!$offset && $dynamicplaylistId eq 'myplugin_byartist') {
		my $seedContributorId = $parameters->{1}->{'value'};
		my $seedArtist = Slim::Schema->find('Contributor', $seedContributorId);

		# ... use $seedArtist to get a track via your own logic ...
		my $nextTrack = pickRelatedTrack($seedArtist);

		if ($nextTrack) {
			my $id = $nextTrack->id;
			push @trackIDs, $id;
			$tracksCompleteInfo{$id}{'primary_artist'} = $nextTrack->primary_artist if $nextTrack->primary_artist;
		}
	}

	return \@trackIDs, \%tracksCompleteInfo;
}



Summary checklist

  • Your plugin is enabled and implements getDynamicPlaylists and getNextDynamicPlaylistTracks at package level.
  • Every playlist ID you return is unique and prefixed with something specific to your plugin.
  • getDynamicPlaylists returns a hashref of hashrefs with at least id and name.
  • getNextDynamicPlaylistTracks returns (\@trackIDs, \%tracksCompleteInfo), where @trackIDs holds numeric Slim::Schema::Track IDs (or the scalar 'error' on failure).
  • Any user-selectable input is declared via parameters in getDynamicPlaylists and read back via $parameters in getNextDynamicPlaylistTracks.