mpris.py 8.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/python
# -*- coding: utf8 -*-
#
# Copyright (C) 2006 Rafaël Carré <funman at videolanorg>
#
# $Id$
# 
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
# 
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
# 
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
#

23
#
24
25
26
# NOTE: this controller is a SAMPLE, and thus doesn't implement all the
# Media Player Remote Interface Specification (MPRIS for short) available at
# http://wiki.xmms2.xmms.se/index.php/Media_Player_Interfaces
27
#
28
29
# You'll need pygtk >= 2.10 to use gtk.StatusIcon
#
30
31
32
33
import dbus
import dbus.glib
import gtk
import gtk.glade
34
import gobject
35
36
37
import os

global position
38
global timer
39
40
global playing
playing = False
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
global shuffle
global repeat
global loop
#mpris doesn't support getting the status of these (at the moment)
shuffle = False
repeat = False
loop = False

global root
global player
global tracklist

global bus

def player_change(newname, a, b):
    if b != "" and "org.mpris." in newname:
        Connect(newname)

60
def itemchange_handler(item):
61
    gobject.timeout_add( 2000, timeset)
62
63
64
65
    try:
        a = item["artist"]
    except:
        a = ""
Rafaël Carré's avatar
Rafaël Carré committed
66
67
68
69
70
71
72
73
    try:
        t = item["title"]
    except:
        t = ""
    if t == "":
        t = item["URI"]
    l_artist.set_text(a)
    l_title.set_text(t)
74

75
#find the first media player available
76
77
78
79
80
81
def Connect(name):
    global root
    global player
    global tracklist
    global bus
    global playing
82

83
84
85
    root_o = bus.get_object(name, "/")
    player_o = bus.get_object(name, "/Player")
    tracklist_o = bus.get_object(name, "/TrackList")
86

87
88
89
    root = dbus.Interface(root_o, "org.freedesktop.MediaPlayer")
    tracklist  = dbus.Interface(tracklist_o, "org.freedesktop.MediaPlayer")
    player = dbus.Interface(player_o, "org.freedesktop.MediaPlayer")
90
    player_o.connect_to_signal("TrackChange", itemchange_handler, dbus_interface="org.freedesktop.MediaPlayer")
91
92
93
94
    if player.GetStatus() == 0:
        gobject.timeout_add( 2000, timeset)
        playing = True
    window.set_title(root.Identity())
95

96
#plays an element
97
def AddTrack(widget):
98
99
    mrl = e_mrl.get_text()
    if mrl != None and mrl != "":
100
        tracklist.AddTrack(mrl, True)
Rafaël Carré's avatar
Rafaël Carré committed
101
        e_mrl.set_text('')
102
103
104
    else:
        mrl = bt_file.get_filename()
        if mrl != None and mrl != "":
105
            tracklist.AddTrack("directory://" + mrl, True)
106
    update(0)
107

