rhythmbox r6002 - in trunk: . plugins/coherence/upnp_coherence
- From: hadess svn gnome org
- To: svn-commits-list gnome org
- Subject: rhythmbox r6002 - in trunk: . plugins/coherence/upnp_coherence
- Date: Mon, 27 Oct 2008 18:47:05 +0000 (UTC)
Author: hadess
Date: Mon Oct 27 18:47:05 2008
New Revision: 6002
URL: http://svn.gnome.org/viewvc/rhythmbox?rev=6002&view=rev
Log:
2008-10-27 Bastien Nocera <hadess hadess net>
* plugins/coherence/upnp_coherence/MediaPlayer.py:
* plugins/coherence/upnp_coherence/MediaStore.py:
* plugins/coherence/upnp_coherence/UpnpSource.py:
* plugins/coherence/upnp_coherence/__init__.py: Update the Coherence
plugin from Franz' code
Modified:
trunk/ChangeLog
trunk/plugins/coherence/upnp_coherence/MediaPlayer.py
trunk/plugins/coherence/upnp_coherence/MediaStore.py
trunk/plugins/coherence/upnp_coherence/UpnpSource.py
trunk/plugins/coherence/upnp_coherence/__init__.py
Modified: trunk/plugins/coherence/upnp_coherence/MediaPlayer.py
==============================================================================
--- trunk/plugins/coherence/upnp_coherence/MediaPlayer.py (original)
+++ trunk/plugins/coherence/upnp_coherence/MediaPlayer.py Mon Oct 27 18:47:05 2008
@@ -10,7 +10,7 @@
from coherence.upnp.core.soap_service import errorCode
from coherence.upnp.core import DIDLLite
-import louie
+import coherence.extern.louie as louie
from coherence.extern.simple_plugin import Plugin
@@ -26,7 +26,8 @@
logCategory = 'rb_media_renderer'
implements = ['MediaRenderer']
- vendor_value_defaults = {'RenderingControl': {'A_ARG_TYPE_Channel':'Master'}}
+ vendor_value_defaults = {'RenderingControl': {'A_ARG_TYPE_Channel':'Master'},
+ 'AVTransport': {'A_ARG_TYPE_SeekMode':('ABS_TIME','REL_TIME')}}
vendor_range_defaults = {'RenderingControl': {'Volume': {'maximum':100}}}
def __init__(self, device, **kwargs):
@@ -36,17 +37,9 @@
self.player = None
self.metadata = None
- self.host = '127.0.0.1'
self.name = "Rhythmbox on %s" % self.server.coherence.hostname
self.player = self.shell.get_player()
- self.player.connect ('playing-song-changed',
- self.playing_song_changed),
- self.player.connect ('playing-changed',
- self.playing_changed)
- self.player.connect ('elapsed-changed',
- self.elapsed_changed)
- self.player.connect("notify::volume", self.volume_changed)
louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)
self.playing = False
@@ -226,24 +219,31 @@
self.metadata = metadata
self.tags = {}
- if len(self.metadata)>0:
- elt = DIDLLite.DIDLElement.fromString(self.metadata)
+ was_playing = self.playing
+
+ if was_playing == True:
+ self.stop()
+
+ if len(metadata)>0:
+ elt = DIDLLite.DIDLElement.fromString(metadata)
if elt.numItems() == 1:
item = elt.getItems()[0]
- self.entry = self.shell.props.db.entry_lookup_by_location(uri)
- self.warning("check for entry %r %r", self.entry, item.server_uuid)
+ if uri.startswith('track-'):
+ self.entry = self.shell.props.db.entry_lookup_by_id(int(uri[6:]))
+ else:
+ self.entry = self.shell.props.db.entry_lookup_by_location(uri)
+ self.warning("check for entry %r %r %r", self.entry,item.server_uuid,uri)
if self.entry == None:
if item.server_uuid is not None:
entry_type = self.shell.props.db.entry_register_type("CoherenceUpnp:" + item.server_uuid)
self.entry = self.shell.props.db.entry_new(entry_type, uri)
self.warning("create new entry %r", self.entry)
else:
- self.shell.load_uri(uri,play=False)
- self.entry = self.shell.props.db.entry_lookup_by_location(uri)
+ entry_type = self.shell.props.db.entry_register_type("CoherencePlayer")
+ self.entry = self.shell.props.db.entry_new(entry_type, uri)
self.warning("load and check for entry %r", self.entry)
-
duration = None
size = None
bitrate = None
@@ -283,13 +283,20 @@
self.shell.props.db.set(self.entry, rhythmdb.PROP_FILE_SIZE,int(size))
else:
- self.shell.load_uri(uri,play=False)
- self.entry = self.shell.props.db.entry_lookup_by_location(uri)
+ if uri.startswith('track-'):
+ self.entry = self.shell.props.db.entry_lookup_by_id(int(uri[6:]))
+ else:
+ #self.shell.load_uri(uri,play=False)
+ #self.entry = self.shell.props.db.entry_lookup_by_location(uri)
+ entry_type = self.shell.props.db.entry_register_type("CoherencePlayer")
+ self.entry = self.shell.props.db.entry_new(entry_type, uri)
+
self.playing = False
+ self.metadata = metadata
connection_id = self.server.connection_manager_server.lookup_avt_id(self.current_connection_id)
- self.server.av_transport_server.set_variable(connection_id, 'CurrentTransportActions','Play,Stop,Pause')
+ self.server.av_transport_server.set_variable(connection_id, 'CurrentTransportActions','Play,Stop,Pause,Seek')
self.server.av_transport_server.set_variable(connection_id, 'NumberOfTracks',1)
self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackURI',uri)
self.server.av_transport_server.set_variable(connection_id, 'AVTransportURI',uri)
@@ -297,6 +304,9 @@
self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackURI',uri)
self.server.av_transport_server.set_variable(connection_id, 'CurrentTrackMetaData',metadata)
+ if was_playing == True:
+ self.play()
+
def start(self, uri):
self.load(uri)
self.play()
@@ -328,12 +338,15 @@
# self.server.connection_manager_server.lookup_avt_id(self.current_connection_id),\
# 'TransportState', 'PAUSED_PLAYBACK')
- def seek(self, location):
+ def seek(self, location, old_state):
"""
@param location: simple number = time to seek to, in seconds
+nL = relative seek forward n seconds
-nL = relative seek backwards n seconds
"""
+ self.warning("player seek %r", location)
+ self.player.seek(location)
+ self.server.av_transport_server.set_variable(0, 'TransportState', old_state)
def mute(self):
self.muted_volume = self.volume
@@ -368,9 +381,17 @@
self.player.set_volume(float(volume/100.0))
def upnp_init(self):
+ self.player.connect ('playing-song-changed',
+ self.playing_song_changed),
+ self.player.connect ('playing-changed',
+ self.playing_changed)
+ self.player.connect ('elapsed-changed',
+ self.elapsed_changed)
+ self.player.connect("notify::volume", self.volume_changed)
+
self.current_connection_id = None
self.server.connection_manager_server.set_variable(0, 'SinkProtocolInfo',
- ['internal:%s:*:*' % self.host,
+ ['rhythmbox:%s:audio/mpeg:*' % self.server.coherence.hostname,
'http-get:*:audio/mpeg:*'],
default=True)
self.server.av_transport_server.set_variable(0, 'TransportState', 'NO_MEDIA_PRESENT', default=True)
@@ -396,6 +417,18 @@
self.stop()
return {}
+ def upnp_Seek(self, *args, **kwargs):
+ InstanceID = int(kwargs['InstanceID'])
+ Unit = kwargs['Unit']
+ Target = kwargs['Target']
+ if Unit in ['ABS_TIME','REL_TIME']:
+ old_state = self.server.av_transport_server.get_variable(0, 'TransportState')
+ self.server.av_transport_server.set_variable(0, 'TransportState', 'TRANSITIONING')
+ h,m,s = Target.split(':')
+ seconds = int(h)*3600 + int(m)*60 + int(s)
+ self.seek(seconds, old_state)
+ return {}
+
def upnp_SetAVTransportURI(self, *args, **kwargs):
InstanceID = int(kwargs['InstanceID'])
CurrentURI = kwargs['CurrentURI']
@@ -404,12 +437,13 @@
#print '>>>', local_protocol_infos
if len(CurrentURIMetaData)==0:
self.load(CurrentURI,CurrentURIMetaData)
+ return {}
else:
elt = DIDLLite.DIDLElement.fromString(CurrentURIMetaData)
#import pdb; pdb.set_trace()
if elt.numItems() == 1:
item = elt.getItems()[0]
- res = item.res.get_matching(local_protocol_infos, protocol_type='internal')
+ res = item.res.get_matching(local_protocol_infos, protocol_type='rhythmbox')
if len(res) == 0:
res = item.res.get_matching(local_protocol_infos)
if len(res) > 0:
Modified: trunk/plugins/coherence/upnp_coherence/MediaStore.py
==============================================================================
--- trunk/plugins/coherence/upnp_coherence/MediaStore.py (original)
+++ trunk/plugins/coherence/upnp_coherence/MediaStore.py Mon Oct 27 18:47:05 2008
@@ -5,17 +5,17 @@
# Copyright 2007, Frank Scholz <coherence beebits net>
import rhythmdb
-import louie
+import coherence.extern.louie as louie
import urllib
from coherence.upnp.core import DIDLLite
-from coherence import log
+from coherence.backend import BackendItem, BackendStore
ROOT_CONTAINER_ID = 0
-AUDIO_CONTAINER = 10
-AUDIO_ALL_CONTAINER_ID = 11
-AUDIO_ARTIST_CONTAINER_ID = 12
-AUDIO_ALBUM_CONTAINER_ID = 13
+AUDIO_CONTAINER = 100
+AUDIO_ALL_CONTAINER_ID = 101
+AUDIO_ARTIST_CONTAINER_ID = 102
+AUDIO_ALBUM_CONTAINER_ID = 103
CONTAINER_COUNT = 10000
@@ -23,7 +23,7 @@
# most of this class is from Coherence, originally under the MIT licence
-class Container(log.Loggable):
+class Container(BackendItem):
logCategory = 'rb_media_store'
@@ -46,7 +46,7 @@
def get_children(self,start=0,request_count=0):
if callable(self.children):
- children = self.children()
+ children = self.children(self.id)
else:
children = self.children
@@ -57,13 +57,9 @@
return children[start:request_count]
def get_child_count(self):
+ return len(self.get_children())
- if callable(self.children):
- return len(self.children())
- else:
- return len(self.children)
-
- def get_item(self):
+ def get_item(self, parent_id=None):
self.item.childCount = self.get_child_count()
return self.item
@@ -74,11 +70,11 @@
return self.id
-class Album(log.Loggable):
+class Album(BackendItem):
logCategory = 'rb_media_store'
- def __init__(self, store, title, id):
+ def __init__(self, store, title, id, parent_id):
self.id = id
self.title = title
self.store = store
@@ -103,7 +99,7 @@
def collate (model, path, iter):
self.info("Album get_children %r %r %r" %(model, path, iter))
id = model.get(iter, 0)[0]
- children.append(Track(self.store,id))
+ children.append(Track(self.store,id,self.id))
self.tracks_per_album_query.foreach(collate)
@@ -117,8 +113,8 @@
def get_child_count(self):
return len(self.get_children())
- def get_item(self):
- item = DIDLLite.MusicAlbum(self.id, AUDIO_ALBUM_CONTAINER_ID, self.title)
+ def get_item(self, parent_id = AUDIO_ALBUM_CONTAINER_ID):
+ item = DIDLLite.MusicAlbum(self.id, parent_id, self.title)
return item
def get_id(self):
@@ -131,11 +127,11 @@
return self.cover
-class Artist(log.Loggable):
+class Artist(BackendItem):
logCategory = 'rb_media_store'
- def __init__(self, store, name, id):
+ def __init__(self, store, name, id, parent_id):
self.id = id
self.name = name
self.store = store
@@ -173,8 +169,8 @@
def get_child_count(self):
return len(self.get_children())
- def get_item(self):
- item = DIDLLite.MusicArtist(self.id, AUDIO_ARTIST_CONTAINER_ID, self.name)
+ def get_item(self, parent_id = AUDIO_ARTIST_CONTAINER_ID):
+ item = DIDLLite.MusicArtist(self.id, parent_id, self.name)
return item
def get_id(self):
@@ -184,16 +180,17 @@
return self.name
-class Track(log.Loggable):
+class Track(BackendItem):
logCategory = 'rb_media_store'
- def __init__(self, store, id):
+ def __init__(self, store, id, parent_id):
self.store = store
if type(id) == int:
self.id = id
else:
self.id = self.store.db.entry_get (id, rhythmdb.PROP_ENTRY_ID)
+ self.parent_id = parent_id
def get_children(self, start=0, request_count=0):
return []
@@ -201,9 +198,9 @@
def get_child_count(self):
return 0
- def get_item(self):
+ def get_item(self, parent_id=None):
- self.info("Track get_item %r" %(self.id))
+ self.info("Track get_item %r @ %r" %(self.id,self.parent_id))
host = ""
@@ -226,9 +223,17 @@
mimetype = "audio/mpeg"
size = self.store.db.entry_get(entry, rhythmdb.PROP_FILE_SIZE)
+ album = self.store.db.entry_get(entry, rhythmdb.PROP_ALBUM)
+ if self.parent_id == None:
+ try:
+ self.parent_id = self.store.albums[album].id
+ except:
+ pass
+
# create item
- item = DIDLLite.MusicTrack(self.id + TRACK_COUNT)
- item.album = self.store.db.entry_get(entry, rhythmdb.PROP_ALBUM)
+ item = DIDLLite.MusicTrack(self.id + TRACK_COUNT,self.parent_id)
+ item.album = album
+
item.artist = self.store.db.entry_get(entry, rhythmdb.PROP_ARTIST)
#item.date =
item.genre = self.store.db.entry_get(entry, rhythmdb.PROP_GENRE)
@@ -239,13 +244,6 @@
#self.warning("cover for %r is %r", item.title, cover)
#item.albumArtURI = ## can we somehow store art in the upnp share??
- # add internal resource
- #res = DIDLLite.Resource(location, 'internal:%s:%s:*' % (host, mimetype))
- #res.size = size
- #res.duration = duration
- #res.bitrate = bitrate
- #item.res.append(res)
-
# add http resource
res = DIDLLite.Resource(self.get_url(), 'http-get:*:%s:*' % mimetype)
if size > 0:
@@ -256,6 +254,16 @@
res.bitrate = str(bitrate)
item.res.append(res)
+ # add internal resource
+ res = DIDLLite.Resource('track-%d' % self.id, 'rhythmbox:%s:%s:*' % (self.store.server.coherence.hostname, mimetype))
+ if size > 0:
+ res.size = size
+ if duration > 0:
+ res.duration = str(duration)
+ if bitrate > 0:
+ res.bitrate = str(bitrate)
+ item.res.append(res)
+
return item
def get_id(self):
@@ -280,17 +288,22 @@
return location
-class MediaStore(log.Loggable):
+class MediaStore(BackendStore):
logCategory = 'rb_media_store'
implements = ['MediaServer']
def __init__(self, server, **kwargs):
- print "creating UPnP MediaStore"
+ self.warning("__init__ MediaStore %r", kwargs)
self.server = server
self.db = kwargs['db']
self.plugin = kwargs['plugin']
+ self.wmc_mapping.update({'4': lambda : self.get_by_id(AUDIO_ALL_CONTAINER_ID), # all tracks
+ '7': lambda : self.get_by_id(AUDIO_ALBUM_CONTAINER_ID), # all albums
+ '6': lambda : self.get_by_id(AUDIO_ARTIST_CONTAINER_ID), # all artists
+ })
+
self.update_id = 0
self.next_id = CONTAINER_COUNT
@@ -340,11 +353,16 @@
def get_by_id(self,id):
self.info("looking for id %r", id)
- id = int(id)
- if id < TRACK_COUNT:
- item = self.containers[id]
+ id = id.split('@',1)
+ item_id = id[0]
+ item_id = int(item_id)
+ if item_id < TRACK_COUNT:
+ try:
+ item = self.containers[item_id]
+ except KeyError:
+ item = None
else:
- item = Track(self, (id - TRACK_COUNT))
+ item = Track(self, (item_id - TRACK_COUNT),None)
return item
@@ -356,24 +374,26 @@
def upnp_init(self):
if self.server:
self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo', [
- #'internal:%s:*:*' % self.name,
+ 'rhythmbox:%s:*:*' % self.server.coherence.hostname,
'http-get:*:audio/mpeg:*',
])
+ self.warning("__init__ MediaStore initialized")
+
- def children_tracks(self):
+ def children_tracks(self, parent_id):
tracks = []
def track_cb (entry):
if self.db.entry_get (entry, rhythmdb.PROP_HIDDEN):
return
id = self.db.entry_get (entry, rhythmdb.PROP_ENTRY_ID)
- track = Track(self, id)
+ track = Track(self, id, parent_id)
tracks.append(track)
self.db.entry_foreach_by_type (self.db.entry_type_get_by_name('song'), track_cb)
return tracks
- def children_albums(self):
+ def children_albums(self,parent_id):
albums = {}
self.info('children_albums')
@@ -389,7 +409,7 @@
self.info("children_albums collate %r %r", name, priority)
if priority is False:
id = self.get_next_container_id()
- album = Album(self, name, id)
+ album = Album(self, name, id,parent_id)
self.containers[id] = album
albums[name] = album
@@ -401,7 +421,7 @@
albums.sort(cmp=album_sort)
return albums
- def children_artists(self,killbug=False):
+ def children_artists(self,parent_id):
artists = []
self.info('children_artists')
@@ -411,7 +431,7 @@
priority = model.get(iter, 1)[0]
if priority is False:
id = self.get_next_container_id()
- artist = Artist(self,name, id)
+ artist = Artist(self,name, id,parent_id)
self.containers[id] = artist
artists.append(artist)
Modified: trunk/plugins/coherence/upnp_coherence/UpnpSource.py
==============================================================================
--- trunk/plugins/coherence/upnp_coherence/UpnpSource.py (original)
+++ trunk/plugins/coherence/upnp_coherence/UpnpSource.py Mon Oct 27 18:47:05 2008
@@ -2,7 +2,7 @@
# http://opensource.org/licenses/mit-license.php
#
# Copyright 2007, James Livingston <doclivingston gmail com>
-# Copyright 2007, Frank Scholz <coherence beebits net>
+# Copyright 2007,2008 Frank Scholz <coherence beebits net>
import rb, rhythmdb
import gobject, gtk
@@ -10,6 +10,7 @@
from coherence import __version_info__ as coherence_version
from coherence import log
+from coherence.upnp.core import DIDLLite
class UpnpSource(rb.BrowserSource,log.Loggable):
@@ -18,7 +19,7 @@
__gproperties__ = {
'plugin': (rb.Plugin, 'plugin', 'plugin', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
'client': (gobject.TYPE_PYOBJECT, 'client', 'client', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
- 'usn': (gobject.TYPE_PYOBJECT, 'usn', 'usn', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
+ 'udn': (gobject.TYPE_PYOBJECT, 'udn', 'udn', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
}
def __init__(self):
@@ -37,8 +38,8 @@
elif property.name == 'client':
self.__client = value
self.props.name = self.__client.device.get_friendly_name()
- elif property.name == 'usn':
- self.__usn = value
+ elif property.name == 'udn':
+ self.__udn = value
else:
raise AttributeError, 'unknown property %s' % property.name
@@ -59,15 +60,12 @@
def load_db(self, id):
- if coherence_version < (0,5,1):
- d = self.__client.content_directory.browse(id, browse_flag='BrowseDirectChildren', backward_compatibility=False)
- else:
- d = self.__client.content_directory.browse(id, browse_flag='BrowseDirectChildren', process_result=False, backward_compatibility=False)
- d.addCallback(self.process_media_server_browse, self.__usn)
+ d = self.__client.content_directory.browse(id, browse_flag='BrowseDirectChildren', process_result=False, backward_compatibility=False)
+ d.addCallback(self.process_media_server_browse, self.__udn)
- def state_variable_change(self, variable, usn=None):
- print "%s changed from %s to %s" % (variable.name, variable.old_value, variable.value)
+ def state_variable_change(self, variable, udn=None):
+ self.info("%s changed from >%s< to >%s<", variable.name, variable.old_value, variable.value)
if variable.old_value == '':
return
@@ -79,12 +77,13 @@
container = changes.pop(0).strip()
update_id = changes.pop(0).strip()
if container in self.container_watch:
- print "we have a change in %s, container needs a reload" % container
+ self.info("we have a change in %r, container needs a reload", container)
self.load_db(container)
- def new_process_media_server_browse(self, results, usn):
- for item in results:
+ def new_process_media_server_browse(self, results, udn):
+ didl = DIDLLite.DIDLElement.fromString(results['Result'])
+ for item in didl.getItems():
self.info("process_media_server_browse %r %r", item.id, item)
if item.upnp_class.startswith('object.container'):
self.load_db(item.id)
@@ -142,39 +141,4 @@
self.__db.commit()
-
- def old_process_media_server_browse(self, results, usn):
- for k,v in results.iteritems():
- if k == 'items':
- for id, values in v.iteritems():
- if values['upnp_class'].startswith('object.container'):
- self.load_db(id)
- if values['upnp_class'].startswith('object.item.audioItem'):
- # (url, [method, something which is in asterix, format, semicolon delimited key=value map of something])
- resources = [(k, v.split(':')) for (k, v) in values['resources'].iteritems()]
- # break data into map
- for r in resources:
- if r[1][3] is not '*':
- r[1][3] = dict([v.split('=') for v in r[1][3].split(';')])
- else:
- r[1][3] = dict()
-
- url = None
- for r in resources:
- if r[1][3].has_key('DLNA.ORG_CI') and r[1][3]['DLNA.ORG_CI'] is not '1':
- url = r[0]
- break
-
- if url is None:
- # use transcoded format, since we can't find a normal one
- url = resources[0][0]
-
- entry = self.__db.entry_lookup_by_location (url)
- if entry == None:
- entry = self.__db.entry_new(self.__entry_type, url)
-
- self.__db.set(entry, rhythmdb.PROP_TITLE, values['title'])
-
- self.__db.commit()
-
gobject.type_register(UpnpSource)
Modified: trunk/plugins/coherence/upnp_coherence/__init__.py
==============================================================================
--- trunk/plugins/coherence/upnp_coherence/__init__.py (original)
+++ trunk/plugins/coherence/upnp_coherence/__init__.py Mon Oct 27 18:47:05 2008
@@ -10,7 +10,7 @@
import rhythmdb, rb
import gobject, gtk
-import louie
+import coherence.extern.louie as louie
from coherence import log
@@ -117,7 +117,7 @@
def get_coherence (self):
coherence_instance = None
- required_version = (0, 3, 2)
+ required_version = (0, 5, 7)
try:
from coherence.base import Coherence
@@ -143,15 +143,15 @@
return coherence_instance
- def removed_media_server(self, usn):
- print "upnp server went away %s" % usn
- if self.sources.has_key(usn):
- self.sources[usn].delete_thyself()
- del self.sources[usn]
-
- def detected_media_server(self, client, usn):
- print "found upnp server %s (%s)" % (client.device.get_friendly_name(), usn)
- self.warning("found upnp server %s (%s)" % (client.device.get_friendly_name(), usn))
+ def removed_media_server(self, udn):
+ print "upnp server went away %s" % udn
+ if self.sources.has_key(udn):
+ self.sources[udn].delete_thyself()
+ del self.sources[udn]
+
+ def detected_media_server(self, client, udn):
+ print "found upnp server %s (%s)" % (client.device.get_friendly_name(), udn)
+ self.warning("found upnp server %s (%s)" % (client.device.get_friendly_name(), udn))
if client.device.get_id() == self.uuid:
""" don't react on our own MediaServer"""
return
@@ -167,8 +167,8 @@
source_group=group,
plugin=self,
client=client,
- usn=usn)
+ udn=udn)
- self.sources[usn] = source
+ self.sources[udn] = source
self.shell.append_source (source, None)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]