Makes mpris.py really a mpris controller
[vlc.git] / extras / mpris.py
1 #!/usr/bin/python
2 # -*- coding: utf8 -*-
3 #
4 # Copyright (C) 2006 Rafaël Carré <funman at videolanorg>
5 #
6 # $Id$
7
8 #  This program is free software; you can redistribute it and/or modify
9 #  it under the terms of the GNU General Public License as published by
10 #  the Free Software Foundation; either version 2 of the License, or
11 #  (at your option) any later version.
12
13 #  This program is distributed in the hope that it will be useful,
14 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #  GNU General Public License for more details.
17
18 #  You should have received a copy of the GNU General Public License
19 #  along with this program; if not, write to the Free Software
20 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 #
22
23 #
24 # NOTE: this controller is a SAMPLE, and thus doesn't implement all the D-Bus Media Player specification. http://wiki.videolan.org/index.php/DBus-spec
25 # This is an unfinished document (on the 12/06/2006) and has been designed to be as general as possible.
26 # So don't expect that much from this, but basic capabilities should work out of the box (Play/Pause/Next/Add)
27 #
28 # Also notice it has been designed first for a previous specificaiton, and thus some code may not work/be disabled
29 #
30 # You'll need pygtk >= 2.10 to use gtk.StatusIcon
31 #
32 import dbus
33 import dbus.glib
34 import gtk
35 import gtk.glade
36 import gobject
37 import os
38
39 global position
40 global timer
41 global playing
42 playing = False
43
44 def itemchange_handler(item):
45     gobject.timeout_add( 2000, timeset)
46     try:
47         a = item["artist"]
48     except:
49         a = ""
50     try:
51         t = item["title"]
52     except:
53         t = ""
54     if t == "":
55         t = item["URI"]
56     l_artist.set_text(a)
57     l_title.set_text(t)
58
59 #connect to the bus
60 bus = dbus.SessionBus()
61
62 #find the first media player available
63 dbus_o = bus.get_object("org.freedesktop.DBus", "/")
64 dbus_intf = dbus.Interface(dbus_o, "org.freedesktop.DBus")
65 name_list = dbus_intf.ListNames()
66 name = ""
67 for n in name_list:
68     if "org.mpris." in n:
69         name = n
70         break
71
72 if name == "":
73     print "No MPRIS enabled players on the bus !"
74     exit()
75
76
77 root_o = bus.get_object(name, "/")
78 player_o = bus.get_object(name, "/Player")
79 tracklist_o = bus.get_object(name, "/TrackList")
80
81 root = dbus.Interface(root_o, "org.freedesktop.MediaPlayer")
82 tracklist  = dbus.Interface(tracklist_o, "org.freedesktop.MediaPlayer")
83 player = dbus.Interface(player_o, "org.freedesktop.MediaPlayer")
84 try:
85     player_o.connect_to_signal("TrackChange", itemchange_handler, dbus_interface="org.freedesktop.MediaPlayer")
86 except:
87     True
88
89 #plays an element
90 def AddTrack(widget):
91     mrl = e_mrl.get_text()
92     if mrl != None and mrl != "":
93         tracklist.AddTrack(mrl, True)
94         e_mrl.set_text('')
95     else:
96         mrl = bt_file.get_filename()
97         if mrl != None and mrl != "":
98             tracklist.AddTrack("directory://" + mrl, True)
99     update(0)
100
101 #basic control
102 def Next(widget):
103     player.Next(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
104     update(0)
105
106 def Prev(widget):
107     player.Prev(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
108     update(0)
109
110 def Stop(widget):
111     player.Stop(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
112     update(0)
113
114 #update status display
115 def update(widget):
116     item = tracklist.GetMetadata(tracklist.GetCurrentTrack())
117     vol.set_value(player.VolumeGet())
118     try: 
119         a = item["artist"]
120     except:        a = ""
121     try:
122         t = item["title"]
123     except:        t = ""
124     if t == "":
125         t = item["URI"]
126     l_artist.set_text(a)
127     l_title.set_text(t)
128     GetPlayStatus(0)
129
130 #get playing status from remote player
131 def GetPlayStatus(widget):
132     global playing
133     status = player.GetStatus()
134     if status == 0:
135         img_bt_toggle.set_from_stock("gtk-media-pause", gtk.ICON_SIZE_SMALL_TOOLBAR)
136         playing = True
137     else:
138         img_bt_toggle.set_from_stock("gtk-media-play", gtk.ICON_SIZE_SMALL_TOOLBAR)
139         playing = False
140
141 def Quit(widget):
142     player.Quit(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
143     l_title.set_text("")
144
145 def Pause(widget):
146     player.Pause()
147     status = player.GetStatus()
148     if status == 0:
149         img_bt_toggle.set_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_SMALL_TOOLBAR)
150         gobject.timeout_add( 2000, timeset)
151     else:
152         img_bt_toggle.set_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_SMALL_TOOLBAR)
153     update(0)
154
155 #callback for volume
156 def volchange(widget, data):
157     player.VolumeSet(vol.get_value_as_int(), reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
158
159 #callback for position change
160 def timechange(widget, x=None, y=None):
161     player.PositionSet(int(time_s.get_value()), reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
162
163 #refresh position
164 def timeset():
165     global playing
166     time_s.set_value(player.PositionGet())
167     return playing
168
169 #simple/full display
170 def expander(widget):
171     if exp.get_expanded() == False:
172         exp.set_label("Less")
173     else:
174         exp.set_label("More")
175
176 #close event
177 def delete_event(self, widget):
178     self.hide()
179     return True
180
181 def destroy(widget):
182     gtk.main_quit()
183
184 def key_release(widget, event):
185     global position
186     if event.keyval == gtk.keysyms.Escape:
187         position = window.get_position()
188         widget.hide()
189
190 #click on the tray icon
191 def tray_button(widget):
192     global position
193     if window.get_property('visible'):
194         position = window.get_position()
195         window.hide()
196     else:
197         window.move(position[0], position[1])
198         window.show()
199
200 xml = gtk.glade.XML('mpris.glade')
201
202 bt_close    = xml.get_widget('close')
203 bt_quit     = xml.get_widget('quit')
204 bt_file     = xml.get_widget('ChooseFile')
205 bt_next     = xml.get_widget('next')
206 bt_prev     = xml.get_widget('prev')
207 bt_stop     = xml.get_widget('stop')
208 bt_toggle   = xml.get_widget('toggle')
209 bt_mrl      = xml.get_widget('AddMRL')
210 l_artist    = xml.get_widget('l_artist')
211 l_title     = xml.get_widget('l_title')
212 e_mrl       = xml.get_widget('mrl')
213 window      = xml.get_widget('window1')
214 img_bt_toggle=xml.get_widget('image6')
215 exp         = xml.get_widget('expander2')
216 expvbox     = xml.get_widget('expandvbox')
217 audioicon   = xml.get_widget('eventicon')
218 vol         = xml.get_widget('vol')
219 time_s      = xml.get_widget('time_s')
220 time_l      = xml.get_widget('time_l')
221
222 window.connect('delete_event',  delete_event)
223 window.connect('destroy',       destroy)
224 window.connect('key_release_event', key_release)
225
226 tray = gtk.status_icon_new_from_icon_name("audio-x-generic")
227 tray.connect('activate', tray_button)
228
229 def icon_clicked(widget, event):
230     update(0)
231
232 bt_close.connect('clicked',     destroy)
233 bt_quit.connect('clicked',      Quit)
234 bt_mrl.connect('clicked',       AddTrack)
235 bt_toggle.connect('clicked',    Pause)
236 bt_next.connect('clicked',      Next)
237 bt_prev.connect('clicked',      Prev)
238 bt_stop.connect('clicked',      Stop)
239 exp.connect('activate',         expander)
240 vol.connect('change-value',     volchange)
241 vol.connect('scroll-event',     volchange)
242 time_s.connect('adjust-bounds', timechange)
243 audioicon.set_events(gtk.gdk.BUTTON_PRESS_MASK) 
244 audioicon.connect('button_press_event', icon_clicked) 
245 time_s.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
246 gobject.timeout_add( 2000, timeset)
247
248 library = "/media/mp3"
249
250 try:
251     os.chdir(library)
252     bt_file.set_current_folder(library)
253 except:
254     print "edit this file to point to your media library"
255
256 window.set_icon_name('audio-x-generic')
257 window.set_title(root.Identity())
258 window.show()
259
260 try:
261     update(0)
262 except:
263     True
264
265 icon_theme = gtk.icon_theme_get_default()
266 try:
267     pix = icon_theme.load_icon("audio-x-generic",24,0)
268     window.set_icon(pix)
269 except:
270     True
271 position = window.get_position()
272 vol.set_value(player.VolumeGet())
273
274 gtk.main()