108
#basic control
109
def Next(widget):
110
    player.Next(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
111
112
113
    update(0)

def Prev(widget):
114
    player.Prev(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
115
116
117
    update(0)

def Stop(widget):
118
    player.Stop(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
119
120
    update(0)

121
#update status display
122
def update(widget):
123
    item = tracklist.GetMetadata(tracklist.GetCurrentTrack())
124
    vol.set_value(player.VolumeGet())
125
126
127
    try: 
        a = item["artist"]
    except:        a = ""
Rafaël Carré's avatar
Rafaël Carré committed
128
129
130
131
    try:
        t = item["title"]
    except:        t = ""
    if t == "":
132
133
134
135
        try:
            t = item["URI"]
        except:
            t = ""
Rafaël Carré's avatar
Rafaël Carré committed
136
137
    l_artist.set_text(a)
    l_title.set_text(t)
138
139
    GetPlayStatus(0)

140
#get playing status from remote player
141
def GetPlayStatus(widget):
Rafaël Carré's avatar
Rafaël Carré committed
142
    global playing
143
    status = player.GetStatus()
144
    if status == 0:
145
        img_bt_toggle.set_from_stock("gtk-media-pause", gtk.ICON_SIZE_SMALL_TOOLBAR)
Rafaël Carré's avatar
Rafaël Carré committed
146
        playing = True
147
148
    else:
        img_bt_toggle.set_from_stock("gtk-media-play", gtk.ICON_SIZE_SMALL_TOOLBAR)
Rafaël Carré's avatar
Rafaël Carré committed
149
        playing = False
150
151

def Quit(widget):
152
    player.Quit(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
Rafaël Carré's avatar
Rafaël Carré committed
153
    l_title.set_text("")
154

155
156
def Pause(widget):
    player.Pause()
157
158
159
    status = player.GetStatus()
    if status == 0:
        img_bt_toggle.set_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_SMALL_TOOLBAR)
160
        gobject.timeout_add( 2000, timeset)
161
162
    else:
        img_bt_toggle.set_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_SMALL_TOOLBAR)
163
164
    update(0)

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
def Repeat(widget):
    global repeat
    repeat = not repeat
    player.Repeat(repeat)

def Shuffle(widget):
    global shuffle
    shuffle = not shuffle
    tracklist.Random(shuffle)

def Loop(widget):
    global loop
    loop = not loop
    tracklist.Loop(loop)

180
#callback for volume
181
def volchange(widget, data):
182
    player.VolumeSet(vol.get_value_as_int(), reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
183

184
#callback for position change
185
def timechange(widget, x=None, y=None):
186
    player.PositionSet(int(time_s.get_value()), reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
187

188
#refresh position
189
def timeset():
190
    global playing
191
    time_s.set_value(player.PositionGet())
192
    return playing
Rafaël Carré's avatar
Rafaël Carré committed
193

194
#simple/full display
195
def expander(widget):
Rafaël Carré's avatar
Rafaël Carré committed
196
    if exp.get_expanded() == False:
197
198
199
200
        exp.set_label("Less")
    else:
        exp.set_label("More")

201
#close event
202
def delete_event(self, widget):
203
    self.hide()
204
205
206
207
208
209
210
211
212
213
214
    return True

def destroy(widget):
    gtk.main_quit()

def key_release(widget, event):
    global position
    if event.keyval == gtk.keysyms.Escape:
        position = window.get_position()
        widget.hide()

215
216
#click on the tray icon
def tray_button(widget):
217
    global position
218
219
220
221
222
223
    if window.get_property('visible'):
        position = window.get_position()
        window.hide()
    else:
        window.move(position[0], position[1])
        window.show()
224

225
#ui setup
226
xml = gtk.glade.XML('mpris.glade')
227
228
229
230
231
232
233
234

bt_close    = xml.get_widget('close')
bt_quit     = xml.get_widget('quit')
bt_file     = xml.get_widget('ChooseFile')
bt_next     = xml.get_widget('next')
bt_prev     = xml.get_widget('prev')
bt_stop     = xml.get_widget('stop')
bt_toggle   = xml.get_widget('toggle')
Rafaël Carré's avatar
Rafaël Carré committed
235
bt_mrl      = xml.get_widget('AddMRL')
236
237
238
bt_shuffle  = xml.get_widget('shuffle')
bt_repeat   = xml.get_widget('repeat')
bt_loop     = xml.get_widget('loop')
Rafaël Carré's avatar
Rafaël Carré committed
239
240
l_artist    = xml.get_widget('l_artist')
l_title     = xml.get_widget('l_title')
241
242
243
244
245
e_mrl       = xml.get_widget('mrl')
window      = xml.get_widget('window1')
img_bt_toggle=xml.get_widget('image6')
exp         = xml.get_widget('expander2')
expvbox     = xml.get_widget('expandvbox')
246
audioicon   = xml.get_widget('eventicon')
Rafaël Carré's avatar
Rafaël Carré committed
247
vol         = xml.get_widget('vol')
248
249
time_s      = xml.get_widget('time_s')
time_l      = xml.get_widget('time_l')
250
251
252
253
254

window.connect('delete_event',  delete_event)
window.connect('destroy',       destroy)
window.connect('key_release_event', key_release)

255
tray = gtk.status_icon_new_from_icon_name("audio-x-generic")
256
tray.connect('activate', tray_button)
257
258
259
260
261
262

def icon_clicked(widget, event):
    update(0)

bt_close.connect('clicked',     destroy)
bt_quit.connect('clicked',      Quit)
263
264
bt_mrl.connect('clicked',       AddTrack)
bt_toggle.connect('clicked',    Pause)
265
266
267
bt_next.connect('clicked',      Next)
bt_prev.connect('clicked',      Prev)
bt_stop.connect('clicked',      Stop)
268
269
270
bt_loop.connect('clicked',      Loop)
bt_repeat.connect('clicked',    Repeat)
bt_shuffle.connect('clicked',   Shuffle)
271
exp.connect('activate',         expander)
272
273
274
vol.connect('change-value',     volchange)
vol.connect('scroll-event',     volchange)
time_s.connect('adjust-bounds', timechange)
275
276
audioicon.set_events(gtk.gdk.BUTTON_PRESS_MASK) 
audioicon.connect('button_press_event', icon_clicked) 
277
time_s.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
278

279
library = "/media/mp3" #editme
280
281
282
283
284

try:
    os.chdir(library)
    bt_file.set_current_folder(library)
except:
285
    bt_file.set_current_folder(os.path.expanduser("~"))
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304

#connect to the bus
bus = dbus.SessionBus()
dbus_names = bus.get_object( "org.freedesktop.DBus", "/org/freedesktop/DBus" )
dbus_names.connect_to_signal("NameOwnerChanged", player_change, dbus_interface="org.freedesktop.DBus")

dbus_o = bus.get_object("org.freedesktop.DBus", "/")
dbus_intf = dbus.Interface(dbus_o, "org.freedesktop.DBus")
name_list = dbus_intf.ListNames()
name = ""
for n in name_list:
    if "org.mpris." in n:
        name = n
        break

if name != "":
    Connect(name)
    window.set_title(root.Identity())
    vol.set_value(player.VolumeGet())
305

306
window.set_icon_name('audio-x-generic')
307
308
309
310
311
312
313
window.show()

try:
    update(0)
except:
    True

314
315
icon_theme = gtk.icon_theme_get_default()
try:
316
    pix = icon_theme.load_icon("audio-x-generic",24,0)
317
318
319
320
321
    window.set_icon(pix)
except:
    True
position = window.get_position()

322
gtk.main()