PDA

View Full Version : New plugin hooks for slimserver 7.0 ?



Dan Sully
2007-03-06, 11:39
* erland shaped the electrons to say...

>I have some ideas of new plugin hooks or access functions I would like
>to see in the SlimServer 7.0 release to improve the integration between
>plugins and standard SlimServer.
>
>Is it time to list these ideas or provide patches for them, or would it
>be better wait a bit more until more work has been done on the new
>plugin architecture ?

Now would be the time. Patches welcome.

-D
--
Adobe Photoshop - When you want the truth. Real bad.

erland
2007-03-06, 11:40
I have some ideas of new plugin hooks or access functions I would like to see in the SlimServer 7.0 release to improve the integration between plugins and standard SlimServer.

Is it time to list these ideas or provide patches for them, or would it be better wait a bit more until more work has been done on the new plugin architecture ?

erland
2007-03-06, 12:38
* erland shaped the electrons to say...

>I have some ideas of new plugin hooks or access functions I would like to see in the SlimServer 7.0 release to improve the integration between plugins and standard SlimServer.
>
>Is it time to list these ideas or provide patches for them, or would it be better wait a bit more until more work has been done on the new plugin architecture ?

Now would be the time. Patches welcome.

Ok, I'll start with listing the things I am thinking of so they can be discarded right away if they don't fit the architecture so patches wouldn't be accepted anyway.

1. Improvement of mixer API
See http://bugs.slimdevices.com/show_bug.cgi?id=4451

2. Possibility to add custom elements to the track details menu shown when pushing the right button on a track in either the "now playing" menu or one of the browse menus.

3. Possibility to add custom elements to the "Song Info" page showing track details in the web interface when the user has clicked on the track.

4. Possibility to dynamically hide menus in the web interface. Today a menu in the web interface added with Slim::Web::Pages->addPageLinks results in a menu that is always shown. I would like to be able to provide a callback function with the addPageLinks call, the callback would be called whenever the web page menus shall be rendered and if the callback returned false for a menu item the menu wouldn't be shown. The purpose of this is making it possible to have menus that is only shown when a specific player(SqueezeBox) is selected in the web interface. If would also be possible to use with the Multi Library plugin to hide menus base on which library that is active.

5. Possibility to dynamically hide menus in the player(SqueezeBox) interface.
This is the same problem as point 4 above but in the player interface. The method called here would be Slim::Buttons::Home::addSubMenu instead. It's a bit less urgent in the player interface since it is already today possible for the user to configure manually to hide/show certain menus items.

6. Possibility to hook in a call to a plugin at the end of the scanning process. Today you can hook in by listening on the "rescan done" event, but the problem is that this code is executed in the SlimServer process instead of the scanning process. What I would like is a way to execute plugin functions at the end of the scanning from inside the scanning process. The reason this is important is that if the functions were executed in the scanning process you would still be able to use SlimServer even if the functions take some time to execute, when they are executed in the SlimServer process they have to be divided into small parts using the Scheduler class.

7. Possibility for a plugin to use the Slim::Hardware::IR::addModeDefaultMapping method to register actions even though some other plugin has registered actions on the same mode. As an example, today only one plugin can call addModeDefaultMapping with the 'playlist' as mode, when the call from a second plugin comes with 'playlist' mode it will be ignored. It would be a good idea to allow multiple calls to addModeDefaultMapping as long as they are registering different buttons. One problem today is that TrackStat registers the 0-9 buttons while the Playlist Manager plugin try to register actions on the Add button, one of them will always fail today.


If any of these won't be accepted or if you see a better solution I would appreciate some indication on this before I start making patches. If there are some of the points you feel it would be better if one of the existing SlimServer developers implemented, I would also appreciate some indication on that.

andyg
2007-03-06, 12:38
Here's some new hooks I plan on merging from SN very soon. These are all for protocol handlers.

onCommand - async code that runs when a user plays or adds something, but before playback begins.

onJump - async code that happens when a user skips a track, but before the next track begins.

onDecoderUnderrun - async code that runs during the normal transition between 2 tracks.

onUnderrun - async code that runs when the buffer runs out, but before playback stops.

showBuffering - flag to indicate whether or not to show the connecting/buffering progress info on the start of this track. I use this for Rhapsody and Pandora to hide the buffering status between normal track advances.

trackInfo - allows plugins to set a custom mode for the Now Playing menu when you press right. This is used to build the Rhapsody menu using XMLBrowser for example.

Triode
2007-03-06, 12:58
On a related topic... Worth saying I've added a hook recently for XMLbrowser
to be used with custom page parsers.

This allows plugins like Alien which parse remote html pages to build a list
of content to reuse the server's xmlbrowser for the web/player/cli interface
and hence the plugin only needs to implement a parser to turn the remote
html into the hash understood by xmlbrowser. My aim was to allow alien to
integrate with the new favorites achitecture, but it would be useful for
anyone wanting to parse remote content and display it. Not thought of all
the applications, but a forum reader shouldn't be too hard for instance...

Adrian

----- Original Message -----
From: "andyg" <andyg.2n1h0o1173210002 (AT) no-mx (DOT) forums.slimdevices.com>
To: <developers (AT) lists (DOT) slimdevices.com>
Sent: Tuesday, March 06, 2007 7:38 PM
Subject: Re: [Developers] New plugin hooks for slimserver 7.0 ?


