<?sphp $this->text('pagetitle') ?>
 
Home of the Squeezebox™ & Transporter® network music players.

SqueezeCenter 7 Plugins

From SqueezeboxWiki

Jump to: navigation, search

Note: this is not an official document.

Contents

SqueezeCenter 7.0 nightly releases

Nightly releases of SqueezeCenter 7.0 are available at http://www.slimdevices.com/downloads/nightly/latest/7.0/

File layout and packaging

Given the relative complexity of the packaging scheme for SqueezeCenter 7's plugins, developers may wish to use the PluginBuilder tool in the tools directory to facilitate building/testing.

The README file for PluginBuilder has more information about the new layout for plugin files. PluginBuilder creates a distributable version of your plugin - it does not need to be used during development.

(OBSOLETE: Additional information about changes in SlimServer are here: SlimServer7Spec )

Logging / debugging

Note that the msg() / d_FOO logging API is going away, replaced by log4perl. See the wiki Debugging page for more info. A general tutorial on log4perl is available here: http://www.perl.com/pub/a/2002/09/11/log4perl.html

Function Changes

  • initPlugin() $class is inserted as the new first argument.
  • setMode() if the plugin has called SUPER::initPlugin, then $class must be inserted as the new first argument, before $client.
  • the hash based display api introduced in 6.5 should now be used as support for the previous api is depreciated. Specifically, lines functions should return a hash and $client->symbols should be used in place of Slim::Display::Display::symbol. [See the display api documentation in technical information section.]
  • screensavers should register themselves by calling Slim::Buttons::Common::addSaver() within their initPlugin() code
  • $client->param() has been deprecated. Screensavers should use code like $client->modeParam('modeUpdateInterval',1); to specify update frequency – and it's probably good to run SqueezeCenter from a command prompt and watch for other messages about deprecated functions
  • The webPages function must now manually call Slim::Web::HTTP::addPageFunction to register its page handlers and it also needs to call Slim::Web::Pages->addPageLinks("plugins", { 'PLUGIN_MYPLUGIN' => 'plugins/MyPlugin/index.html' }); if you like it to show up as an entry below the "Extras" section on the home page.
  • Slim::Utils::Prefs has been totally changed, see "Preferences API" section below for more details.
  • The setupGroup function is no longer used, see "General observations" below for more details.
  • Debug logging API has changed see, see separate Debugging for more information regarding this.

Preferences API

The preference API has been changed, the result is that you will need to create/lookup a preference context, by making a call like this:

use Slim::Utils::Prefs;
my $prefs = preferences('plugin.myplugin');

After this you can replace existing calls as follows:

my $property1 = Slim::Utils::Prefs::get('myplugin_property1');

Can be replaced with:

my $property1 = $prefs->get('property1');

And

Slim::Utils::Prefs::set('myplugin_property1','nicevalue');

Can be replaced with:

$prefs->set('property1','nicevalue');

And

my $clientProperty2 = $client->prefGet('myplugin_property2');

Can be replaced with:

$prefs->client($client)->get('property2');

And

