mpris.py
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:11k
源码类别:

midi

开发平台:

Unix_Linux

  1. #!/usr/bin/env python
  2. # -*- coding: utf8 -*-
  3. #
  4. # Copyright 漏 2006-2007 Rafa毛l Carr茅 <funman at videolanorg>
  5. #
  6. # $Id$
  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. #  This program is distributed in the hope that it will be useful,
  12. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. #  GNU General Public License for more details.
  15. #  You should have received a copy of the GNU General Public License
  16. #  along with this program; if not, write to the Free Software
  17. #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  18. #
  19. #
  20. # NOTE: This controller is a SAMPLE, and thus doesn't use all the
  21. # Media Player Remote Interface Specification (MPRIS for short) capabilities
  22. #
  23. # MPRIS:  http://wiki.xmms2.xmms.se/index.php/Media_Player_Interfaces
  24. #
  25. # You'll need pygtk >= 2.10 to use gtk.StatusIcon
  26. #
  27. # TODO
  28. #   Ability to choose the Media Player if several are connected to the bus
  29. # core dbus stuff
  30. import dbus
  31. import dbus.glib
  32. # core interface stuff
  33. import gtk
  34. import gtk.glade
  35. # timer
  36. import gobject
  37. # file loading
  38. import os
  39. global win_position # store the window position on the screen
  40. global playing
  41. playing = False
  42. global shuffle      # playlist will play randomly
  43. global repeat       # repeat the playlist
  44. global loop         # loop the current element
  45. # mpris doesn't support getting the status of these (at the moment)
  46. shuffle = False
  47. repeat = False
  48. loop = False
  49. # these are defined on the mpris detected unique name
  50. global root         # / org.freedesktop.MediaPlayer
  51. global player       # /Player org.freedesktop.MediaPlayer
  52. global tracklist    # /Tracklist org.freedesktop.MediaPlayer
  53. global bus          # Connection to the session bus
  54. global identity     # MediaPlayer Identity
  55. # If a Media Player connects to the bus, we'll use it
  56. # Note that we forget the previous Media Player we were connected to
  57. def NameOwnerChanged(name, new, old):
  58.     if old != "" and "org.mpris." in name:
  59.         Connect(name)
  60. # Callback for when "TrackChange" signal is emitted
  61. def TrackChange(Track):
  62.     # the only mandatory metadata is "URI"
  63.     try:
  64.         a = Track["artist"]
  65.     except:
  66.         a = ""
  67.     try:
  68.         t = Track["title"]
  69.     except:
  70.         t = Track["URI"]
  71.     try:
  72.         length = Track["length"]
  73.     except:
  74.         length = 0
  75.     if length > 0:
  76.         time_s.set_range(0,Track["length"])
  77.         time_s.set_sensitive(True)
  78.     else:
  79.         # disable the position scale if length isn't available
  80.         time_s.set_sensitive(False)
  81.     # update the labels
  82.     l_artist.set_text(a)
  83.     l_title.set_text(t)
  84. # Connects to the Media Player we detected
  85. def Connect(name):
  86.     global root, player, tracklist
  87.     global playing, identity
  88.     # first we connect to the objects
  89.     root_o = bus.get_object(name, "/")
  90.     player_o = bus.get_object(name, "/Player")
  91.     tracklist_o = bus.get_object(name, "/TrackList")
  92.     # there is only 1 interface per object
  93.     root = dbus.Interface(root_o, "org.freedesktop.MediaPlayer")
  94.     tracklist  = dbus.Interface(tracklist_o, "org.freedesktop.MediaPlayer")
  95.     player = dbus.Interface(player_o, "org.freedesktop.MediaPlayer")
  96.     # connect to the TrackChange signal
  97.     player_o.connect_to_signal("TrackChange", TrackChange, dbus_interface="org.freedesktop.MediaPlayer")
  98.     # determine if the Media Player is playing something
  99.     if player.GetStatus() == 0:
  100.         playing = True
  101.         TrackChange(player.GetMetadata())
  102.     # gets its identity (name and version)
  103.     identity = root.Identity()
  104.     window.set_title(identity)
  105. #plays an element
  106. def AddTrack(widget):
  107.     mrl = e_mrl.get_text()
  108.     if mrl != None and mrl != "":
  109.         tracklist.AddTrack(mrl, True)
  110.         e_mrl.set_text('')
  111.     else:
  112.         mrl = bt_file.get_filename()
  113.         if mrl != None and mrl != "":
  114.             tracklist.AddTrack("directory://" + mrl, True)
  115.     update(0)
  116. # basic control
  117. def Next(widget):
  118.     player.Next(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
  119.     update(0)
  120. def Prev(widget):
  121.     player.Prev(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
  122.     update(0)
  123. def Stop(widget):
  124.     player.Stop(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
  125.     update(0)
  126. def Quit(widget):
  127.     root.Quit(reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
  128.     l_title.set_text("")
  129. def Pause(widget):
  130.     player.Pause()
  131.     status = player.GetStatus()
  132.     if status == 0:
  133.         img_bt_toggle.set_from_stock(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_SMALL_TOOLBAR)
  134.     else:
  135.         img_bt_toggle.set_from_stock(gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_SMALL_TOOLBAR)
  136.     update(0)
  137. def Repeat(widget):
  138.     global repeat
  139.     repeat = not repeat
  140.     player.Repeat(repeat)
  141. def Shuffle(widget):
  142.     global shuffle
  143.     shuffle = not shuffle
  144.     tracklist.Random(shuffle)
  145. def Loop(widget):
  146.     global loop
  147.     loop = not loop
  148.     tracklist.Loop(loop)
  149. # update status display
  150. def update(widget):
  151.     Track = player.GetMetadata()
  152.     vol.set_value(player.VolumeGet())
  153.     try: 
  154.         a = Track["artist"]
  155.     except:
  156.         a = ""
  157.     try:
  158.         t = Track["title"]
  159.     except:        
  160.         t = ""
  161.     if t == "":
  162.         try:
  163.             t = Track["URI"]
  164.         except:
  165.             t = ""
  166.     l_artist.set_text(a)
  167.     l_title.set_text(t)
  168.     try:
  169.         length = Track["length"]
  170.     except:
  171.         length = 0
  172.     if length > 0:
  173.         time_s.set_range(0,Track["length"])
  174.         time_s.set_sensitive(True)
  175.     else:
  176.         # disable the position scale if length isn't available
  177.         time_s.set_sensitive(False)
  178.     GetPlayStatus(0)
  179. # callback for volume change
  180. def volchange(widget, data):
  181.     player.VolumeSet(vol.get_value_as_int(), reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
  182. # callback for position change
  183. def timechange(widget, x=None, y=None):
  184.     player.PositionSet(int(time_s.get_value()), reply_handler=(lambda *args: None), error_handler=(lambda *args: None))
  185. # refresh position change
  186. def timeset():
  187.     global playing
  188.     if playing == True:
  189.         try:
  190.             time_s.set_value(player.PositionGet())
  191.         except:
  192.             playing = False
  193.     return True
  194. # toggle 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. # close event : hide in the systray
  201. def delete_event(self, widget):
  202.     self.hide()
  203.     return True
  204. # shouldn't happen
  205. def destroy(widget):
  206.     gtk.main_quit()
  207. # hide the controller when 'Esc' is pressed
  208. def key_release(widget, event):
  209.     if event.keyval == gtk.keysyms.Escape:
  210.         global win_position
  211.         win_position = window.get_position()
  212.         widget.hide()
  213. # callback for click on the tray icon
  214. def tray_button(widget):
  215.     global win_position
  216.     if window.get_property('visible'):
  217.         # store position
  218.         win_position = window.get_position()
  219.         window.hide()
  220.     else:
  221.         # restore position
  222.         window.move(win_position[0], win_position[1])
  223.         window.show()
  224. # hack: update position, volume, and metadata
  225. def icon_clicked(widget, event):
  226.     update(0)
  227. # get playing status, modify the Play/Pause button accordingly
  228. def GetPlayStatus(widget):
  229.     global playing
  230.     global shuffle
  231.     global loop
  232.     global repeat
  233.     status = player.GetStatus()
  234.     playing = status[0] == 0
  235.     if playing:
  236.         img_bt_toggle.set_from_stock("gtk-media-pause", gtk.ICON_SIZE_SMALL_TOOLBAR)
  237.     else:
  238.         img_bt_toggle.set_from_stock("gtk-media-play", gtk.ICON_SIZE_SMALL_TOOLBAR)
  239.     shuffle = status[1] == 1
  240.     bt_shuffle.set_active( shuffle )
  241.     loop = status[2] == 1
  242.     bt_loop.set_active( loop )
  243.     repeat = status[3] == 1
  244.     bt_repeat.set_active( repeat )
  245. # loads glade file from the directory where the script is,
  246. # so we can use /path/to/mpris.py to execute it.
  247. import sys
  248. xml = gtk.glade.XML(os.path.join(os.path.dirname(sys.argv[0]) , 'mpris.glade'))
  249. # ui setup
  250. bt_close    = xml.get_widget('close')
  251. bt_quit     = xml.get_widget('quit')
  252. bt_file     = xml.get_widget('ChooseFile')
  253. bt_next     = xml.get_widget('next')
  254. bt_prev     = xml.get_widget('prev')
  255. bt_stop     = xml.get_widget('stop')
  256. bt_toggle   = xml.get_widget('toggle')
  257. bt_mrl      = xml.get_widget('AddMRL')
  258. bt_shuffle  = xml.get_widget('shuffle')
  259. bt_repeat   = xml.get_widget('repeat')
  260. bt_loop     = xml.get_widget('loop')
  261. l_artist    = xml.get_widget('l_artist')
  262. l_title     = xml.get_widget('l_title')
  263. e_mrl       = xml.get_widget('mrl')
  264. window      = xml.get_widget('window1')
  265. img_bt_toggle=xml.get_widget('image6')
  266. exp         = xml.get_widget('expander2')
  267. expvbox     = xml.get_widget('expandvbox')
  268. audioicon   = xml.get_widget('eventicon')
  269. vol         = xml.get_widget('vol')
  270. time_s      = xml.get_widget('time_s')
  271. time_l      = xml.get_widget('time_l')
  272. # connect to the different callbacks
  273. window.connect('delete_event',  delete_event)
  274. window.connect('destroy',       destroy)
  275. window.connect('key_release_event', key_release)
  276. tray = gtk.status_icon_new_from_icon_name("audio-x-generic")
  277. tray.connect('activate', tray_button)
  278. bt_close.connect('clicked',     destroy)
  279. bt_quit.connect('clicked',      Quit)
  280. bt_mrl.connect('clicked',       AddTrack)
  281. bt_toggle.connect('clicked',    Pause)
  282. bt_next.connect('clicked',      Next)
  283. bt_prev.connect('clicked',      Prev)
  284. bt_stop.connect('clicked',      Stop)
  285. bt_loop.connect('clicked',      Loop)
  286. bt_repeat.connect('clicked',    Repeat)
  287. bt_shuffle.connect('clicked',   Shuffle)
  288. exp.connect('activate',         expander)
  289. vol.connect('change-value',     volchange)
  290. vol.connect('scroll-event',     volchange)
  291. time_s.connect('adjust-bounds', timechange)
  292. audioicon.set_events(gtk.gdk.BUTTON_PRESS_MASK) # hack for the bottom right icon
  293. audioicon.connect('button_press_event', icon_clicked) 
  294. time_s.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
  295. library = "/media/mp3" # editme
  296. # set the Directory chooser to a default location
  297. try:
  298.     os.chdir(library)
  299.     bt_file.set_current_folder(library)
  300. except:
  301.     bt_file.set_current_folder(os.path.expanduser("~"))
  302. # connect to the bus
  303. bus = dbus.SessionBus()
  304. dbus_names = bus.get_object( "org.freedesktop.DBus", "/org/freedesktop/DBus" )
  305. dbus_names.connect_to_signal("NameOwnerChanged", NameOwnerChanged, dbus_interface="org.freedesktop.DBus") # to detect new Media Players
  306. dbus_o = bus.get_object("org.freedesktop.DBus", "/")
  307. dbus_intf = dbus.Interface(dbus_o, "org.freedesktop.DBus")
  308. name_list = dbus_intf.ListNames()
  309. # connect to the first Media Player found
  310. for n in name_list:
  311.     if "org.mpris." in n:
  312.         Connect(n)
  313.         window.set_title(identity)
  314.         vol.set_value(player.VolumeGet())
  315.         update(0)
  316.         break
  317. # run a timer to update position
  318. gobject.timeout_add( 1000, timeset)
  319. window.set_icon_name('audio-x-generic')
  320. window.show()
  321. icon_theme = gtk.icon_theme_get_default()
  322. try:
  323.     pix = icon_theme.load_icon("audio-x-generic",24,0)
  324.     window.set_icon(pix)
  325. except:
  326.     True
  327. win_position = window.get_position()
  328. gtk.main() # execute the main loop