mpc.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. from __future__ import print_function
  2. import logging
  3. import gevent
  4. from gevent.queue import Queue
  5. from mpd import MPDClient, ConnectionError, CommandError
  6. from eventutils import ParentedLet, Timer
  7. from audiogen import audiogenerate
  8. def get_mpd_client(conf):
  9. client = MPDClient(use_unicode=True)
  10. client.connect(conf['MPD_HOST'], conf['MPD_PORT'])
  11. return client
  12. class MpcWatcher(ParentedLet):
  13. def __init__(self, queue, conf, client=None):
  14. ParentedLet.__init__(self, queue)
  15. self.log = logging.getLogger(self.__class__.__name__)
  16. self.conf = conf
  17. self.client = client # assume it is already connected, or None
  18. def refresh_client(self):
  19. self.client = get_mpd_client(self.conf)
  20. def do_business(self):
  21. while True:
  22. try:
  23. if self.client is None:
  24. self.refresh_client()
  25. self.log.info('idling')
  26. status = self.client.idle()[0]
  27. except ConnectionError:
  28. # TODO: should we emit an error just in case?
  29. self.client = None
  30. continue
  31. self.log.info(status)
  32. yield ('mpc', status)
  33. class Player(gevent.Greenlet):
  34. def __init__(self, conf):
  35. gevent.Greenlet.__init__(self)
  36. self.min_playlist_length = 10
  37. self.log = logging.getLogger(self.__class__.__name__)
  38. self.q = Queue()
  39. self.conf = conf
  40. def _get_mpd(self):
  41. mpd_client = MPDClient(use_unicode=True)
  42. mpd_client.connect(self.conf['MPD_HOST'], self.conf['MPD_PORT'])
  43. return mpd_client
  44. def check_playlist(self):
  45. mpd_client = self._get_mpd()
  46. songs = mpd_client.playlist()
  47. current = mpd_client.currentsong()
  48. pos = int(current.get('pos', 0)) + 1
  49. if(len(songs) - pos >= self.min_playlist_length):
  50. return
  51. self.log.info('need to add new songs')
  52. picker = gevent.Greenlet(audiogenerate,
  53. self.conf['CONTINOUS_AUDIODESC'])
  54. def add(greenlet):
  55. uris = greenlet.value
  56. for uri in uris:
  57. assert type(uri) is unicode, type(uri)
  58. mpd_client.add(uri.strip())
  59. picker.link_value(add)
  60. picker.start()
  61. def enqueue(self, songs):
  62. mpd_client = self._get_mpd()
  63. assert type(songs) is dict
  64. assert 'uris' in songs
  65. spec = songs['audiospec']
  66. for uri in songs['uris']:
  67. assert type(uri) is unicode
  68. self.log.info('Adding {} to playlist (from {}={})'.
  69. format(uri, songs['aid'], spec))
  70. insert_pos = 0 if len(mpd_client.playlistid()) == 0 else \
  71. int(mpd_client.currentsong().get('pos', 0)) + 1
  72. try:
  73. mpd_client.addid(uri, insert_pos)
  74. except CommandError:
  75. self.log.exception("Cannot insert song {}".format(uri))
  76. def _run(self):
  77. mw = MpcWatcher(self.q, self.conf, client=None)
  78. mw.parent_greenlet = self
  79. mw.start()
  80. t = Timer(int(self.conf['CHECK_SECS']) * 1000, self.q)
  81. t.parent_greenlet = self
  82. t.start()
  83. # at the very start, run a check!
  84. gevent.Greenlet.spawn(self.check_playlist)
  85. while True:
  86. value = self.q.get()
  87. self.log.debug('<- %s' % str(value))
  88. # emitter = value['emitter']
  89. kind = value['kind']
  90. args = value['args']
  91. if kind == 'timer' or (kind == 'mpc' and args[0] in ('player', 'playlist')):
  92. gevent.Greenlet.spawn(self.check_playlist)
  93. elif kind == 'mpc':
  94. pass
  95. elif kind == 'add':
  96. self.enqueue(args[0])
  97. else:
  98. self.log.warning("Unknown message: %s" % str(value))