Hello,
As promised (but later than expected due to the sudden arrival of the real life in my geek life) here comes the first plugin architecture (what a presomptuous name for this hack).
Feature: - Supports the audioscrobbler plugin (which has became official now, if you use it change the client name to 'pte').
Mis-feature: - the audioscrobbler plugin might be the only one supported
PS: The diff is against debian's pytone 2.1
Hi,
On 26.11.04, Nicolas Évrard wrote:
As promised (but later than expected due to the sudden arrival of the real life in my geek life) here comes the first plugin architecture (what a presomptuous name for this hack).
Feature:
- Supports the audioscrobbler plugin (which has became official now, if you use it change the client name to 'pte').
Mis-feature:
- the audioscrobbler plugin might be the only one supported
PS: The diff is against debian's pytone 2.1
Thanks a lot. Note that I did not yet include the plugin support in PyTone 2.1.3. I want to stabilize this release a little bit, before going ahead with new features.
I've added a few comments below.
diff -rub --exclude='*pyc' pytone-2.1.0/src/config.py pytone-2.1.0.mine/src/config.py --- pytone-2.1.0/src/config.py 2004-07-28 22:04:37.000000000 +0200 +++ pytone-2.1.0.mine/src/config.py 2004-11-26 00:57:02.000000000 +0100 @@ -120,7 +120,16 @@ def _convert(self, s): return float(s)
+class configlist(configitem):
- def _check(self, s):
try:
items = s.split(',')
except:
raise ConfigError("Expecting list, got '%s'" % s)
- def _convert(self, s):
return s.split(',')
class configcolor(configitem):
@@ -616,13 +625,16 @@ rescan = configkeys("u U") shuffle = configkeys("r R")
+class plugins(configsection):
- torun = configlist('')
# # register known configuration sections #
sections = ['mixerwindow', 'helpwindow', 'filelistwindow', 'database', 'iteminfowindow', 'logwindow', 'mixer', 'colors', 'playerwindow', 'playlistwindow', 'general',
'inputwindow', 'network', 'player', 'keybindings']
'inputwindow', 'network', 'player', 'keybindings', 'plugins']
If there is only one configuration option ("torun"), we probably don't need a new section.
############################################################################## # end configuration tree
[ snip ws changes ]
diff -rub --exclude='*pyc' pytone-2.1.0/src/pytone.py pytone-2.1.0.mine/src/pytone.py --- pytone-2.1.0/src/pytone.py 2004-07-19 19:58:07.000000000 +0200 +++ pytone-2.1.0.mine/src/pytone.py 2004-11-26 00:46:39.000000000 +0100 @@ -109,6 +109,7 @@ import network network.unixserver(os.path.expanduser(config.network.socketfile)).start()
- # Now that everything is setup, we can initialize the players. This has # to be done after all other services have been setup because # the players immediately start requesting a new song
@@ -119,6 +120,33 @@ hub.hub.notify(events.quit(), 100) raise
+############################################################################## +# Plugins initialization +############################################################################## +initializedPlugins = []
+# Adding the plugin to sys.path +sys.path.insert(0, os.path.expanduser('~/.pytone/plugins'))
We probably should also search in a global module plugins in the pytone module hierarchy.
+# Initializing the plugins determined in the config file +plugins = config.plugins.torun +for name in plugins:
- plugin = __import__(name)
- initializedPlugins.append(plugin.initialize())
+# Now we put sys.path back to normal +del sys.path[0]
+# And now the plugins are all started +for plugin in initializedPlugins:
- try:
plugin.start()
- except:
# If a plugin cannot be started it's not really annoying
# TODO We should warn the user
pass
At the moment, you only support plugins which do not need to create any new window (think about the ID3 tag editor proposed on the list). While this may be okay for the beginning, we have to keep in mind that things like this should be possible.
Btw, could you also send the new version of the audioscrobbler plugin.
Thanks,
Jörg
* Joerg Lehmann [22:26 29/11/04 CET]:
Hi,
Hello,
On 26.11.04, Nicolas Évrard wrote:
As promised (but later than expected due to the sudden arrival of the real life in my geek life) here comes the first plugin architecture (what a presomptuous name for this hack).
Feature:
- Supports the audioscrobbler plugin (which has became official now, if you use it change the client name to 'pte').
Mis-feature:
- the audioscrobbler plugin might be the only one supported
PS: The diff is against debian's pytone 2.1
Thanks a lot. Note that I did not yet include the plugin support in PyTone 2.1.3. I want to stabilize this release a little bit, before going ahead with new features.
That's perfectly normal. You don't want my bug in your code unless they are proven usefull :)
sections = ['mixerwindow', 'helpwindow', 'filelistwindow', 'database', 'iteminfowindow', 'logwindow', 'mixer', 'colors', 'playerwindow', 'playlistwindow', 'general',
'inputwindow', 'network', 'player', 'keybindings']
'inputwindow', 'network', 'player', 'keybindings', 'plugins']
If there is only one configuration option ("torun"), we probably don't need a new section.
Indeed, but I thought that one day we might want to add more information there (don't know what yet).
+initializedPlugins = []
+# Adding the plugin to sys.path +sys.path.insert(0, os.path.expanduser('~/.pytone/plugins'))
We probably should also search in a global module plugins in the pytone module hierarchy.
Yes, but where is this module situated ?
Some possibilities :
- /usr/share/pytone/plugins
I think that's where debian would put it
- /usr/local/share/pytone/plugins
That's where someone installing from the sources would put them
- Somewhere in the python path ?
I believe the right thing to do is to use the second proposition and let distro packagers do there jobs.
+# Initializing the plugins determined in the config file +plugins = config.plugins.torun +for name in plugins:
- plugin = __import__(name)
- initializedPlugins.append(plugin.initialize())
+# Now we put sys.path back to normal +del sys.path[0]
+# And now the plugins are all started +for plugin in initializedPlugins:
- try:
plugin.start()
- except:
# If a plugin cannot be started it's not really annoying
# TODO We should warn the user
pass
In fact I changed this section a bit:
+ # Adding the plugin to sys.path + sys.path.insert(0, os.path.expanduser('~/.pytone/plugins')) + plugins = [__import__(name) for name in config.plugins.torun] + + # Now we put sys.path back to normal + del sys.path[0] + + # And now the plugins are all started + for plugin in plugins: + try: + plugin.initializeAndStart() + except: + # If a plugin cannot be started it's not really annoying + # TODO We should warn the user + pass
Because this code seems more clean to me.
At the moment, you only support plugins which do not need to create any new window (think about the ID3 tag editor proposed on the list). While this may be okay for the beginning, we have to keep in mind that things like this should be possible.
Yes. It occured to me when I was thinking on how I could display errors in plugin.
So I came with this idea:
- the graphical ui is just another service
- there should be a way to call this service to display information
Basic view ==========
+-----------+ +--------------+ | UI Server | <------ UI Communication ----> | Services | +-----------+ a real protocol +--------------+ or just calling /|\ methods | | | |/
+-------------------+ | UI Implementation | +-------------------+
Basic idea ==========
We have the pytone main programs that initialize the UIServer. The UIServer is providing 'UICapacity'.
Plugins are then initialized, they all provide a capacity, just as the UIServer. Those that need a certain capacity make the request to the main program to gain access to it. They are passed a pointer to the service providing the requested capacity.
What the pointer is I have no idea. The easiest way to go is to use the instance implementing the service. The most portable way to go would be to use a socket or a URI and to communicate throught a defined protocol.
The UIServer then selects the best UIImplementation (taken from the user's config file) and indicate the windows and
Comments are welcomed, as I don't have a full view on the program I have probably downsized some problems and/or I did not see some obvious answers to this problem.
Btw, could you also send the new version of the audioscrobbler plugin.
Here it is. For now the plugin is using a file in the plugin directory to get the username and the password. I also noticed that to be thread-safe the initialization should only occur in the start method. SO I moved it there.
I added a backlog to the module so I post it also.