$client->prefSet('myplugin_property2','niceClientValue);

Can be replaced with:

$prefs->client($client)->set('property2','niceClientValue);

If you have been using array properties using getArray, setArray and push functions in Slim::Utils::Prefs, there are a bit more changes. To retrieve a reference to an array property you can now do:

my $arrayProperty1 = $prefs->get('property3');

The $arrayProperty1 can now be used as any other array reference, so you can modify its content using standard perl functions and then to store the result you do:

$prefs->set('property3',$arrayProperty1);

Hash properties can be handled in the same way as array properties, you will just get a hash reference instead of an array refefence.

As shown in the sample it now works to have plugin properties without using the plugin name as a prefix in the property name. So you can choose to remove the prefix from all properties or keep it, both ways will work.

If you need a standard SqueezeCenter server setting, you just look up the server preferences context with:

my $serverPrefs = preferences('server');

General observations

(Taken from http://forums.slimdevices.com/showpost.php?p=161516&postcount=48)

Instructions on how to update plugins to 7.0 would help greatly - and I noticed whilst doing this that the error log provides feedback to say what's wrong with the plugin which is lovely. Anyhow... for LazySearch2 the following is necessary (as an example - other plugins may be similar in their changes - and some of this is restating things mentioned in the thread) :

Plugins can no longer be bare perl .pm files. They must be in a sub-directory. Create a sub-directory with the correct name for the plugin - in this case 'LazySearch2'. Place the plugin source inside this directory as 'Plugin.pm'.

Because of this move, the plugin's package will no longer be correct. This means that all references to 'Plugins::LazySearch2' will need to be replaced by 'Plugins::LazySearch2::Plugin'. A search and replace will do here. If the plugin tries to manipulate the contents of other plugins then they, too, will need to be updated. Obviously it's not a wonderful idea to mess with someone else's innards like that, but you knew that when you wrote the code.

Strings have changed. They are no longer stored in the plugin source, but in a 'strings.txt' in the directory. Most plugins (LazySearch2 included) just return a big string. If the plugin does something more dynamic than this then it may be necessary to be more clever. However, for LazySearch2, locate the 'sub strings' and see it is returning a single string containing all the internationalised string translations. The contents of this string should be placed in 'strings.txt'. LazySearch2 has a few comments in the source attributing the translations to people. Obviously we don't want to lose this information, so these can be copied to the 'strings.txt' as well. Lines preceded by a '#' character are comments (same as perl) so this is easy to transfer. When this is done, remove the 'sub strings' function and all the comments relating to it.

(at this point the plugin will function, but may not be completely usable)

Settings have changed. Plugins are no longer organised so that all the settings are on a single 'Plugins' configuration. Each plugin has its own page. This means that the 'sub setupGroup' function which was previously used to return the details of how to construct the page is no longer used.

(at this point I'm not entirely clear and haven't managed to make things work, so I'm going to explain what I can see and how I think it works)

A new source file should be used to handle the settings - this is called 'Settings.pm', and should be based on the Slim::Web::Settings package ('use base qw(Slim::Web::Settings)'). This package provides most of the work necessary to configure the plugin. 3 functions must be provided in Settings file - name, page and prefs.

The name is the name of the plugin and should be a string (eg "sub name { return 'PLUGIN_LAZYSEARCH2'; }" or "sub name { return Slim::Web::HTTP::protectName('PLUGIN_LAZYSEARCH2'); }" ).

The page should be the path in the SqueezeCenter HTML hierarchy of the page to be used as the template (eg "sub page { return 'plugins/LazySearch2/settings/basic.html';" }' or "sub page { return Slim::Web::HTTP::protectURI('plugins/LazySearch2/settings/basic.html'); }")

To protect against CSRF attacks tricking users' web browsers into making changes to their settings without the users' approval, developers should use the new protect* routines in Slim::Web::HTTP. Generally, developers should

  • use Slim::Web::HTTP::protectURI() to protect the page URI
  • use Slim::Web::HTTP::protectName() to protect the page's "name" string token
  • embed the following on any web page that doesn't use the standard settings footer (which has this code): <input type="hidden" name="pageAntiCSRFToken" value="[% pageAntiCSRFToken %]">

The prefs returns a list of the preference variables which are required by this plugin (eg 'sub prefs { return qw(plugin-lazysearch2-minlength-artist plugin-lazysearch2-minlength-album ...); }' (many plugin preferences omitted!) ). It is recommended that these be prefixed by 'plugin-<name>' so ensure that there are no clashes.

In the old API, the hash for the plugin variables allowed validation of the values specified and the specification of a message to display when the value was changed. My quick examination of the source doesn't tell me how to do this too clearly. It looks like there's a 'handler' function which takes a list of the values specifid and processes them; Someone else probably ought to provide some explanation of this, because I'm having trouble following what it must do and how it does it.

The actual HTML files should be held within a directory within the plugin directory. This has the somewhat longwinded, but obvious form of 'HTML/<EN>plugins<pluginname>settings<html file>', where <EN> can be replaced by skin names (if you want skin specific templates - EN will do in most cases), <pluginname> is the name of the plugin, and <html file> is the actual settings file to use. Other non-settings files would, presumably, live alongside the 'settings' directory. Compare this structure to the top level HTML resource directory and it should be observed that it follows the same pattern. The regular template operations can be used within the HTML.

It might be useful for the Plugin manager to either log a warning if the plugin contains a 'setupGroup' function, as this no longer functions, OR to delegate its processing to another handler which can do the page generation in the old style.

In investigating, the RadioTime plugin seems to have a very simple interface to allow it to be configured and would probably be a nice starting point for anyone trying to copy that behaviour.

A Detailed Example

Based on the above description I have updated my LazySearch plugin to support 7.0a1 (actually revision 11782 of SqueezeCenter 7.0a1).

The changes I made to the main plugin Perl module (besides renaming it to Plugin.pm and putting it in its own folder) can be seen in the following diff:

http://www.hickinbottom.com/lazysearch/changeset?old_path=trunk%2FLazySearch2.pm&old=228&new_path=trunk%2FPlugin.pm&new=265

The other changes I've made (such as externalising the strings, creating the HTML templates for the plugin settings and the general plugin folder layout), can be seen here:

http://www.hickinbottom.com/lazysearch/browser/trunk?rev=265

Protecting CLI commands from Web abuse

All CLI commands can be called by requesting URLS like http://localhost:9000/status.html?p0=rescan In order to prevent CSRF attacks from being used to trick users' web browsers into calling commands without their approval or knowledge, plugins that register new commands with addDispatch() should use Slim::Web::HTTP::protectCommand() to prevent CSRF attacks. For instance, to protect the "rescan" command against CSRF attacks, the core SqueezeCenter code uses a call like "Slim::Web::HTTP::protectCommand('rescan');". Generally CSRF protection is only needed for commands that are resource intensive or make changes.

Further Requirements

/This information is not necessarily correct! It's the stuff that I (Max) was able to find out whilst converting a plugin to work with SqueezeCenter 7./

There must be an install.xml file in your plugin's base directory or the plugin will not load. To get started, this can be copied from one of the plugins in SqueezeCenter's Slim/Plugin/ folder. Remove the <id> element (which is generated by PluginBuilder tool) and change other elements appropriately. The name and description elements reference tokens defined in your strings.txt file.

A plugin should declare its parent class to be Slim::Plugin::Base (use base qw(Slim::Plugin::Base)). Within initPlugin, the plugin should call $class->SUPER::initPlugin().

Hello World Sample/Tutorial Plugin

Here's a zip file that contains a plugin called HelloWorld. If you unzip it in squeezecenter/server/Plugins and then play with it via the squeezebox and web interface you'll see what it does. Then look at the code and/or run squeezecenter with logging level set to debug and see the tons of messages it displays and/or add your own logging messages so you can follow along with what's happening.

The zip file can be found here: http://www.jesslex.com/slim/HelloWorld.zip.

I don't claim to be the best Perl or SqueezeCenter programmer, but the plugin does work and it does demonstrate SC7 stuff as well as some of the Input Modes stuff.