Extending iPeng using the iPeng CLI command
What does this mean?
iPeng now features the “ipeng” CLI command that can be used to extend iPeng’s functionality. Right now, it is supported by the “NowPlaying” screen to add plugins to the “left” page and can be used to configure the shortcut button on the bottom of the screen. And most important: The same mechanism will be used by the native iPeng application for iPhone and iPod touch so any plugin supporting this for the web skin will also appear on the native app. The native app will also use this to generate extended browse pages.
Using the iPeng Command
Last modified on 2008-04-04 05:29:49 GMT. 0 comments. Top.
There are two ways to use the iPeng command.
XML File Configuration
The simple one is to just generate an XML file for the command.
You can add your own customized commands by creating a XML file that follows the specification described in the XML Interface Data Specification below. The XML file needs to have the extension .ipeng.xml and must be stored in the directory you have specified in the iPeng section of SqueezeCenter Settings.
Plugin Registration
The alternative way is to register the plugin directly
A plugin can register one or several commands, the attributes specified by the plugin is the same as those described in the XML Interface Data Specification section below. There are three different functions that can be used by a plugin when registering commands:
- Plugins::iPeng::Plugin::addSubSection
Registers a new sub section, this needs to be used if you like to set a name or sorting order of the plugin specific sub sections you are going to use when registering commands. If called twice for the same sub section, this function will update the existing sub section with new values. - Plugins::iPeng::Plugin::addCommand
Registers a single command in the specificed section and sub section. If called twice for the same command this function will update the existing command with new values. - Plugins::iPeng::Plugin::deleteCommand
Removes a previously registered command from the specified section and sub section.
A typical plugin would register its commands in the initPlugin function by calling addSubSection once for each sub section used by the plugin and addCommand once for each command that should be registered. Typically there is no reason to call the deleteCommand, the reason it exists is if a plugin likes to have dynamic commands that disapears due to some configuration or state change in the plugin, you don’t need to call deleteCommand when shutting down the plugin.
The following code shows an example how you register a new sub section and add command to it:
# Only perform the registration if the iPeng plugin is installed
if(UNIVERSAL::can("Plugins::iPeng::Plugin","addCommand") && UNIVERSAL::can("Plugins::iPeng::Plugin","addSubSection")) {
# Prepare sub section registration data
my %subsection = (
'weight' => 10,
'name' => 'CB Info',
);
eval { Plugins::iPeng::Plugin::addSubSection('nowplaying','custombrowse',\%subsection) };
if ($@) {
$log->warn("Failed to register iPeng command:\n$@");
}
# Prepare command registration data
my %command = (
'weight' => 10,
'name' => 'Song Info',
'icon' => 'html/images/infobutton.png',
'url' => 'plugins/CustomBrowse/custombrowse_contextheader.html?hierarchy=group_track&contexttype=track',
'type' => 'content',
'parameters' => {
'id' => 'contextid',
'title' => 'contextname',
'player' => 'player',
},
);
# Register the new
eval { Plugins::iPeng::Plugin::addCommand('nowplaying','custombrowse','custombrowse_songinfo',\%command) };
if ($@) {
# Something went wrong
$log->warn("Failed to register iPeng command:\n$@");
}
}
Command Usage
The use of the ipeng command is not limited to iPeng itself. As long as the plugin is installed, any application can use it by calling
ipeng commands <section>
through CLI or JSON/RPC interfaces (please refer to the SqueezeCenter documentation if you don’t know what that is).
As a result, iPeng will deliver an array of interface data as described in the XML specification
<ADD MORE SPECIFICS>
XML Interface Data Specification
Last modified on 2008-08-02 02:30:21 GMT. 0 comments. Top.
The data being handed to iPeng through the iPeng command is specified as follows:
—
<!-- An iPeng XML file / parameter description using DTD format -->
<!-- the content of the config file is contained in a <configuration> element -->
<!ELEMENT configuration ( section* )>
<!-- The configuration is made up of sections which in turn are entirely made up of one or more subsections --> <!ELEMENT section ( subsection* )>
<!-- Each section has an "id" attribute determining the type of content it contains, as in <section id = "nowplaying">. This attribute is used by iPeng to select the content valid for a certain page. currently defined values are: browse - for browse pages nowplaying - for the NowPlaying page toolbar - for toolbar icons --> <!ATTLIST section id ( "browse"|“nowplaying"|"toolbar"|#PCDATA )> <!-- A <subsection id="..."> represents a row on the "NowPlaying" screen or a Browse screen or a context on the Toolbar. A subsection is not a command, so no action is assigned to a subsection. A Subsection may have a name and/or icon, these will be shown to the left of the <command> content and will not be selectable. <name> and <icon> will be ignored for the toolbar. A subsection on the toolbar represents a context parameter and can be used to determine, when a command is being shown. There are the following predefined contexts: * - default items valid in all contexts. Context specific commands take precedence default - a context that will be used when no context parameter is being set, e.g. when a plugin or page is not aware of the toolbar context functionality. home - the home screen browse - iPengs standard browse screens playlists - playlist browse screen xmlbrowse - the xmlbrowse context, typically, this is being used for internet radios A plugin may define it's own contexts. Subsections are sorted by the <weight> parameter. A subsection is made up of one or more commands --> <!ELEMENT subsection ( weight?, <!-- --> name?, <!-- --> icon?, <!-- --> command* )> <!-- Each subsection has an arbitrary id that is being used to group commands together. If more than one plugin registers a subsection under the same name, these subsections will be merged and interpreted like one subsection. <ATTLIST subsection id ( #PCDATA )> <!-- A subsection is made up of one or more commands. Commands represent an element that can be selected and will result in an action. They result is dependent on the type and the section. Section "nowplaying": <type>: "command" - a command that will be executed either through the CLI or by calling an url - through ajaxRequest. "content" - a command that will be executed through ajaxUpdate; the result will be shown in - the "plugin content" page on the NowPlaying screen. Section "browse": <type> "command" - a command that will be executed through "ajaxRequest" or the CLI. "content" - a url of a new page that will be loaded or a CLI command that will return - XML content to be rendered in a browse page. Format tbd. Section "toolbar": <type> has no meaning and is ignored. --> <!ELEMENT command ( weight?, <!-- --> position?, <!-- --> description?, <!-- --> requireplugins?, <!-- --> defaultenabled?, <!-- --> type, <!-- --> name?, namestring? <!-- --> icon?, selectedicon?, <!-- --> html?, <!-- --> width?, height?, <!-- --> parameters*, <!-- --> url?|cli? )> !ATTLIST command id ( #PCDATA )> <!-- an id that will be used to identify the command --> <!ELEMENT description ( #PCDATA )> <!-- a description being used to identify the command on the settings page --> <!ELEMENT requireplugins ( #PCDATA )> <!-- names of plugins required to enable the command. --> <!-- If the plugin is not present, the command will not be shown --> <!ELEMENT defaultenabled ( "0" | "1")> <!-- if set to "0" the command will be disabled by default --> <!ELEMENT weight ( #PCDATA )> <!-- a numeric value being used to sort the commands --> <!ELEMENT position ( #PCDATA )> <!-- a numeric value defining the position on the toolbar or in the list --> <!-- on the NowPlaying screen. Has to be 1-5 for Toolbars --> <!ELEMENT type ( "command"|"content"|#PCDATA )> <!-- the "type" of the command as descibed above --> <!ELEMENT name ( #PCDATA )> <!-- an optional string shown with the command --> <!ELEMENT namestring ( #PCDATA )> <!-- Identifier of a localized string that will be run through the --> <!-- string filter when displayed. The translated string will be returned --> <!-- in the "name" parameter as well --> <!ELEMENT icon ( #PCDATA )> <!-- an url of a bitmap to be shown with the command. --> <!-- For the toolbar a 40x30 icon is expected --> <!ELEMENT selectedicon ( #PCDATA )> <!-- toolbar only. The icon to be used when the respective page is active --> <!ELEMENT html ( #PCDATA )> <!-- an optional HTML string to be shown with the command --> <!ELEMENT width ( #PCDATA )> <!-- optional: the width of the selectable area. If name --> <!-- or html is present this is the width of the overall area --> <!-- if only an icon is given it's the width of the image --> <!ELEMENT height ( #PCDATA )> <!-- the height of the command area AND the height of an icon --> <!ELEMENT url ( #PCDATA )> <!-- the url to be called. May include a Hash for positioning (#...)--> <!ELEMENT cli ( #PCDATA )> <!-- a CLI command to be executed. only one of <cli> OR <url> --> <!-- may be used. If both are present, url takes precedence. --> <!-- With each commands a set of parameters can be specified that will be filled by iPeng and handed to the command. Generally the tag specified identifies the parameter while the value of the tag specifies the name under which a parameter will be added. So "<album_id>record</album_id>" will result in the album ID being passed to the command as a "record" parameter, as in "record=xxxx". A special Parameter is "other" which gives an additional parameter string that will be passed "as is". There may be more than one "other" parameter. Allowed parameters are: <other> - any string, can also be other0, other1,... <album> - the current album name <album_id> - the current album id <artist> - the current artist name <artist_id> - the current artist id <genre> - the current genre name <genre_id> - the current genre id <title> - the current track title <id> - the current track id <index> - the index of the current track in the playlist <playlist> - the name of the current playlist, currently not supported <playlist_id> - the id of the current playlist, currently not supported <player> - the id of the active player --> <!ELEMENT parameters ( other|album|album_id|artist|artist_id|genre|genre_id| <!-- --> title|id|index|playlist|playlist_id|player )>
<!ELEMENT other ( #PCDATA )> <!ELEMENT album ( #PCDATA )> <!ELEMENT album_id ( #PCDATA )> <!ELEMENT artist ( #PCDATA )> <!ELEMENT artist_id ( #PCDATA )> <!ELEMENT genre ( #PCDATA )> <!ELEMENT genre_id ( #PCDATA )>
<!ELEMENT title ( #PCDATA )> <!ELEMENT id ( #PCDATA )> <!ELEMENT index ( #PCDATA )> <!ELEMENT playlist ( #PCDATA )> <!ELEMENT playlist_id ( #PCDATA )> <!ELEMENT player ( #PCDATA )>
—
End of file
