~titan-lien/ubuntu/saucy/totem/totem.dev

« back to all changes in this revision

Viewing changes to src/plugins/dbusservice/dbusservice.py

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Sjoerd Simons, Michael Biebl, Josselin Mouette
  • Date: 2011-11-27 06:21:34 UTC
  • mfrom: (1.4.8) (5.1.23 sid)
  • Revision ID: package-import@ubuntu.com-20111127062134-c3ikko9wdfn9m2av
Tags: 3.2.1-1
[ Sjoerd Simons ]
* New upstream release
* debian/control.in: Update build-depends
* debian/rules: Enable vala plugins
* debian/totem-plugins.install:
  - Add grilo and rotation plugins
  - Remove jamendo, thumbnail and tracker plugins

[ Michael Biebl ]
* debian/control.in:
  - Bump Depends on python-gobject to (>= 2.90.3).

[ Josselin Mouette ]
* Replace python-gobject dependencies by python-gi.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
## Totem D-Bus plugin
 
4
## Copyright (C) 2009 Lucky <lucky1.data@gmail.com>
 
5
## Copyright (C) 2009 Philip Withnall <philip@tecnocode.co.uk>
 
6
##
 
7
## This program is free software; you can redistribute it and/or modify
 
8
## it under the terms of the GNU General Public License as published by
 
9
## the Free Software Foundation; either version 2 of the License, or
 
10
## (at your option) any later version.
 
11
##
 
12
## This program is distributed in the hope that it will be useful,
 
13
## but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
## GNU General Public License for more details.
 
16
##
 
17
## You should have received a copy of the GNU General Public License
 
18
## along with this program; if not, write to the Free Software
 
19
## Foundation, Inc., 51 Franklin St, Fifth Floor,
 
20
## Boston, MA 02110-1301  USA.
 
21
##
 
22
## Sunday 13th May 2007: Bastien Nocera: Add exception clause.
 
23
## See license_change file for details.
 
24
 
 
25
import gettext
 
26
from gi.repository import GObject, Peas, Totem # pylint: disable-msg=E0611
 
27
import dbus, dbus.service
 
28
from dbus.mainloop.glib import DBusGMainLoop
 
29
 
 
30
gettext.textdomain ("totem")
 
31
_ = gettext.gettext
 
32
 
 
33
class DbusService (GObject.Object, Peas.Activatable):
 
34
    __gtype_name__ = 'DbusService'
 
35
 
 
36
    object = GObject.property (type = GObject.Object)
 
37
 
 
38
    def __init__ (self):
 
39
        GObject.Object.__init__ (self)
 
40
 
 
41
        self.root = None
 
42
 
 
43
    def do_activate (self):
 
44
        DBusGMainLoop (set_as_default = True)
 
45
 
 
46
        name = dbus.service.BusName ('org.mpris.MediaPlayer2.totem',
 
47
                                     bus = dbus.SessionBus ())
 
48
        self.root = Root (name, self.object)
 
49
 
 
50
    def do_deactivate (self):
 
51
        # Ensure we don't leak our paths on the bus
 
52
        self.root.disconnect ()
 
53
 
 
54
class Root (dbus.service.Object): # pylint: disable-msg=R0923,R0904
 
55
    def __init__ (self, name, totem):
 
56
        dbus.service.Object.__init__ (self, name, '/org/mpris/MediaPlayer2')
 
57
        self.totem = totem
 
58
 
 
59
        self.null_metadata = {
 
60
            'year' : '', 'tracknumber' : '', 'location' : '',
 
61
            'title' : '', 'album' : '', 'time' : '', 'genre' : '',
 
62
            'artist' : ''
 
63
        }
 
64
        self.current_metadata = self.null_metadata.copy ()
 
65
        self.current_position = 0
 
66
 
 
67
        totem.connect ('metadata-updated', self.__do_update_metadata)
 
68
        totem.connect ('notify::playing', self.__do_notify_playing)
 
69
        totem.connect ('notify::seekable', self.__do_notify_seekable)
 
70
        totem.connect ('notify::current-mrl', self.__do_notify_current_mrl)
 
71
        totem.connect ('notify::current-time', self.__do_notify_current_time)
 
72
 
 
73
    def disconnect (self):
 
74
        self.totem.disconnect_by_func (self.__do_notify_current_time)
 