>
> Here's some new hooks I plan on merging from SN very soon. These are
> all for protocol handlers.

mherger
2007-03-07, 02:42
> trackInfo - allows plugins to set a custom mode for the Now Playing
> menu when you press right. This is used to build the Rhapsody menu
> using XMLBrowser for example.

Yes, please!

--

Michael

-----------------------------------------------------------------
http://www.herger.net/SlimCD - your SlimServer on a CD
http://www.herger.net/slim - AlbumReview, Biography, MusicInfoSCR

peterw
2007-03-07, 07:28
7. Possibility for a plugin to use the Slim::Hardware::IR::addModeDefaultMapping method to register actions even though some other plugin has registered actions on the same mode. As an example, today only one plugin can call addModeDefaultMapping with the 'playlist' as mode, when the call from a second plugin comes with 'playlist' mode it will be ignored. It would be a good idea to allow multiple calls to addModeDefaultMapping as long as they are registering different buttons. One problem today is that TrackStat registers the 0-9 buttons while the Playlist Manager plugin try to register actions on the Add button, one of them will always fail today.

If any of these won't be accepted or if you see a better solution I would appreciate some indication on this before I start making patches. If there are some of the points you feel it would be better if one of the existing SlimServer developers implemented, I would also appreciate some indication on that.

This sounds nice, but I don't think there's a bigger problem with button mappings that would be more worthy of your time, especially since Plugins currently can effectively register functions in modes by trapping IR commands.

A more important problem than allowing plugins to register buttons in existing mappings is handling conflict between plugins. Both TrackStat and SaverSwitcher want to use the 0-9 buttons when a song is playing. Both you and I have figured out how to do that (I'm wrapping IR commands with addDispatch). It's not the nicest API for getting the job done (and your suggestion would help), but I would rather see things like
7b. a way for users to configure which plugin handles buttons first
7c. a way for plugins to cooperate on points of contention

Currently the addDispatch setup allows multiple plugins to wrap an IR command to look for button codes that do not have mappings in the current mode. When multiple plugins use this, the server ends up with multiple layers of code wrapping, like an onion. Whatever code runs addDispatch last is the first to take a stab at handling the button press, and can prevent other plugins from seeing the IR event. This is the problem you saw with SaverSwitcher preventing TrackStat from seeing buttons, right?

Since I imagine addDispatch is normally called in plugins' initPlugin() routines, the onion is constructed in the order that Slimserver initializes plugins. Users have no way of controlling that order right now.

At the simplest level, if the web UI had an interface much like the Up/Down interface for re-ordering lists (playlist items, Favorites, etc.) that would allow them to specify the order in which known plugins are loaded/initialized, then users could have more control over the order in which the onion is built.

Better would be
a. allowing each mapping mode to map a button to an ordered list of functions (start with internal/default, then add mappings as requested by plugins)

playlist = {
'0' => [ \&Plugins::TrackStat::someMethod,
\&Plugins::SaverSwitcher::someMethod,
\&Slim::Something::someMethod ]
}

b. have a "fallthrough" logic so that if one of the ordered mappings returned undef, the next would be executed (unlike the addDispatch original function chaining model, Slimserver would handle the chaining)
c. having a web interface that allows users to change the order of the mappings for individual buttons in individual modes. This begs for an AJAX approach -- a master pulldown for the mode, a second pulldown for the button name (dynamically populated), and then an area with entries like the playlist UI, with up/down (and maybe even delete/disable) options for each function mapped to that button.

An alternative to c. that gives less control to the user, but offers a cleaner UI, would simply have a pulldown for the mode and a list of plugin names (plugins that registered their own mappings for that mode), and would allow controlling that order. In this alternative, instead of each button mapping to an array of coderef, each mode name would map to an array of button mappings,

playlist = {
'playlist.TrackStat' = {
'0' => \&Plugins::TrackStat::someMethod,
},
'playlist.SaverSwitcher' = {
'0' => \&Plugins::SaverSwitcher::someMethod ]
},
'playlist.internal' = {
'0' => \&Slim::Something::someMethod,
}
}

The fallthrough logic of b. would still apply -- if a mapping did not have an entry for a button, or if the code returned undef, Slimserver would look at the next mapping and execute its code.

For both these suggestions of "array mappings", the API used by a plugin to register new mappings should either always put the plugin's mapping first (ala addDispatch's onion) or allow the plugin to request some sort of ordering info -- with the restriction that Slimserver will rearrange the order to follow the user's request once all plugins have been loaded. Among the arguments passed to the API should be a string to identify the mapping and a string token for any UI display. This would allow the simpler alternative web UI to display strings like "Slimserver (internal)", "SaverSwitcher - manual screensaver selection", "TrackStat - rate the current song", etc.

-Peter

hickinbottoms
2007-03-07, 07:44
I'd definitely vote for the following:

> 1. Improvement of mixer API
> See http://bugs.slimdevices.com/show_bug.cgi?id=4451
>
(I'd better do, since I raised it!)
> 6. Possibility to hook in a call to a plugin at the end of the scanning
> process. Today you can hook in by listening on the "rescan done" event,
> but the problem is that this code is executed in the SlimServer process
> instead of the scanning process. What I would like is a way to execute
> plugin functions at the end of the scanning from inside the scanning
> process. The reason this is important is that if the functions were
> executed in the scanning process you would still be able to use
> SlimServer even if the functions take some time to execute, when they
> are executed in the SlimServer process they have to be divided into
> small parts using the Scheduler class.
>
Agreed, although I'd also like the flexibility to have the code run in
either the main SlimServer or the scanner process (perhaps two hooks, in
that case). Additionally, I think the current hook is only called in
some specific circumstances and misses others (tracks added through
MusicIP database sync and browsing into new music folders spring to mind).

I think the latter is a clear enough enhancement that it could go into
Bugzilla right away and be a candidate for voting and progression (plus,
I can subscribe to it to track the progress). I'd be happy to do that,
Erland, if you don't want to.

Stuart

erland
2007-03-07, 10:30
A more important problem than allowing plugins to register buttons in existing mappings is handling conflict between plugins. Both TrackStat and SaverSwitcher want to use the 0-9 buttons when a song is playing. Both you and I have figured out how to do that (I'm wrapping IR commands with addDispatch). It's not the nicest API for getting the job done (and your suggestion would help)
I actually feel that allowing plugins to register free buttons in existing mappings is more important, because today only ONE plugin can register a button in the "Now Playing" screen and thats a real limitation.

However, the collision handling is also a good idea, just a bit more work. I would imagine that it might require a lot of work since it affects both configuration interface and probably also user interface beside the logic itself. But if you register a feature request on it, it would get my vote.

I would suggest a solution where colliding buttons would result in a menu where the user can choose which action to execute. This way it would be possible for two plugins to register the same button and the user can choose which action to perform. Pretty much the same way as the mixer API for the "hold play" action works today.

Some sort of prioritized solution where the user can adjust the priority might be good, but I would suggest that we then skip the user interface to limit the amount of work and just put the configuration in some configuration file which the user can edit. Maybe in a similar way as the user can configure custom keys for a mode already today.

erland
2007-03-07, 10:32
Agreed, although I'd also like the flexibility to have the code run in either the main SlimServer or the scanner process (perhaps two hooks, in that case). Additionally, I think the current hook is only called in
some specific circumstances and misses others (tracks added through MusicIP database sync and browsing into new music folders spring to mind).

I think the latter is a clear enough enhancement that it could go into Bugzilla right away and be a candidate for voting and progression (plus, I can subscribe to it to track the progress). I'd be happy to do that, Erland, if you don't want to.
Feel free to register the feature request in Bugzilla and provide patches to it also if you like that.

hickinbottoms
2007-03-07, 10:37
Will do. I'll take a look re patching as well.

Stuart

erland wrote:
> Stuart Hickinbottom;186224 Wrote:
>
>> Agreed, although I'd also like the flexibility to have the code run in
>> either the main SlimServer or the scanner process (perhaps two hooks,
>> in that case). Additionally, I think the current hook is only called
>> in
>> some specific circumstances and misses others (tracks added through
>> MusicIP database sync and browsing into new music folders spring to
>> mind).
>>
>> I think the latter is a clear enough enhancement that it could go into
>> Bugzilla right away and be a candidate for voting and progression
>> (plus, I can subscribe to it to track the progress). I'd be happy to do
>> that, Erland, if you don't want to.
>>
> Feel free to register the feature request in Bugzilla and provide
> patches to it also if you like that.
>
>
>

hickinbottoms
2007-03-07, 13:46
As a start, I've raised the enhancement as bug #4812.

Stuart

Stuart Hickinbottom wrote:
> Will do. I'll take a look re patching as well.
>
> Stuart
>
> erland wrote:
>
>> Stuart Hickinbottom;186224 Wrote:
>>
>>
>>> Agreed, although I'd also like the flexibility to have the code run in
>>> either the main SlimServer or the scanner process (perhaps two hooks,
>>> in that case). Additionally, I think the current hook is only called
>>> in
>>> some specific circumstances and misses others (tracks added through
>>> MusicIP database sync and browsing into new music folders spring to
>>> mind).
>>>
>>> I think the latter is a clear enough enhancement that it could go into
>>> Bugzilla right away and be a candidate for voting and progression
>>> (plus, I can subscribe to it to track the progress). I'd be happy to do
>>> that, Erland, if you don't want to.
>>>
>>>
>> Feel free to register the feature request in Bugzilla and provide
>> patches to it also if you like that.
>>
>>
>>
>>
>

Philip Meyer
2007-03-07, 14:06
It would be nice if multiple plugins could register the same button action for the same mode. SlimServer could hold an array of actions for each button in each mode.

When the button is pressed, Slimserver could display a menu for the user to select the desired action.

Thereby, when two plugins register actions for the same key, such as pressing "1.hold" in "now playing", a menu would pop up giving options like "Rate Track *" and "Play Bookmark 1".

Maybe some optional params could be specified, such as:
- whether the new button mapping overrides the slimserver default, or is an extra option to the default action.
- the name of the menu option.

If only one action is specified (and it overrides the slimserver default action), there would be no need for the menu selection.

Phil

peterw
2007-03-08, 19:22
It might be nice for one of the args when adding a mapping to be a coderef for some code that would return true or false depending on whether the plugin would actually want to take action. Two examples:
1) my BottleRocket plugin maps digits to X-10 devices (currently only when displaying the BottleRocket menus). If there's only one X-10 device, then BottleRocket would not have any interest in the "2" button. Before presenting options to the user, Slimserver could ask each plugin if they were at all interested in the "2" key I just pressed.
2) my SaverSwitcher plugin allows users to toggle button control on or off. Instead of trying to register and un-register button mappings as users toggle preferences, Slimserver could call a SaverSwitcher method to learn if SaverSwitcher cared about number buttons.

