tags 496506 + patch thanks Package: rhythmbox Version: 0.11.6-1 Followup-For: Bug #496506
Hi. The attached patch should solve this issue. Please include an updated coherence plugin by applying this patch. Hope this helps. -- System Information: Debian Release: 5.0 APT prefers testing APT policy: (990, 'testing'), (500, 'unstable') Architecture: i386 (i686) Kernel: Linux 2.6.26-1-686 (SMP w/1 CPU core) Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages rhythmbox depends on: ii dbus 1.2.1-4 simple interprocess messaging syst ii gconf2 2.22.0-1 GNOME configuration database syste ii gnome-icon-theme 2.22.0-1 GNOME Desktop icon theme ii gstreamer0.10-alsa [gs 0.10.19-2 GStreamer plugin for ALSA ii gstreamer0.10-gnomevfs 0.10.19-2 GStreamer plugin for GnomeVFS ii gstreamer0.10-plugins- 0.10.19-2 GStreamer plugins from the "base" ii gstreamer0.10-plugins- 0.10.8-4 GStreamer plugins from the "good" ii gstreamer0.10-x 0.10.19-2 GStreamer plugins for X11 and Pang ii libart-2.0-2 2.3.20-2 Library of functions for 2D graphi ii libatk1.0-0 1.22.0-1 The ATK accessibility toolkit ii libavahi-client3 0.6.22-3 Avahi client library ii libavahi-common3 0.6.22-3 Avahi common library ii libavahi-glib1 0.6.22-3 Avahi glib integration library ii libbonobo2-0 2.22.0-1 Bonobo CORBA interfaces library ii libbonoboui2-0 2.22.0-1 The Bonobo UI library ii libc6 2.7-16 GNU C Library: Shared libraries ii libcairo2 1.6.4-7 The Cairo 2D vector graphics libra ii libdbus-1-3 1.2.1-4 simple interprocess messaging syst ii libdbus-glib-1-2 0.76-1 simple interprocess messaging syst ii libexpat1 2.0.1-4 XML parsing C library - runtime li ii libfontconfig1 2.6.0-3 generic font configuration library ii libfreetype6 2.3.7-2 FreeType 2 font engine, shared lib ii libgconf2-4 2.22.0-1 GNOME configuration database syste ii libglade2-0 1:2.6.2-1 library to load .glade files at ru ii libglib2.0-0 2.16.6-1 The GLib library of C routines ii libgnome-keyring0 2.22.3-2 GNOME keyring services library ii libgnome-media0 2.22.0-3 runtime libraries for the GNOME me ii libgnome2-0 2.20.1.1-1 The GNOME 2 library - runtime file ii libgnomecanvas2-0 2.20.1.1-1 A powerful object-oriented display ii libgnomeui-0 2.20.1.1-2 The GNOME 2 libraries (User Interf ii libgnomevfs2-0 1:2.22.0-5 GNOME Virtual File System (runtime ii libgpod3 0.6.0-6 library to read and write songs an ii libgstreamer-plugins-b 0.10.19-2 GStreamer libraries from the "base ii libgstreamer0.10-0 0.10.19-3 Core GStreamer libraries and eleme ii libgtk2.0-0 2.12.11-4 The GTK+ graphical user interface ii libhal1 0.5.11-6 Hardware Abstraction Layer - share ii libice6 2:1.0.4-1 X11 Inter-Client Exchange library ii liblircclient0 0.8.3-3 infra-red remote control support - ii libmtp7 0.2.6.1-3 Media Transfer Protocol (MTP) libr ii libmusicbrainz4c2a 2.1.5-2 Second generation incarnation of t ii libnautilus-burn4 2.20.0-1 Nautilus Burn Library - runtime ve ii libnotify1 [libnotify1 0.4.4-3 sends desktop notifications to a n ii libnspr4-0d 4.7.1-4 NetScape Portable Runtime Library ii liborbit2 1:2.14.13-0.1 libraries for ORBit2 - a CORBA ORB ii libpango1.0-0 1.20.5-3 Layout and rendering of internatio ii libpixman-1-0 0.10.0-2 pixel-manipulation library for X a ii libpng12-0 1.2.27-2 PNG library - runtime ii libpopt0 1.14-4 lib for parsing cmdline parameters ii libsexy2 0.1.11-2+b1 collection of additional GTK+ widg ii libsm6 2:1.0.3-2 X11 Session Management library ii libsoup2.4-1 2.4.1-2 an HTTP library implementation in ii libtotem-plparser10 2.22.3-1 Totem Playlist Parser library - ru ii libusb-0.1-4 2:0.1.12-13 userspace USB programming library ii libx11-6 2:1.1.5-2 X11 client-side library ii libxcb-render-util0 0.2.1+git1-1 utility libraries for X C Binding ii libxcb-render0 1.1-1.1 X C Binding, render extension ii libxcb1 1.1-1.1 X C Binding ii libxcursor1 1:1.1.9-1 X cursor management library ii libxext6 2:1.0.4-1 X11 miscellaneous extension librar ii libxfixes3 1:4.0.3-2 X11 miscellaneous 'fixes' extensio ii libxi6 2:1.1.4-1 X11 Input extension library ii libxinerama1 2:1.0.3-2 X11 Xinerama extension library ii libxml2 2.6.32.dfsg-5 GNOME XML library ii libxrandr2 2:1.2.3-1 X11 RandR extension library ii libxrender1 1:0.9.4-2 X Rendering Extension client libra ii python 2.5.2-3 An interactive high-level object-o ii python-gnome2 2.22.0-1 Python bindings for the GNOME desk ii python-gtk2 2.12.1-6 Python bindings for the GTK+ widge ii python-support 0.8.4 automated rebuilding support for P ii python2.5 2.5.2-14 An interactive high-level object-o ii zlib1g 1:1.2.3.3.dfsg-12 compression library - runtime Versions of packages rhythmbox recommends: ii avahi-daemon 0.6.22-3 Avahi mDNS/DNS-SD daemon ii gnome-app-install 0.5.5.1-1 GNOME Application Installer ii gnome-control-center 1:2.22.2.1-2 utilities to configure the GNOME d ii gnome-volume-manager 2.22.1-1 GNOME daemon to auto-mount and man ii gstreamer0.10-plugins-ugly 0.10.8-1 GStreamer plugins from the "ugly" ii hal 0.5.11-6 Hardware Abstraction Layer ii libgnomevfs2-extra 1:2.22.0-5 GNOME Virtual File System (extra m ii notification-daemon 0.3.7-1+b1 a daemon that displays passive pop ii python-gst0.10 0.10.12-1.1 generic media-playing framework (P ii scrollkeeper 0.3.14-16 A free electronic cataloging syste ii sound-juicer 2.22.0-2 GNOME 2 CD Ripper ii yelp 2.22.1-8+b1 Help browser for GNOME 2 Versions of packages rhythmbox suggests: ii gstreamer0.10-plugins-bad 0.10.7-2 GStreamer plugins from the "bad" s ii python-coherence 0.5.8-1 Python UPnP framework -- no debconf information -- Olivier BERGER (OpenPGP: 1024D/B4C5F37F) http://www.olivierberger.com/weblog/
diff -Naur upnp_coherence.old/__init__.py upnp_coherence/__init__.py --- upnp_coherence.old/__init__.py 2008-12-22 15:12:08.000000000 +0100 +++ upnp_coherence/__init__.py 2008-07-14 16:08:06.000000000 +0200 @@ -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) diff -Naur upnp_coherence.old/MediaPlayer.py upnp_coherence/MediaPlayer.py --- upnp_coherence.old/MediaPlayer.py 2008-12-22 15:12:08.000000000 +0100 +++ upnp_coherence/MediaPlayer.py 2008-10-22 23:48:15.000000000 +0200 @@ -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: diff -Naur upnp_coherence.old/MediaStore.py upnp_coherence/MediaStore.py --- upnp_coherence.old/MediaStore.py 2008-12-22 15:12:08.000000000 +0100 +++ upnp_coherence/MediaStore.py 2008-07-14 16:08:06.000000000 +0200 @@ -5,17 +5,17 @@ # Copyright 2007, Frank Scholz <cohere...@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) diff -Naur upnp_coherence.old/UpnpSource.py upnp_coherence/UpnpSource.py --- upnp_coherence.old/UpnpSource.py 2008-12-22 15:12:08.000000000 +0100 +++ upnp_coherence/UpnpSource.py 2008-06-30 22:26:43.000000000 +0200 @@ -2,7 +2,7 @@ # http://opensource.org/licenses/mit-license.php # # Copyright 2007, James Livingston <doclivings...@gmail.com> -# Copyright 2007, Frank Scholz <cohere...@beebits.net> +# Copyright 2007,2008 Frank Scholz <cohere...@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)