75
        self.totem.disconnect_by_func (self.__do_notify_current_mrl)
 
76
        self.totem.disconnect_by_func (self.__do_notify_seekable)
 
77
        self.totem.disconnect_by_func (self.__do_notify_playing)
 
78
        self.totem.disconnect_by_func (self.__do_update_metadata)
 
79
 
 
80
        self.__do_update_metadata (self.totem, '', '', '', 0)
 
81
 
 
82
        self.remove_from_connection (None, None)
 
83
 
 
84
    def __calculate_playback_status (self):
 
85
        if self.totem.is_playing ():
 
86
            return 'Playing'
 
87
        elif self.totem.is_paused ():
 
88
            return 'Paused'
 
89
        else:
 
90
            return 'Stopped'
 
91
 
 
92
    def __calculate_metadata (self):
 
93
        metadata = {
 
94
            'mpris:trackid': dbus.String (self.totem.props.current_mrl,
 
95
                variant_level = 1),
 
96
            'mpris:length': dbus.Int64 (
 
97
                self.totem.props.stream_length * 1000L,
 
98
                variant_level = 1),
 
99
        }
 
100
 
 
101
        if self.current_metadata['title'] != '':
 
102
            metadata['xesam:title'] = dbus.String (
 
103
                self.current_metadata['title'], variant_level = 1)
 
104
 
 
105
        if self.current_metadata['artist'] != '':
 
106
            metadata['xesam:artist'] = dbus.Array (
 
107
                [ self.current_metadata['artist'] ], variant_level = 1)
 
108
 
 
109
        if self.current_metadata['album'] != '':
 
110
            metadata['xesam:album'] = dbus.String (
 
111
                self.current_metadata['album'], variant_level = 1)
 
112
 
 
113
        if self.current_metadata['tracknumber'] != '':
 
114
            metadata['xesam:trackNumber'] = dbus.Int32 (
 
115
                self.current_metadata['tracknumber'], variant_level = 1)
 
116
 
 
117
        return metadata
 
118
 
 
119
    def __do_update_metadata (self, totem, artist, # pylint: disable-msg=R0913
 
120
                              title, album, num):
 
121
        self.current_metadata = self.null_metadata.copy ()
 
122
        if title:
 
123
            self.current_metadata['title'] = title
 
124
        if artist:
 
125
            self.current_metadata['artist'] = artist
 
126
        if album:
 
127
            self.current_metadata['album'] = album
 
128
        if num:
 
129
            self.current_metadata['tracknumber'] = num
 
130
 
 
131
        self.PropertiesChanged ('org.mpris.MediaPlayer2.Player',
 
132
            { 'Metadata': self.__calculate_metadata () }, [])
 
133
 
 
134
    def __do_notify_playing (self, totem, prop):
 
135
        self.PropertiesChanged ('org.mpris.MediaPlayer2.Player',
 
136
            { 'PlaybackStatus': self.__calculate_playback_status () }, [])
 
137
 
 
138
    def __do_notify_current_mrl (self, totem, prop):
 
139
        self.PropertiesChanged ('org.mpris.MediaPlayer2.Player', {
 
140
            'CanPlay': (self.totem.props.current_mrl != None),
 
141
            'CanPause': (self.totem.props.current_mrl != None),
 
142
            'CanSeek': (self.totem.props.current_mrl != None and
 
143
                        self.totem.props.seekable),
 
144
        }, [])
 
145
 
 
146
    def __do_notify_seekable (self, totem, prop):
 
147
        self.PropertiesChanged ('org.mpris.MediaPlayer2.Player', {
 
148
            'CanSeek': (self.totem.props.current_mrl != None and
 
149
                        self.totem.props.seekable),
 
150
        }, [])
 
151
 
 
152
    def __do_notify_current_time (self, totem, prop):
 
153
        # Only notify of seeks if we've skipped more than 3 seconds
 
154
        if abs (totem.props.current_time - self.current_position) > 3:
 
155
            self.Seeked (totem.props.current_time * 1000L)
 
156
 
 
157
        self.current_position = totem.props.current_time
 
158
 
 
159
    # org.freedesktop.DBus.Properties interface
 
160
    @dbus.service.method (dbus_interface = dbus.PROPERTIES_IFACE,
 
161
                          in_signature = 'ss', # pylint: disable-msg=C0103
 
162
                          out_signature = 'v')
 