More thoughts:

1) So the UI would look something like

User presses "1"
Slimserver realizes there are multiple mappings for this button in this mode.
Screen displays "Rate song *" (from TrackStat)
User presses "Down"
Screen displays "Use Date and Time saver" (SaverSwitcher)
User presses "Down"
Screen displays "Power on Den Lights" (from BottleRocket: oops! too far!)
User presses "Up"
Screen displays "Use Date and Time saver"
User presses "Right"
Slimserver executes SaverSwitcher code

Each of these 1, Up, and Down presses should trigger IR commands (as should Right), but those IR commands would not trigger normal "button" commands (or we'd have recursion problems with the Up/Down/Right buttons). Only one "button" command would fire, the SaverSwitcher code, after the user pressed Right to select that last choice.

2) Slimserver should still allow users to control the order so that TrackStat always preceded SaverSwitcher or vice-versa.

3) I've read some complaints on the forums about the modal buton behavior. This sort of UI, while adding at least one button press to commands for users who load extra plugins, might assuage some of the modal behavior critics.

4) For the modal critics, we might even want an option for adding a mapping to indicate whether Slimserver should always confirm the button presses.

-Peter

erland
2007-03-08, 21:52
It might be nice for one of the args when adding a mapping to be a coderef for some code that would return true or false depending on whether the plugin would actually want to take action. Good idea


1) So the UI would look something like

User presses "1"
Slimserver realizes there are multiple mappings for this button in this mode.
Screen displays "Rate song *" (from TrackStat)
User presses "Down"
Screen displays "Use Date and Time saver" (SaverSwitcher)
User presses "Down"
Screen displays "Power on Den Lights" (from BottleRocket: oops! too far!)
User presses "Up"
Screen displays "Use Date and Time saver"
User presses "Right"
Slimserver executes SaverSwitcher code

Each of these 1, Up, and Down presses should trigger IR commands (as should Right), but those IR commands would not trigger normal "button" commands (or we'd have recursion problems with the Up/Down/Right buttons). Only one "button" command would fire, the SaverSwitcher code, after the user pressed Right to select that last choice.
I agree on the menu, but I'm not sure different IR commands would be required. When the user enters the menu he would probably enter a new "mode" and I think this might solve the recursion problems.

I just realized that we might have som problems with screen savers here.

I'm not sure in what situation the screen saver is deactivated, but I guess you still want to screen saver to be activate when the SaverSwitcher code is executed. In the opposite way I think the normal button subscription TrackStat is using won't be called until the screen saver is deactivated.


2) Slimserver should still allow users to control the order so that TrackStat always preceded SaverSwitcher or vice-versa.Controlling the order via a user interface would be prefered, but I think it might be enough if this could be configured manually in some configuration file in the first version. Most users probably doesn't care to change the order. I think it will be quite easy to make the implementation so it remember the command you selected the last time and automatically steps down to that command the next time the menu is activated. This way the ordering configuration might not be so important in the first version.


3) I've read some complaints on the forums about the modal buton behavior. This sort of UI, while adding at least one button press to commands for users who load extra plugins, might assuage some of the modal behavior critics.

4) For the modal critics, we might even want an option for adding a mapping to indicate whether Slimserver should always confirm the button presses.
I'm not sure I understand what you mean with "modal button behaviour", could you explains some more or refer to a thread where the problem is discussed ?

I would suggest a step by step implementation regarding this to make sure we at least solve the most critical issues, something like:

Step 1:
Make it possible for plugins to register actions on free buttons in the same mode

Step 2:
Make it possible for plugins to register action on non-free buttons in the same mode, resulting in a menu when the user pressed the button. Maybe the callback to check if a menu want to execute the action could also be implemented in this step.

Step 3:
Support for configuring the ordering in the menu via a configuration file.

Step 4:
Support for configuring everything from the web and/or player interface.

erland
2007-03-08, 22:04
Just to make everything clear. If anyone feels like providing patches for any of the things I have mentioned in this thread, please do.

I will probably try to look at some of the items myself sometime in the next weeks/months, but at the moment I'm in a middle of some refactoring of the code in some of my plugins to make them easier to maintain, so that will probably keep me busy in the next weeks.

So feel free to provide patches or register my ideas as feature requests. If you just register an issue as a feature request I think it might be a good idea to post the number here so anyone willing to make a patch can attach it to the feature request.

hickinbottoms
2007-03-09, 02:10
I've provided a patch for the "browse music folder not reporting end of
scan" issue in bug#4812:
http://bugs.slimdevices.com/show_bug.cgi?id=4812

Stuart

erland wrote:
> Just to make everything clear. If anyone feels like providing patches
> for any of the things I have mentioned in this thread, please do.
>
> I will probably try to look at some of the items myself sometime in the
> next weeks/months, but at the moment I'm in a middle of some refactoring
> of the code in some of my plugins to make them easier to maintain, so
> that will probably keep me busy in the next weeks.
>
> So feel free to provide patches or register my ideas as feature
> requests. If you just register an issue as a feature request I think it
> might be a good idea to post the number here so anyone willing to make a
> patch can attach it to the feature request.
>
>
>

peterw
2007-03-09, 07:05
Good idea

I agree on the menu, but I'm not sure different IR commands would be required. When the user enters the menu he would probably enter a new "mode" and I think this might solve the recursion problems.

I just realized that we might have som problems with screen savers here.

I'm not sure in what situation the screen saver is deactivated, but I guess you still want to screen saver to be activate when the SaverSwitcher code is executed. In the opposite way I think the normal button subscription TrackStat is using won't be called until the screen saver is deactivated.


Thinking about Slimserver internals, I don't see how to avoid IR commands. The player sends IR information to Slimserver via the SliMP3 or Squeezebox protocol. As I understand it, Slimserver then fires an IR command with a hex(?) argument representing the IR "code" information from the player. It tries to map the the IR code to a IR name, and the IR name to a button mapping for the current mode (or the default mode). If the button mapping succeeds, the code for the button mapping is executed.

You've got a good point about screensavers -- their player update intervals range from minutes (for something like Date and Spelled Time) to half seconds (Date and Time, and other savers that might show time including seconds) to tiny fractions of a second (visualizer screensavers). My first thought is this "disambiguity" menu would result in Slimserver pushing the player into a new mode, which should prevent the screensaver from reclaiming the player display. Perhaps we could use button commands after all, simply have Slimserver refuse to allow any changes to the special disambiguity mode's mappings.

Modal button behavior: a number of customers don't like the fact that buttons behave differently depending on the player's current mode. Classic example is "+" -- when browsing the catalog, it means add to the current playlist. But when scrolling through the current playlist from Now Playing, "+" means *remove* from the current playlist. Everyone seems to agree that this situation stems from reliance on a remote control with relatively few buttons. Some users seem to desire remote controls with more buttons -- they'd prefer separate "Add" and "Remove" buttons instead of the modal behavior of "+"; they'd like a Stop button instead of having to remember to hold Pause, etc. With a disambiguity/confirmation menu like we're talking about for button conflicts, there's a chance that Slimserver could offer users the option of prompting for confirmation of some of the more unusual modal behaviors like "+" or even "1.hold" for playing Favorite #1.

For the record, I do not want a remote control with significantly more buttons. Perhaps a few -- "Menu" to bring up some sort of contextual menu, perhaps "OK" as an alternative to "Right" for confirming choices. But I would rather have the current remote than some 75-key monstrosity.

peterw
2007-03-09, 21:43
I'm starting to play with code for a plugin to provide the button conflict resolution and a general "context menu" as well. To work, plugins would call an API defined by this plugin instead of Slim APIs like addModeDefaultMapping(). To do this, they'd copy & use a wrapper function like that I've suggested for my FuzzyTime plugin:
http://www.tux.org/~peterw/slim/FuzzyTime.html
Essentially, define a local sub that calls the 3rd party API if the 3rd party plugin has been loaded; otherwise, call the normal Slim API.

The button conflict resolution would would work as described in post #14 -- when the user pressed a button that had multiple mappings for the current mode, the plugin would determine which mappings really were valid and offer choices like "Rate track *".

I imagine the context menu working something like this: when a user pressed the Search button, my plugin would find every set of mappings associated with the current mode. It would see which plugins were interested in offering an action and get a general menu string for each ("Rate this song", "Switch screensavers", etc.). When the user right-arrows on a general option like "Rate this song", the plugin would ask the appropriate plugin for a string for each relevant button. The user could Up/Down through those options and right-arrow to execute the command.

I think of this context menu like a typical OS/2 / Windows / MacOS / Gnome / KDE desktop "right-click" context menu. It would let the user find functions that the user doesn't remember the shortcuts for.

First level context menu (the first option provides access to old Search function, so what you get now with "Search" would be "Search" + "Right"):

Search
Rate this song
Switch screensavers
Send an X-10 command

Second level, after right-arrowing on "Rate this song":

Rate this song *
Rate this song **
Rate this song ***
Rate this song ****
Rate this song *****

Pressing the left arrow button would immediately exit/cancel this context menu.

Perhaps a configurable option would be displaying the shortcut by the options in the context menu, ala

Rate this song * (Hold 1)
Rate this song ** (Hold 2)
Rate this song *** (Hold 3)
Rate this song **** (Hold 4)
Rate this song ***** (Hold 5)

to help teach users the shortcuts.

How does that sound -- both the context menu idea, and the idea for implementing this first as a 3rd party plugin (rather than as a Slimserver 7.x patch)?

-Peter

erland
2007-03-09, 22:25
First level context menu (the first option provides access to old Search function, so what you get now with "Search" would be "Search" + "Right"):

Search
Rate this song
Switch screensavers
Send an X-10 command

Second level, after right-arrowing on "Rate this song":

Rate this song *
Rate this song **
Rate this song ***
Rate this song ****
Rate this song *****

Pressing the left arrow button would immediately exit/cancel this context menu.

Perhaps a configurable option would be displaying the shortcut by the options in the context menu, ala

Rate this song * (Hold 1)
Rate this song ** (Hold 2)
Rate this song *** (Hold 3)
Rate this song **** (Hold 4)
Rate this song ***** (Hold 5)

to help teach users the shortcuts.

