ob-mpd.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #!/usr/bin/python2
  2. #
  3. # Author: John Eikenberry <jae@zhar.net>
  4. # License: GPL 3.0 <http://www.gnu.org/licenses/gpl.txt>
  5. #
  6. # Changelog
  7. # 2007-09-09 - Fixed compatibility issue with mpdclient2 version 1.0
  8. # vs. 11.1 which I have (debian).
  9. # 2007-11-18 - Added playlist load/clear support.
  10. # 2009-01-26 - Changed playlist load behaviour to clear/load/play in one go.
  11. # 2009-06-30 - Changed order to work better with menu middle set
  12. #
  13. #
  14. # This script depends on py-libmpdclient2 which you can get from
  15. # http://incise.org/index.cgi/py-libmpdclient2
  16. #
  17. # Usage:
  18. # Put an entry in ~/.config/openbox/menu.xml:
  19. # <menu id="mpd" label="MPD" execute="~/.config/openbox/scripts/ob-mpd.py" />
  20. #
  21. # Add the following wherever you'd like it to be displayed in your menu:
  22. # <menu id="mpd" />
  23. #
  24. #
  25. # Originally Based on code by John McKnight <jmcknight@gmail.com>
  26. #
  27. # Almost completely reworked, including:
  28. #
  29. # Changed to use libmpdclient2.
  30. # Refactored/Cleaned up the code.
  31. # Added random/repeat toggle indicators.
  32. # Changed Pause/Play so only the appropriate one would show up.
  33. # Added actions to start and stop mpd daemon.
  34. # Added exception to deal with no id3 tags.
  35. # Added volume controls.
  36. # Added output setting controls.
  37. # Determine location of script dynamically instead of hardcoded
  38. import os, sys, socket
  39. import mpdclient2
  40. argv = sys.argv
  41. # The default port for MPD is 6600. If for some reason you have MPD
  42. # running on a different port, change this setting.
  43. mpdPort = 6600
  44. # Client program and args as list or tuple
  45. CLIENT = 'x-terminal-emulator'
  46. CLIENT_ARGS = ('-name', 'ncmpc', '-e', 'ncmpcpp')
  47. #CLIENT_ARGS = ('-name', 'ncmpc', '-geometry', '80x10', '-e', 'ncmpc')
  48. # determin path to this file
  49. my_path = sys.modules[__name__].__file__
  50. # if this fails for some reason, just set it manually.
  51. # Eg.
  52. # my_path = "~/.config/openbox/scripts/ob-mpd.py"
  53. separator = "<separator />"
  54. info = """<item label="%s" />"""
  55. action = ("""<item label="%s"><action name="Execute">"""
  56. """<execute>MY_PATH %s</execute>"""
  57. """</action></item>""").replace("MY_PATH",my_path)
  58. menu = """<menu id="%s" label="%s">"""
  59. menu_end = """</menu>"""
  60. try:
  61. server = mpdclient2.connect(port=mpdPort)
  62. except socket.error:
  63. # If MPD is not running.
  64. if len(argv) > 1:
  65. arg = argv[1]
  66. if arg == 'start':
  67. os.system('mpd')
  68. else:
  69. print ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
  70. "<openbox_pipe_menu>")
  71. print action % ('MPD is not running [start]','start')
  72. print "</openbox_pipe_menu>"
  73. else: # part of server try block
  74. song = server.currentsong()
  75. stats = server.stats()
  76. status = server.status()
  77. if status['state'] == "stop":
  78. display_state = "Not playing"
  79. else:
  80. try:
  81. display_state = "%s - %s" % (song.artist, song.title)
  82. except (AttributeError, KeyError): # no id3 tags
  83. display_state = os.path.basename(song.file)
  84. if status['state'] == "pause":
  85. display_state += " (paused)"
  86. display_state = display_state.replace('"',"'")
  87. display_state = display_state.replace('&','&amp;')
  88. if len(argv) > 1:
  89. state = status.state
  90. def play():
  91. if state == "stop" or state == "pause":
  92. server.play()
  93. def pause():
  94. if state == "play":
  95. server.pause(1)
  96. elif state == "pause":
  97. server.play()
  98. def stop():
  99. if state == "play" or state == "pause":
  100. server.stop()
  101. def prev():
  102. if state == "play":
  103. server.previous()
  104. def next():
  105. if state == "play":
  106. server.next()
  107. random_state = int(status.random)
  108. def random():
  109. if random_state:
  110. server.random(0)
  111. else:
  112. server.random(1)
  113. repeat_state = int(status.repeat)
  114. def repeat():
  115. if repeat_state:
  116. server.repeat(0)
  117. else:
  118. server.repeat(1)
  119. def kill():
  120. try:
  121. server.kill()
  122. except EOFError:
  123. pass
  124. def update():
  125. server.update()
  126. def volume(setto):
  127. relative = (setto[0] in ['+','-'])
  128. setto = int(setto)
  129. if relative:
  130. newvol = int(status.volume) + setto
  131. newvol = newvol <= 100 or 100
  132. newvol = newvol >= 0 or 0
  133. server.setvol(setto)
  134. def client():
  135. os.execlp(CLIENT, CLIENT, *CLIENT_ARGS)
  136. def enable(output_id):
  137. server.enableoutput(int(output_id))
  138. def disable(output_id):
  139. server.disableoutput(int(output_id))
  140. def load(list_name):
  141. server.clear()
  142. server.load(list_name)
  143. server.play()
  144. def clear():
  145. server.clear()
  146. if (argv[1] == "play"): play()
  147. elif (argv[1] == "pause"): pause()
  148. elif (argv[1] == "stop"): stop()
  149. elif (argv[1][:4] == "prev"): prev()
  150. elif (argv[1] == "next"): next()
  151. elif (argv[1] == "random"): random()
  152. elif (argv[1] == "repeat"): repeat()
  153. elif (argv[1] == "volume"): volume(argv[2])
  154. elif (argv[1] == "client"): client()
  155. elif (argv[1] == "kill"): kill()
  156. elif (argv[1] == "update"): update()
  157. elif (argv[1] == "enable"): enable(argv[2])
  158. elif (argv[1] == "disable"): disable(argv[2])
  159. elif (argv[1] == "load"): load(argv[2])
  160. elif (argv[1] == "clear"): clear()
  161. else:
  162. #
  163. print """<?xml version="1.0" encoding="UTF-8"?>"""
  164. print """<openbox_pipe_menu>"""
  165. print action % (display_state,'client')
  166. print separator
  167. print menu % ("volume","Volume: %s%%" % status.volume)
  168. print action % ('[100%]','volume 100')
  169. print action % (' [80%]','volume 80')
  170. print action % (' [60%]','volume 60')
  171. print action % (' [40%]','volume 40')
  172. print action % (' [20%]','volume 20')
  173. print action % ('[Mute]','volume 0')
  174. print menu_end
  175. print menu % ("playlist","Playlist")
  176. print action % ('clear','clear')
  177. print separator
  178. for entity in server.lsinfo():
  179. if 'playlist' in entity:
  180. playlist = entity['playlist']
  181. print action % (playlist, 'load %s' % playlist)
  182. print menu_end
  183. print menu % ("output","Audio Output")
  184. for out in server.outputs():
  185. name,oid = out['outputname'],out['outputid']
  186. on = int(out['outputenabled'])
  187. print action % ("%s [%s]" % (name, on and 'enabled' or 'disabled'),
  188. "%s %s" % ((on and 'disable' or 'enable'), oid))
  189. print menu_end
  190. print separator
  191. print action % ('Previous','prev')
  192. print action % ('Next','next')
  193. if status['state'] in ["pause","stop"]:
  194. print action % ('Play','play')
  195. if status['state'] == "play":
  196. print action % ('Pause','pause')
  197. print action % ('Stop','stop')
  198. print separator
  199. print action % ('Toggle random %s' % (
  200. int(status.random) and '[On]' or '[Off]'), 'random')
  201. print action % ('Toggle repeat %s' % (
  202. int(status.repeat) and '[On]' or '[Off]'), 'repeat')
  203. print separator
  204. print action % ('Update Database','update')
  205. print action % ('Kill MPD','kill')
  206. print "</openbox_pipe_menu>"
  207. # print menu % ("Song Info","Volume: %s%%" % status.volume)
  208. # print info % ('%s kbs' % status.bitrate)
  209. # print separator
  210. # print info % ("Artists in DB: %s" % stats.artists)
  211. # print info % ("Albums in DB: %s" % stats.albums)
  212. # print info % ("Songs in DB: %s" % stats.songs)