163
    def Get (self, interface_name, property_name):
 
164
        return self.GetAll (interface_name)[property_name]
 
165
 
 
166
    @dbus.service.method (dbus_interface = dbus.PROPERTIES_IFACE,
 
167
                          in_signature = 's', # pylint: disable-msg=C0103
 
168
                          out_signature = 'a{sv}')
 
169
    def GetAll (self, interface_name):
 
170
        if interface_name == 'org.mpris.MediaPlayer2':
 
171
            return {
 
172
                'CanQuit': True,
 
173
                'CanRaise': True,
 
174
                'HasTrackList': False,
 
175
                'Identity': self.totem.get_version (),
 
176
                'DesktopEntry': 'totem',
 
177
                'SupportedUriSchemes': self.totem.get_supported_uri_schemes (),
 
178
                'SupportedMimeTypes': self.totem.get_supported_content_types (),
 
179
            }
 
180
        elif interface_name == 'org.mpris.MediaPlayer2.Player':
 
181
            # Loop status (we don't support Track)
 
182
            if self.totem.action_remote_get_setting (
 
183
                Totem.RemoteSetting.REPEAT):
 
184
                loop_status = 'Playlist'
 
185
            else:
 
186
                loop_status = 'None'
 
187
 
 
188
            # Shuffle
 
189
            shuffle = self.totem.action_remote_get_setting (
 
190
                Totem.RemoteSetting.SHUFFLE)
 
191
 
 
192
            return {
 
193
                'PlaybackStatus': self.__calculate_playback_status (),
 
194
                'LoopStatus': loop_status, # TODO: Notifications
 
195
                'Rate': 1.0,
 
196
                'MinimumRate': 1.0,
 
197
                'MaximumRate': 1.0,
 
198
                'Shuffle': shuffle, # TODO: Notifications
 
199
                'Metadata': self.__calculate_metadata (),
 
200
                'Volume': self.totem.get_volume (), # TODO: Notifications
 
201
                'Position': self.totem.props.current_time * 1000L,
 
202
                'CanGoNext': True, # TODO
 
203
                'CanGoPrevious': True, # TODO
 
204
                'CanPlay': (self.totem.props.current_mrl != None),
 
205
                'CanPause': (self.totem.props.current_mrl != None),
 
206
                'CanSeek': (self.totem.props.current_mrl != None and
 
207
                            self.totem.props.seekable),
 
208
                'CanControl': True,
 
209
            }
 
210
 
 
211
        raise dbus.exceptions.DBusException (
 
212
            'org.mpris.MediaPlayer2.UnknownInterface',
 
213
            _(u'The MediaPlayer2 object does not implement the ‘%s’ interface')
 
214
                % interface_name)
 
215
 
 
216
    @dbus.service.method (dbus_interface = dbus.PROPERTIES_IFACE,
 
217
                          in_signature = 'ssv') # pylint: disable-msg=C0103
 
218
    def Set (self, interface_name, property_name, new_value):
 
219
        if interface_name == 'org.mpris.MediaPlayer2':
 
220
            raise dbus.exceptions.DBusException (
 
221
                'org.mpris.MediaPlayer2.ReadOnlyProperty',
 
222
                _(u'The property ‘%s’ is not writeable.'))
 
223
        elif interface_name == 'org.mpris.MediaPlayer2.Player':
 
224
            if property_name == 'LoopStatus':
 
225
                self.totem.action_remote_set_setting (
 
226
                    Totem.RemoteSetting.REPEAT, (new_value == 'Playlist'))
 
227
            elif property_name == 'Rate':
 
228
                # Ignore, since we don't support setting the rate
 
229
                pass
 
230
            elif property_name == 'Shuffle':
 
231
                self.totem.action_remote_set_setting (
 
232
                    Totem.RemoteSetting.SHUFFLE, new_value)
 
233
            elif property_name == 'Volume':
 
234
                self.totem.action_volume (new_value)
 
235
 
 
236
            raise dbus.exceptions.DBusException (
 
237
                'org.mpris.MediaPlayer2.ReadOnlyProperty',
 
238
                _(u'Unknown property ‘%s’ requested of a MediaPlayer 2 object')
 
239
                    % interface_name)
 