How does that sound -- both the context menu idea, and the idea for implementing this first as a 3rd party plugin (rather than as a Slimserver 7.x patch)?
Making it as a plugin would be a lot better than not making it at all, so I think it's a great start. In the long run I think it would be preferable if this type of thing was in standard slimserver, but having it as a plugin would be a good start. I think the only problem with making this as a plugin is that you probably won't get support by all 3rd party plugins and probably by none of the plugins included with the standard slimserver since I imagine that they don't like to have dependencies from standard SlimServer plugins to a 3rd party plugin. However, I think I would support it in all my plugins as long as it was just a question of adding and if statement that checked if your plugin was installed and then execute some code that registers in your plugin instead of SlimServer. I have actually thought a bit earlier about making this my self as a plugin, but my thought was just to handle the simple situation so plugins can register free buttons (Step 1 in my previous post).

Maybe the plugin even could be compatible with the 6.5 releases for now, so we don't have to wait for the 7.0 release to use it ?

A single level menu would be a great start, I personally think you can let the plugins handle the second menu level themself to make your plugin a bit simplier. The reason is that the plugin would probably like to work the same if your plugin wasn't installed. If the second menu logic was handled by your plugin this would mean that the plugin would anyway need to implement corresponding logic by itself to support the second level when your plugin isn't installed.

The mixer functions accessible by holding play button down today in various places works this way today, it handles the first level menu by itself and let the plugins handle any second level menu by themself.

I'm sure you are already aware of this, but make sure that its possible to register a button for a certain mode, for example the 'playlist' mode which corresponds to the "Now Playing" screen. Basically in the same way as this is possible today with the addModeDefaultMapping function.

If I understands it correctly I can see it work something like this when your plugin is installed:
1. My plugin register its button functions in your plugin
2. When a button is pressed the menu is shown (if more than one plugins/functions has been registered for the button)
3. The user navigates to the correct menu entry on the top level and right click
4. Your plugin calls the registered plugin function in my plugin. My plugin would now move into a custom mode which displayed the second level menu.

And without your plugin installed it would work this way:
1. My plugin register its button functions in standard SlimServer
2. When a button is pressed no menu is shown, instead SlimServer will directly call the registered plugin function in my plugin. My plugin would now move into a custom mode which display the second level menu (the first level menu would not be displayed in this setup).

As I said initially I think it would be a great start to make this a plugin, it is always possible to move the code into standard SlimServer at a later time if we want to.

Edit: Changed the sentence in point 2 in the last section to make it understandable.

Philip Meyer
2007-03-10, 03:54
That all sounds good to me. Like erland said, it would be nice for this to be core slimserver functionality for 7.0, seeing that the plugin API is currently being worked on, now would seem a good time to do it.

However, writing it as a plugin for 6.5 now and if it goes well getting some help to get it into 7.0 is probably the way to go.

I would support it in my plugin(s).

Phil

peterw
2007-03-10, 07:41
In the long run I think it would be preferable if this type of thing was in standard slimserver, but having it as a plugin would be a good start. I think the only problem with making this as a plugin is that you probably won't get support by all 3rd party plugins and probably by none of the plugins included with the standard slimserver since I imagine that they don't like to have dependencies from standard SlimServer plugins to a 3rd party plugin. However, I think I would support it in all my plugins as long as it was just a question of adding and if statement that checked if your plugin was installed and then execute some code that registers in your plugin instead of SlimServer. I have actually thought a bit earlier about making this my self as a plugin, but my thought was just to handle the simple situation so plugins can register free buttons (Step 1 in my previous post).

Maybe the plugin even could be compatible with the 6.5 releases for now, so we don't have to wait for the 7.0 release to use it ?

A single level menu would be a great start, I personally think you can let the plugins handle the second menu level themself to make your plugin a bit simplier. The reason is that the plugin would probably like to work the same if your plugin wasn't installed. If the second menu logic was handled by your plugin this would mean that the plugin would anyway need to implement corresponding logic by itself to support the second level when your plugin isn't installed.


I definitely imagine this as a 6.5 plugin, for two reasons. One, I haven't bothered porting my plugins to 7.x, and don't much care for bleeding edge code. Two, this seems like a good "proof of concept" plan. Show Slim Devices (and other users) how this sort of thing could work, to solicit more feedback without asking users to go the more adventurous 7.0 beta route.

If it's deemed a success, yes, definitely move it into the core code!

Having the plugin handle the context menus was something I thought about briefly. I don't know which is a better route. On the one hand, having this new "ContextMenu" plugin handle the menus reduces options for other plugins. On the other hand, having the new plugin handle context menus would help unify the user interface experience for the on-demand context menu. And some plugins have button operations that don't require menu interfaces. For instance, my SaverSwitcher, StatusFirst, and VolumeLock plugins will automatically take action under certain button circumstances, perhaps using showBriefly(), but not entering a new menu mode. I'd rather simply register some information like
['repeat.single', 'Show current repeat status', \&myFunction ]
than implement a bunch of code for my own new menu mode.

My StatusFirst and VolumeLock plugins are examples of some *bad* UI, too. Currently, each developer chooses their own style for using the menu system to set preferences. Some use Right arrow with the new radio button/checkbox overlay. Some, like SaverSwitcher, use just Right arow. Others like StatusFirst and VolumeLock have UI rules like "press Play to enable", "press Add to disable". I think it would be good to start working toward a more uniform user experience, and I think the context menu might be a good place to enforce something more uniform.

