Author: duncan
Date: Fri Mar 9 20:17:29 2007
New Revision: 9312
Modified:
branches/rel-1/freevo/src/audio/plugins/musicip.py
Log:
[ 1676991 ] MusicIP Mixer Plugin
Update applied
Modified: branches/rel-1/freevo/src/audio/plugins/musicip.py
==============================================================================
--- branches/rel-1/freevo/src/audio/plugins/musicip.py (original)
+++ branches/rel-1/freevo/src/audio/plugins/musicip.py Fri Mar 9 20:17:29 2007
@@ -1,4 +1,3 @@
-# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------
# musicip.py - MusicIP Mixer plugin
# -----------------------------------------------------------------------
@@ -33,11 +32,15 @@
# -----------------------------------------------------------------------
+from audio.audioitem import AudioItem
from gui.PopupBox import PopupBox
from directory import Playlist
import plugin
import config
import time
+import item
+import menu
+import socket
from urllib import urlencode
from httplib import HTTPConnection
@@ -45,22 +48,33 @@
class MusicIPException(Exception):
pass
+
+
class MusicIPClient:
+
def __init__(self, host):
self.host = host
- self.connection = HTTPConnection(host)
+ self.connection = None
+
def callApi(self, func, args=None):
+ if not self.connection:
+ self.connection = HTTPConnection(self.host)
+
url = '/api/'+func
if args:
url += '?' + urlencode(args)
#print '[MusicIP Mixer] Fetching', url, 'from', self.host
- self.connection.request("GET", url)
+ try: self.connection.request("GET", url)
+ except socket.error:
+ self.connection = None
+ raise MusicIPException("Failed to communicate with MusicIP
service!")
response = self.connection.getresponse()
if response.status != 200:
- raise MusicIPException(response.read())
+ raise MusicIPException(response.read().rstrip())
return response.read()
+
def getArtists(self, filter=None, showCounts=False):
"""
Returns a list of all the artists.
@@ -76,6 +90,7 @@
if showCounts: args["showCounts"] = 1
return self.callApi("artists", args).split('\n')
+
def getAlbums(self, artist=None, bysong=False, extended=False,
filter=None, showCount=None):
"""
Returns a list of all the albums.
@@ -84,10 +99,10 @@
artist=name Only include albums with at least one song by the named
artist
bysong Return key song from each album (useful for other api calls) 1.5
- extended Return album in artist@@name format 1.5
- filter=name Use the named filter when creating the list (default none)
- If there is no such filter the name may refer to a genre as an
implicit filter. 1.5
- showCount Prefix each album with the number of songs on that album
+ extended Return album in artist@@name format 1.5 filter=name Use the
named
+ filter when creating the list (default none) If there is no such
filter the
+ name may refer to a genre as an implicit filter. 1.5 showCount Prefix
each
+ album with the number of songs on that album
"""
args = {}
if artist: args["artist"] = artist
@@ -97,45 +112,45 @@
if showCount: args["showCount"] = 1
return self.callApi("albums", args).split('\n')
+
def getGenres(self, filter=None, showCount=False):
"""
- Returns a list of all the genres. Parameters are: filter=name Use the
- named filter when creating the list (default none) 1.6 showCount
Prefix each
- genres with the number of songs in that genre
+ Returns a list of all the genres. Parameters are: filter=name Use the
named
+ filter when creating the list (default none) 1.6 showCount Prefix each
genres
+ with the number of songs in that genre
"""
args = {}
if filter: args["filter"] = filter
if showCount: args["showCount"] = 1
return self.callApi("genres", args).split('\n')
+
def getMix(self, song=None, artist=None, album=None, mixgenre=None,
mood=None, playlist=None, rejectsize=None,
- rejecttype=None, size=None, sizetype=None, style=None,
variety=None, filter=None,
- content=None):
+ rejecttype=None, size=None, sizetype=None, style=None, variety=None,
filter=None,
+ content=None):
"""
Return a dynamic playlist. Parameters are: song=fullpath Choose a seed
song
- artist=name Choose a seed artist
- album=fullpath Choose a seed album. fullpath is any song from the album
- album=artistname@@albumname Choose a seed album. (example: "The
Beatles@@The White Album")
- mixgenre=boolean Restrict mix to the genre of the seed 1.1.6
- mood=name Make a mood mix based on the given mood 1.5
+ artist=name Choose a seed artist album=fullpath Choose a seed album.
fullpath
+ is any song from the album album=artistname@@albumname Choose a seed
album.
+ (example: "The Beatles@@The White Album") mixgenre=boolean Restrict
mix to the
+ genre of the seed 1.1.6 mood=name Make a mood mix based on the given
mood 1.5
playlist=name||fullpath Choose all songs in the playlist as seeds
1.1.5.1
rejectsize=# Set the number of items to skip before repeating artists
1.1.6
- rejecttype=(tracks|min|mbytes) Set the units for rejectsize (default
tracks) 1.1.6
- size=# Set the size of the list (default 12)
- sizetype=(tracks|min|mbytes) Set the units for size (default tracks)
- style=# Set the style slider (default 20, range is 0..200)
- variety=# Set the variety slider (default 0, range is 0..9))
- filter=name Use the named filter when creating the playlist (default
none)
- If there is no such filter, the name may refer to a genre as an
implicit filter.
- content=(json|m3u|text|xspf) Set the returned mime type (default text)
- json|xspf requires 1.5
- short Return short-style names (Windows only) 1.1.4
- You may specify any number of songs, artists or albums as seeds, but
- you may not mix different types in a single request. If no seeds are
set, a
- random song will be chosen from within the current filter.
+ rejecttype=(tracks|min|mbytes) Set the units for rejectsize (default
tracks)
+ 1.1.6 size=# Set the size of the list (default 12)
sizetype=(tracks|min|mbytes)
+ Set the units for size (default tracks) style=# Set the style slider
(default
+ 20, range is 0..200) variety=# Set the variety slider (default 0,
range is
+ 0..9)) filter=name Use the named filter when creating the playlist
(default
+ none) If there is no such filter, the name may refer to a genre as an
implicit
+ filter. content=(json|m3u|text|xspf) Set the returned mime type
(default text)
+ json|xspf requires 1.5 short Return short-style names (Windows only)
1.1.4 You
+ may specify any number of songs, artists or albums as seeds, but you
may not
+ mix different types in a single request. If no seeds are set, a random
song
+ will be chosen from within the current filter.
As of version 1.1.4, the above default values are replaced with the
current application settings from the mix preferences.
+
"""
args = {}
if song: args["song"] = song
@@ -161,28 +176,28 @@
else:
return data
+
def getMoods(self):
"""
- Returns a list of all the moods. Call this without parameters. This
- will only return information on platforms supporting the Moods menu.
+ Returns a list of all the moods. Call this without parameters. This
will only
+ return information on platforms supporting the Moods menu.
"""
return self.callApi("moods").split()
+
def getSongs(self, album=None, artist=None, content=None, filter=None,
extended=None):
"""
- Returns a list of all the songs (as a playlist). As of version 1.5, if
- you pass no artists or albums, all songs are returned. Parameters are:
- album=fullpath Only include songs from the named album. fullpath is
any song
- from the album album=artistname@@albumname Only include songs from the
named
- album. (example: "Pink Floyd@@Dark Side of the Moon")
- artist=name Only include songs by the named artist
- content=(json|m3u|text|xspf) Set the returned mime type (default text)
- json|xspf requires 1.5
- filter=name Use the named filter when creating the playlist (default
none)
- If there is no such filter the name may refer to a genre as an
implicit filter. 1.5
- extended Return extended info for each song (as in the getSong
- command). This ignores the content and short options.1.5 short Return
- short-style names (Windows only)
+ Returns a list of all the songs (as a playlist). As of version 1.5, if
you pass
+ no artists or albums, all songs are returned. Parameters are:
album=fullpath
+ Only include songs from the named album. fullpath is any song from the
album
+ album=artistname@@albumname Only include songs from the named album.
(example:
+ "Pink Floyd@@Dark Side of the Moon") artist=name Only include songs by
the
+ named artist content=(json|m3u|text|xspf) Set the returned mime type
(default
+ text) json|xspf requires 1.5 filter=name Use the named filter when
creating the
+ playlist (default none) If there is no such filter the name may refer
to a
+ genre as an implicit filter. 1.5 extended Return extended info for
each song
+ (as in the getSong command). This ignores the content and short
options.1.5
+ short Return short-style names (Windows only)
"""
args = {}
if album: args["album"] = album
@@ -198,17 +213,16 @@
else:
return data
+
def getSongInfo(self, index=None, file=None):
"""
- Returns information about the indicated song. Parameters are: index
- Choose a song by index file Choose a song by file
- Returned value is a list of attributes, 1 per line. The first word is
- the field name, and the rest of the line is the field value. Some
fields may
- not be present if there is no associated value. Current fields are:
name,
- artist, album, album-id, file, genre, track, active, seconds,
- bytes, year, bitrate, composer, conductor, orchestra, lyricist,
- rating, modified, lastplayed, playcount, added
-
+ Returns information about the indicated song. Parameters are: index
Choose a
+ song by index file Choose a song by file Returned value is a list of
+ attributes, 1 per line. The first word is the field name, and the rest
of the
+ line is the field value. Some fields may not be present if there is no
+ associated value. Current fields are: name, artist, album, album-id,
file,
+ genre, track, active, seconds, bytes, year, bitrate, composer,
conductor,
+ orchestra, lyricist, rating, modified, lastplayed, playcount, added
"""
assert index or file, 'Must specify a file or an index'
args = {}
@@ -222,14 +236,158 @@
info[k] = v
return info
-if __name__ == "__main__":
- client = MusicIPClient("minipc:10002")
- print client.getMix(artist="Aural Float", size=50, content='json')
-class PluginInterface(plugin.ItemPlugin):
+def getAudioItemsLazily(parent, callable, *args, **kwargs):
+ for filename in callable(*args, **kwargs):
+ yield AudioItem(filename, parent)
+
+
+
+class ArtistItem(item.Item):
+
+ def __init__(self, name, parent, service):
+ item.Item.__init__(self, parent)
+ self.name = name
+ self.type = 'musicip_album'
+ self.service = service
+
+
+ def actions(self):
+ return [ (self.make_menu, 'Browse') ]
+
+
+ def make_menu(self, arg=None, menuw=None):
+ try:
+ menuw.pushmenu(menu.Menu('Genres',
+ [ Playlist('All', getAudioItemsLazily(self, self.service.getSongs,
artist=self.name), self)] +
+ [ AlbumItem(x, self, self.service) for x in
self.service.getAlbums(artist=self.name, extended=True)]))
+ except MusicIPException, x:
+ pop = PopupBox(text=_(str(x)))
+ pop.show()
+ time.sleep(2)
+ pop.destroy()
+ return
+
+
+
+class AlbumItem(Playlist):
+
+ def __init__(self, name, parent, service):
+ Playlist.__init__(self, name.replace("@@", " - "), \
+ getAudioItemsLazily(self, service.getSongs, album=name), parent)
+ self.name = name.replace("@@", " - ")
+
+
+
+class GenreItem(item.Item):
+
+ def __init__(self, name, parent, service):
+ item.Item.__init__(self, parent)
+ self.name = name
+ self.type = 'musicip_genre'
+ self.service = service
+
+
+ def actions(self):
+ return [ (self.make_menu, 'Browse') ]
+
+
+ def make_menu(self, arg=None, menuw=None):
+ try:
+ menuw.pushmenu(menu.Menu(self.name,
+ [ Playlist('All', getAudioItemsLazily(self, self.service.getSongs,
filter=self.name), self)] +
+ [ AlbumItem(x, self, self.service) for x in
self.service.getAlbums(filter=self.name, extended=True)]))
+ except MusicIPException, x:
+ pop = PopupBox(text=_(str(x)))
+ pop.show()
+ time.sleep(2)
+ pop.destroy()
+ return
+
+
+
+class GenresItem(item.Item):
+
+ def __init__(self, parent, service):
+ item.Item.__init__(self, parent)
+ self.name = 'Genres'
+ self.type = 'musicip_genre_browser'
+ self.service = service
+
+
+ def actions(self):
+ return [ (self.make_menu, 'Browse') ]
+
+
+ def make_menu(self, arg=None, menuw=None):
+ try:
+ menuw.pushmenu(menu.Menu('Genres',
+ [ GenreItem(x, self, self.service) for x in
self.service.getGenres()]))
+ except MusicIPException, x:
+ pop = PopupBox(text=_(str(x)))
+ pop.show()
+ time.sleep(2)
+ pop.destroy()
+ return
+
+
+
+class ArtistsItem(item.Item):
+
+ def __init__(self, parent, service):
+ item.Item.__init__(self, parent)
+ self.name = 'Artists'
+ self.type = 'musicip_artist_browser'
+ self.service = service
+
+
+ def actions(self):
+ return [ (self.make_menu, 'Browse') ]
+
+
+ def make_menu(self, arg=None, menuw=None):
+ try:
+ menuw.pushmenu(menu.Menu('Artists',
+ [ ArtistItem(x, self, self.service) for x in
self.service.getArtists()]))
+ except MusicIPException, x:
+ pop = PopupBox(text=_(str(x)))
+ pop.show()
+ time.sleep(2)
+ pop.destroy()
+ return
+
+
+
+class AlbumsItem(item.Item):
+
+ def __init__(self, parent, service):
+ item.Item.__init__(self, parent)
+ self.name = 'Albums'
+ self.type = 'musicip_album_browser'
+ self.service = service
+
+
+ def actions(self):
+ return [ (self.make_menu, 'Browse') ]
+
+
+ def make_menu(self, arg=None, menuw=None):
+ try:
+ menuw.pushmenu(menu.Menu('Albums',
+ [ AlbumItem(x, self, self.service) for x in
self.service.getAlbums()]))
+ except MusicIPException, x:
+ pop = PopupBox(text=_(str(x)))
+ pop.show()
+ time.sleep(2)
+ pop.destroy()
+ return
+
+
+
+class PluginInterface(plugin.ItemPlugin,plugin.MainMenuPlugin):
"""
- This plugin allows you to create a new mix based on MusicIP's automatic
- mixing feature.
+ This plugin allows you to create a new mix based on MusicIP's automatic
mixing
+ feature. It also allows browsing by Genre, Album, or Artist.
You may set config.MUSICIP_SERVER to the host:port of the MusicIP service;
127.0.0.1:10002 is the default.
@@ -239,23 +397,33 @@
try: server = config.MUSICIP_SERVER
except AttributeError: server = "127.0.0.1:10002"
self.service = MusicIPClient(server)
+ #config.
plugin.ItemPlugin.__init__(self)
+ plugin.MainMenuPlugin.__init__(self)
+
+ #plugin.activate(self, type="audio")
+ #self._type = 'mainmenu_audio'
+
+
+ def items(self, parent):
+ return [GenresItem(parent, self.service),
+ ArtistsItem(parent, self.service),
+ AlbumsItem(parent, self.service)]
def actions(self, item):
self.item = item
-
+ #print 'actions called for item', item
items = []
if item.type in ('audio', 'playlist'):
items.append((self.file_mix, _('MusicIP Mix'), 'musicip_file_mix'))
if item.type == 'audio':
items.append((self.file_play_album, _('Songs From Same Album'),
'musicip_file_play_album'))
- items.append((self.file_play_all_by_artist, _('Songs From Same
Artist'), \
- 'musicip_file_play_all_by_artist'))
-
+ items.append((self.file_play_all_by_artist, _('Songs From Same
Artist'), 'musicip_file_play_all_by_artist'))
return items
+
def file_mix(self, arg=None, menuw=None):
kwargs = {}
try:
@@ -279,6 +447,7 @@
playlist = Playlist('MusicIP Mix', playlist=filenames,
display_type="audio", autoplay=True)
playlist.browse(arg=arg, menuw=menuw)
+
def file_play_album(self, arg=None, menuw=None):
kwargs = {}
try:
@@ -298,10 +467,10 @@
#file.write(m3u)
#print '\n'.join(filenames)
#items = [kaa.beacon.query(filename=f) for f in filenames]
- playlist = Playlist('%s - %s'%(songInfo['artist'], songInfo['album']),
\
- playlist=filenames, display_type="audio", autoplay=True)
+ playlist = Playlist('%s - %s'%(songInfo['artist'], songInfo['album']),
playlist=filenames, display_type="audio", autoplay=True)
playlist.browse(arg=arg, menuw=menuw)
+
def file_play_all_by_artist(self, arg=None, menuw=None):
kwargs = {}
try:
@@ -321,5 +490,5 @@
#file.write(m3u)
#print '\n'.join(filenames)
#items = [kaa.beacon.query(filename=f) for f in filenames]
- playlist = Playlist('Music by '+songInfo['artist'],
playlist=filenames, display_type="audio", autoplay=True)
+ playlist = Playlist(songInfo['artist'], playlist=filenames,
display_type="audio", autoplay=True)
playlist.browse(arg=arg, menuw=menuw)
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog