Checks ncursesw/curses.h presence
[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
25 # Media Player Remote Interface Specification (MPRIS for short) available at
26 # http://wiki.xmms2.xmms.se/index.php/Media_Player_Interfaces
27 #
28 # You'll need pygtk >= 2.10 to use gtk.StatusIcon
29 #
30 import dbus
31 import dbus.glib
32 import gtk
33 import gtk.glade
34 import gobject
35 import os
36
37 global position
38 global timer
39 global playing
40 playing = False
41
42 global shuffle
43 global repeat
44 global loop
45 #mpris doesn't support getting the status of these (at the moment)
46 shuffle = False
47 repeat = False
48 loop = False
49
50 global root
51 global player
52 global tracklist
53
54 global bus
55
56 def player_change(newname, a, b):
57     if b != "" and "org.mpris." in newname:
58         Connect(newname)
59
60 def itemchange_handler(item):
61     gobject.timeout_add( 2000, timeset)
62     try:
63         a = item["artist"]
64     except:
65         a = ""
66     try:
67         t = item["title"]
68     except:
69         t = ""
70     if t == "":
71         t = item["URI"]
72     l_artist.set_text(a)
73     l_title.set_text(t)
74
75 #find the first media player available
76 def Connect(name):
77     global root
78     global player
79     global tracklist
80     global bus
81     global playing
82
83     root_o = bus.get_object(name, "/")
84     player_o = bus.get_object(name, "/Player")
85     tracklist_o = bus.get_object(name, "/TrackList")
86
87     root = dbus.Interface(root_o, "org.freedesktop.MediaPlayer")
88     tracklist  = dbus.Interface(tracklist_o, "org.freedesktop.MediaPlayer")
89     player = dbus.Interface(player_o, "org.freedesktop.MediaPlayer")
90     player_o.connect_to_signal("TrackChange", itemchange_handler, dbus_interface="org.freedesktop.MediaPlayer")
91     if player.GetStatus() == 0:
92         gobject.timeout_add( 2000, timeset)
93         playing = True
94     window.set_title(root.Identity())
95
96 #plays an element
97 def AddTrack(widget):
98     mrl = e_mrl.get_text()
99     if mrl != None and mrl != "":
100         tracklist.AddTrack(mrl, True)
101         e_mrl.set_text('')
102     else:
103         mrl = bt_file.get_filename()
104         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     update(0)
112
113 def Prev(widget):
114     player.Prev(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
115     update(0)
116
117 def Stop(widget):
118     player.Stop(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
119     update(0)
120
121 #update status display
122 def update(widget):
123     item = tracklist.GetMetadata(tracklist.GetCurrentTrack())
124     vol.set_value(player.VolumeGet())
125     try: 
126         a = item["artist"]
127     except:        a = ""
128     try:
129         t = item["title"]
130     except:        t = ""
131     if t == "":
132         try:
133             t = item["URI"]
134         except:
135             t = ""
136     l_artist.set_text(a)
137     l_title.set_text(t)
138     GetPlayStatus(0)
139
140 #get playing status from remote player
141 def GetPlayStatus(widget):
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)
146         playing = True
147     else:
148         img_bt_toggle.set_from_stock("gtk-media-play", gtk.ICON_SIZE_SMALL_TOOLBAR)
149         playing = False
150
151 def Quit(widget):
152     player.Quit(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
153     l_title.set_text("")
154
155 def Pause(widget):
156     player.Pause()
157     status = player.GetStatus()
158     if status == 0:
159         img_bt_toggle.set_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_SMALL_TOOLBAR)
160         gobject.timeout_add( 2000, timeset)
161     else:
162         img_bt_toggle.set_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_SMALL_TOOLBAR)
163     update(0)
164
165 def Repeat(widget):
166     global repeat
167     repeat = not repeat
168     player.Repeat(repeat)
169
170 def Shuffle(widget):
171     global shuffle
172     shuffle = not shuffle
173     tracklist.Random(shuffle)
174
175 def Loop(widget):
176     global loop
177     loop = not loop
178     tracklist.Loop(loop)
179
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
193
194 #simple/full display
195 def expander(widget):
196     if exp.get_expanded() == False:
197         exp.set_label("Less")
198     else:
199         exp.set_label("More")
200
201 #close event
202 def delete_event(self, widget):
203     self.hide()
204     return True
205
206 def destroy(widget):
207     gtk.main_quit()
208
209 def key_release(widget, event):
210     global position
211     if event.keyval == gtk.keysyms.Escape:
212         position = window.get_position()
213         widget.hide()
214
215 #click on the tray icon
216 def tray_button(widget):
217     global position
218     if window.get_property('visible'):
219         position = window.get_position()
220         window.hide()
221     else:
222         window.move(position[0], position[1])
223         window.show()
224
225 #loads glade file from the directory where the script is,
226 #so we can use /path/to/mpris.py to execute it.
227 import sys
228 xml = gtk.glade.XML(os.path.dirname(sys.argv[0]) + '/mpris.glade')
229
230 #ui setup
231 bt_close    = xml.get_widget('close')
232 bt_quit     = xml.get_widget('quit')
233 bt_file     = xml.get_widget('ChooseFile')
234 bt_next     = xml.get_widget('next')
235 bt_prev     = xml.get_widget('prev')
236 bt_stop     = xml.get_widget('stop')
237 bt_toggle   = xml.get_widget('toggle')
238 bt_mrl      = xml.get_widget('AddMRL')
239 bt_shuffle  = xml.get_widget('shuffle')
240 bt_repeat   = xml.get_widget('repeat')
241 bt_loop     = xml.get_widget('loop')
242 l_artist    = xml.get_widget('l_artist')
243 l_title     = xml.get_widget('l_title')
244 e_mrl       = xml.get_widget('mrl')
245 window      = xml.get_widget('window1')
246 img_bt_toggle=xml.get_widget('image6')
247 exp         = xml.get_widget('expander2')
248 expvbox     = xml.get_widget('expandvbox')
249 audioicon   = xml.get_widget('eventicon')
250 vol         = xml.get_widget('vol')
251 time_s      = xml.get_widget('time_s')
252 time_l      = xml.get_widget('time_l')
253
254 window.connect('delete_event',  delete_event)
255 window.connect('destroy',       destroy)
256 window.connect('key_release_event', key_release)
257
258 tray = gtk.status_icon_new_from_icon_name("audio-x-generic")
259 tray.connect('activate', tray_button)
260
261 def icon_clicked(widget, event):
262     update(0)
263
264 bt_close.connect('clicked',     destroy)
265 bt_quit.connect('clicked',      Quit)
266 bt_mrl.connect('clicked',       AddTrack)
267 bt_toggle.connect('clicked',    Pause)
268 bt_next.connect('clicked',      Next)
269 bt_prev.connect('clicked',      Prev)
270 bt_stop.connect('clicked',      Stop)
271 bt_loop.connect('clicked',      Loop)
272 bt_repeat.connect('clicked',    Repeat)
273 bt_shuffle.connect('clicked',   Shuffle)
274 exp.connect('activate',         expander)
275 vol.connect('change-value',     volchange)
276 vol.connect('scroll-event',     volchange)
277 time_s.connect('adjust-bounds', timechange)
278 audioicon.set_events(gtk.gdk.BUTTON_PRESS_MASK) 
279 audioicon.connect('button_press_event', icon_clicked) 
280 time_s.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
281
282 library = "/media/mp3" #editme
283
284 try:
285     os.chdir(library)
286     bt_file.set_current_folder(library)
287 except:
288     bt_file.set_current_folder(os.path.expanduser("~"))
289
290 #connect to the bus
291 bus = dbus.SessionBus()
292 dbus_names = bus.get_object( "org.freedesktop.DBus", "/org/freedesktop/DBus" )
293 dbus_names.connect_to_signal("NameOwnerChanged", player_change, dbus_interface="org.freedesktop.DBus")
294
295 dbus_o = bus.get_object("org.freedesktop.DBus", "/")
296 dbus_intf = dbus.Interface(dbus_o, "org.freedesktop.DBus")
297 name_list = dbus_intf.ListNames()
298 name = ""
299 for n in name_list:
300     if "org.mpris." in n:
301         name = n
302         break
303
304 if name != "":
305     Connect(name)
306     window.set_title(root.Identity())
307     vol.set_value(player.VolumeGet())
308
309 window.set_icon_name('audio-x-generic')
310 window.show()
311
312 try:
313     update(0)
314 except:
315     True
316
317 icon_theme = gtk.icon_theme_get_default()
318 try:
319     pix = icon_theme.load_icon("audio-x-generic",24,0)
320     window.set_icon(pix)
321 except:
322     True
323 position = window.get_position()
324
325 gtk.main()