But it could work the other way, or it could be more flexible. I expected when ContextMenu started to display the context menu, it would call the registered coderef for each plugin with undef or maybe '' as the normal "button" argument.** I imagined the plugin would return something like a an array of
[ $buttonName, $labelTextForDisplay, $coderefToExecute ]
arrays for each different action the plugin offered at that point (as above, though of course string() would be used for the label). Perhaps plugins could instead return a simple $coderef object if they wanted to control their own menu.

-Peter

** general mapping registration would look something like
addContextModeDefaultMapping($mode,$mapref,$codere f)
for resolving conflicts, the new plugin would find all coderefs for the current mode that had an entry for the button in question in the current mode. It would call each registered coderef with the button name and $client. Each plugin would return something like
[ $labelTextForDisplay, $coderefToExecute ]
if interested in offering an action, or something like undef if not. The on-demand context menu would use this same $coderef from the addContextModeDefaultMapping() call, but since there's been no real button press, it would pass '' or undef as the button name.

erland
2007-03-10, 09:32
Having the plugin handle the context menus was something I thought about briefly. I don't know which is a better route. On the one hand, having this new "ContextMenu" plugin handle the menus reduces options for other plugins. On the other hand, having the new plugin handle context menus would help unify the user interface experience for the on-demand context menu. And some plugins have button operations that don't require menu interfaces. For instance, my SaverSwitcher, StatusFirst, and VolumeLock plugins will automatically take action under certain button circumstances, perhaps using showBriefly(), but not entering a new menu mode. I'd rather simply register some information like
['repeat.single', 'Show current repeat status', \&myFunction ]
than implement a bunch of code for my own new menu mode.
I'm not saying that it would be wrong to support sub menus, but it feels like we are trying to solve two different problems.

Problem 1: The button collision stuff and the first level menu
Problem 2: It's too hard to implement a menu for a plugin

It wouldn't hurt to solve both problems in your plugin, but I just feel that it might get your plugin more complicated than neccesary. Problem 2 would be much better solved by adding some easier way for a plugin to implement a menu, this could be used when a button is pressed but it could also be used in a lot of other places where a menu is needed, for example in the "Plugins" section of the menu structure. It could be implemented as a separate plugin or it could be implemented as some utility class which is included with SlimServer. I also think the solution to problem 2 needs to support more than one menu level, the best would be if the number of menu levels could be unlimited. I would also imagine that a plugin might want to have different menus depending on which item you were standing on when the first menu were launched. As an example if you register a button that launces a menu in the browse menus, you might not want to have the same sub menus if you were standing on a artists compared to if you were standing on an album or track. A plugin might also want to be able to have partly dynamic text for the sub menus, so depending on which album you are standing on the text in the sub menus will be different.

Anyway, it's great seeing that you want to do something to solve the collision problem. It might be a good idea to start making the plugin and then we can see how it feels like regarding the sub menus when you have something up and running.

peterw
2007-03-10, 10:18
I'm not saying that it would be wrong to support sub menus, but it feels like we are trying to solve two different problems.

Problem 1: The button collision stuff and the first level menu
Problem 2: It's too hard to implement a menu for a plugin

It wouldn't hurt to solve both problems in your plugin, but I just feel that it might get your plugin more complicated than neccesary. Problem 2 would be much better solved by adding some easier way for a plugin to implement a menu, this could be used when a button is pressed but it could also be used in a lot of other places where a menu is needed, for example in the "Plugins" section of the menu structure. It could be implemented as a separate plugin or it could be implemented as some utility class which is included with SlimServer. I also think the solution to problem 2 needs to support more than one menu level,


I see three problems, in this order of importance:

Problem 1: The button collision stuff and the first level menu
Problem 2: It's hard for users to remember the button sequences for all their plugins (and even some Slimserver functions!)
Problem 3: Some plugins that would benefit from fixing 1 & 2 don't currently have much in the way of menu UI for taking action, and it's too hard to implement a menu for a plugin

I *completely* agree that it would be good to have some library to simplify menu code. I feel like I'm reinventing the wheel every time I make a plugin with player menus. And I shudder to look at some of the code I've cobbled together for menus -- in stark contrast to the clean API in 6.5.x for web menus. I've got some basic ideas for Perl classes (a "ScrollChoices" object that's basically an array of string tokens for up/down scrolling at a given spot in a menu tree, and a "MenuTree" object that ties together ScrollChoices, has hooks for executing code as the user goes through the tree, a "pointer" for remember location and "path" traversed above and below the current location, APIs for manipulating the hierarchy and ScrollChoices objects, etc.; plugins would have per-player MenuTree objects...) but I haven't had enough free time & interest to start writing even pseudocode.

And I agree with your earlier assessment about prioritizing any work towards a solution.

Would you be interested in seeing code that likely doesn't even compile? I've been fleshing out the code with lots of TODO gaps, etc., and might not have much time to work on it until next week since much of my work happens on the commuter train to/from work.

-Peter

Grotus
2007-03-10, 18:58
On Mar 10, 2007, at 9:18 AM, peterw wrote:

>
> I *completely* agree that it would be good to have some library to
> simplify menu code. I feel like I'm reinventing the wheel every time I
> make a plugin with player menus. And I shudder to look at some of the
> code I've cobbled together for menus -- in stark contrast to the clean
> API in 6.5.x for web menus. I've got some basic ideas for Perl
> classes
> (a "ScrollChoices" object that's basically an array of string
> tokens for
> up/down scrolling at a given spot in a menu tree, and a "MenuTree"
> object that ties together ScrollChoices, has hooks for executing code
> as the user goes through the tree, a "pointer" for remember location
> and "path" traversed above and below the current location, APIs for
> manipulating the hierarchy and ScrollChoices objects, etc.; plugins
> would have per-player MenuTree objects...) but I haven't had enough
> free time & interest to start writing even pseudocode.
>

Your "ScrollChoices" sounds a lot like Slim::Buttons::Input::List.
That is exactly what it is for, present a list of things and handle
the up/down scrolling (and number scrolling, etc). At one point I
wanted to make a Slim::Buttons::Input::Tree module, but I never got
around to it. It would most likely have involved stringing together
a series of Slim::Buttons::Input::List modes.

What really needs to happen, is for the client modes to be
Objectified. That would make things a lot easier, in that you could
inherit all the input handling and just have to provide custom
functions for whatever it is that your mode is doing. That would
also eliminate the need for the passback function that seems to
confuse everyone. If I ever get the time to get my home computer up
and running again, I might take that on.

As for button mappings, let me say good luck to anyone attempting a
UI for setting that up. You can map any function to any button, and
different remotes can have different buttons. And of course you also
have to account for the modal nature of things. And you don't even
get to use the modes as a way to limit the number of functions, since
there's a function in common to allow you to call a function from any
mode. And you also need to set up the function arguments, since
there aren't ten functions corresponding to numberLetter 0 - 9,
there's one function that gets passed the number pressed.

erland
2007-03-11, 03:05
Would you be interested in seeing code that likely doesn't even compile? I've been fleshing out the code with lots of TODO gaps, etc., and might not have much time to work on it until next week since much of my work happens on the commuter train to/from work.Unless there is some specific part where you feel it's important to get early feedback on the actual source code, I think I would prefer to wait until you have something that is up and running with some basic functionality.

One experience that I have with plugin interfaces towards external plugins is that its really important that you make sure the interface which the other plugins are going to use is stable and almost never change. One example on this is that it might be a good idea to make the interface in a way so you can add new input/output parameters to it at a later time without making the interface incompatible. Some sort of checkVersion/getVersion function that a plugin can call to check if it's compatible with your plugin might also be useful.

The problem with incompatible interface changes is that it must be synchronized with releases for all other plugin developers and also that normal users won't understand that uppgrading one plugin also requires that other plugins must be upgraded, especially if the plugins comes from different 3rd party developers.

Triode
2007-03-12, 13:47
Thought it was worth a quick post of how I expect the external parser extensions for xmlbrowser to work in 7.0.

Essentially this allows xmlbrowser to be reused to fetch remote content and then parse it with a custom parser before displaying using xmlbrowser [web, player or cli]

This should reduce the amount of code needed for plugins which fetch remote content, process them and then display a list [alien for example]

Attached is an example which browses the latest posts on these forums. Extract the zip file into the server directory and then open the opml file in the OPML browser [need to enable it under server settings - favorites]. From here you can browse into the linked url or save it as a favorite (which makes it available on the player UI). When you browse into the remote url, its content is fetched parsed to create a new list - in this case recent posts. Browsing into this fetches, parses the posts and then displays them.

erland
2007-06-10, 00:20
7. Possibility for a plugin to use the Slim::Hardware::IR::addModeDefaultMapping method to register actions even though some other plugin has registered actions on the same mode. As an example, today only one plugin can call addModeDefaultMapping with the 'playlist' as mode, when the call from a second plugin comes with 'playlist' mode it will be ignored. It would be a good idea to allow multiple calls to addModeDefaultMapping as long as they are registering different buttons. One problem today is that TrackStat registers the 0-9 buttons while the Playlist Manager plugin try to register actions on the Add button, one of them will always fail today.

Just for information, I have registered a bugzilla report together with a patch for 7.0 for this:
http://bugs.slimdevices.com/show_bug.cgi?id=5112

The current patch just solves the most critical part of the problem by allowing several plugins to register different buttons on the same mode. The situation where several plugins wants to use the same button has not been solved yet.

peterw
2007-06-10, 06:50
Thanks for moving this forward a bit.

erland
2007-06-12, 12:53
7. Possibility for a plugin to use the Slim::Hardware::IR::addModeDefaultMapping method to register actions even though some other plugin has registered actions on the same mode. As an example, today only one plugin can call addModeDefaultMapping with the 'playlist' as mode, when the call from a second plugin comes with 'playlist' mode it will be ignored. It would be a good idea to allow multiple calls to addModeDefaultMapping as long as they are registering different buttons. One problem today is that TrackStat registers the 0-9 buttons while the Playlist Manager plugin try to register actions on the Add button, one of them will always fail today.

Just for information, I have registered a bugzilla report together with a patch for 7.0 for this:
http://bugs.slimdevices.com/show_bug.cgi?id=5112

The current patch just solves the most critical part of the problem by allowing several plugins to register different buttons on the same mode. The situation where several plugins wants to use the same button has not been solved yet.

If someone is interested in including this in a future SlimServer release, please vote on the bug report.