240
 
 
241
        raise dbus.exceptions.DBusException (
 
242
            'org.mpris.MediaPlayer2.UnknownInterface',
 
243
            _(u'The MediaPlayer2 object does not implement the ‘%s’ interface')
 
244
                % interface_name)
 
245
 
 
246
    @dbus.service.signal (dbus_interface = dbus.PROPERTIES_IFACE,
 
247
                          signature = 'sa{sv}as') # pylint: disable-msg=C0103
 
248
    def PropertiesChanged (self, interface_name, changed_properties,
 
249
                           invalidated_properties):
 
250
        pass
 
251
 
 
252
    # org.mpris.MediaPlayer2 interface
 
253
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2',
 
254
                          in_signature = '', # pylint: disable-msg=C0103
 
255
                          out_signature = '')
 
256
    def Raise (self):
 
257
        main_window = self.totem.get_main_window ()
 
258
        main_window.present ()
 
259
 
 
260
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2',
 
261
                          in_signature = '', # pylint: disable-msg=C0103
 
262
                          out_signature = '')
 
263
    def Quit (self):
 
264
        self.totem.action_exit ()
 
265
 
 
266
    # org.mpris.MediaPlayer2.Player interface
 
267
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
268
                          in_signature = '', # pylint: disable-msg=C0103
 
269
                          out_signature = '')
 
270
    def Next (self):
 
271
        if self.totem.is_playing () or self.totem.is_paused ():
 
272
            return
 
273
 
 
274
        self.totem.action_next ()
 
275
 
 
276
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
277
                          in_signature = '', # pylint: disable-msg=C0103
 
278
                          out_signature = '')
 
279
    def Previous (self):
 
280
        if self.totem.is_playing () or self.totem.is_paused ():
 
281
            return
 
282
 
 
283
        self.totem.action_previous ()
 
284
 
 
285
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
286
                          in_signature = '', # pylint: disable-msg=C0103
 
287
                          out_signature = '')
 
288
    def Pause (self):
 
289
        self.totem.action_pause ()
 
290
 
 
291
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
292
                          in_signature = '', # pylint: disable-msg=C0103
 
293
                          out_signature = '')
 
294
    def PlayPause (self):
 
295
        self.totem.action_play_pause ()
 
296
 
 
297
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
298
                          in_signature = '', # pylint: disable-msg=C0103
 
299
                          out_signature = '')
 
300
    def Stop (self):
 
301
        self.totem.action_stop ()
 
302
 
 
303
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
304
                          in_signature = '', # pylint: disable-msg=C0103
 
305
                          out_signature = '')
 
306
    def Play (self):
 
307
        # If playing or no track loaded: do nothing,
 
308
        # else: start playing.
 
309
        if self.totem.is_playing () or self.totem.props.current_mrl == None:
 
310
            return
 
311
 
 
312
        self.totem.action_play ()
 
313
 
 
314
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
315
                          in_signature = 'x', # pylint: disable-msg=C0103
 
316
                          out_signature = '')
 
317
    def Seek (self, offset):
 
318
        self.totem.action_seek_relative (offset / 1000L, False)
 
319
 
 
320
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
321
                          in_signature = 'ox', # pylint: disable-msg=C0103
 
322
                          out_signature = '')
 
323
    def SetPosition (self, track_id, position):
 
324
        position = position / 1000L
 
325
 
 
326
        # Bail if the position is not in the permitted range
 
327
        if position < 0 or position > self.totem.props.stream_length:
 
328
            return
 
329
 
 
330
        self.totem.action_seek_time (position, False)
 
331
 
 
332
    @dbus.service.method (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
333
                          in_signature = 's', # pylint: disable-msg=C0103
 
334
                          out_signature = '')
 
335
    def OpenUri (self, uri):
 
336
        if self.totem.action_set_mrl (uri):
 
337
            self.totem.action_play ()
 
338
 
 
339
        raise dbus.exceptions.DBusException (
 
340
            'org.mpris.MediaPlayer2.InvalidUri',
 
341
            _(u'The URI ‘%s’ is not supported.') % uri)
 
342
 
 
343
    @dbus.service.signal (dbus_interface = 'org.mpris.MediaPlayer2.Player',
 
344
                          signature = 'x') # pylint: disable-msg=C0103
 
345
    def Seeked (self, position):
 
346
        pass