1 # -*- coding: utf-8 -*-
2 """Core Object dealing with plugins and player client
5 __version__ = '0.12.0.b'
6 __author__ = 'kaliko jack'
7 __url__ = 'git://git.kaliko.me/sima.git'
13 from collections import deque
14 from logging import getLogger
16 from .client import PlayerClient
17 from .client import PlayerError, PlayerUnHandledError
18 from .lib.simadb import SimaDB
19 from .lib.daemon import Daemon
22 """Main class, plugin and player management
25 def __init__(self, conf):
27 Daemon.__init__(self, conf.get('daemon', 'pidfile'))
30 self.sdb = SimaDB(db_path=conf.get('sima', 'db_file'))
31 self.log = getLogger('sima')
33 self.player = self.__get_player() # Player client
36 except (PlayerError, PlayerUnHandledError) as err:
37 self.log.error('Fails to connect player: {}'.format(err))
39 self.short_history = deque(maxlen=60)
41 def __get_player(self):
42 """Instanciate the player"""
43 host = self.config.get('MPD', 'host')
44 port = self.config.get('MPD', 'port')
45 pswd = self.config.get('MPD', 'password', fallback=None)
46 return PlayerClient(host, port, pswd)
48 def add_history(self):
49 self.short_history.appendleft(self.player.current)
51 def register_plugin(self, plugin_class):
52 """Registers plubin in Sima instance..."""
53 self.plugins.append(plugin_class(self))
55 def foreach_plugin(self, method, *args, **kwds):
56 """Plugin's callbacks dispatcher"""
57 for plugin in self.plugins:
58 #self.log.debug('dispatching {0} to {1}'.format(method, plugin))
59 getattr(plugin, method)(*args, **kwds)
61 def need_tracks(self):
63 self.log.debug('Queueing disabled!')
65 queue = self.player.queue
66 queue_trigger = self.config.getint('sima', 'queue_length')
67 self.log.debug('Currently {0} track(s) ahead. (target {1})'.format(
68 len(queue), queue_trigger))
69 if len(queue) < queue_trigger:
75 for plugin in self.plugins:
76 pl_callback = getattr(plugin, 'callback_need_track')()
78 to_add.extend(pl_callback)
80 self.log.warning('Queue plugins returned nothing!')
81 for plugin in self.plugins:
82 pl_callback = getattr(plugin, 'callback_need_track_fb')()
84 to_add.extend(pl_callback)
85 random.shuffle(to_add)
87 self.player.add(track)
89 def reconnect_player(self):
90 """Trying to reconnect cycling through longer timeout
91 cycle : 5s 10s 1m 5m 20m 1h
93 sleepfor = [5, 10, 60, 300, 1200, 3600]
97 self.log.info('Trying to reconnect in {:>4d} seconds'.format(tmp))
100 self.player.connect()
103 except PlayerUnHandledError as err:
104 #TODO: unhandled Player exceptions
105 self.log.warning('Unhandled player exception: %s' % err)
106 self.log.info('Got reconnected')
110 """General shutdown method
112 self.log.warning('Starting shutdown.')
113 self.player.disconnect()
114 self.foreach_plugin('shutdown')
116 self.log.info('The way is shut, it was made by those who are dead. '
117 'And the dead keep it…')
118 self.log.info('bye...')
127 except PlayerUnHandledError as err:
128 #TODO: unhandled Player exceptions
129 self.log.warning('Unhandled player exception: {}'.format(err))
131 self.player = PlayerClient()
133 except PlayerError as err:
134 self.log.warning('Player error: %s' % err)
135 self.reconnect_player()
138 """Dispatching callbacks to plugins
140 # hanging here untill a monitored event is raised in the player
141 if getattr(self, 'changed', False): # first iteration exception
142 self.changed = self.player.monitor()
143 else: # first iteration goes through else
144 self.changed = ['playlist', 'player', 'skipped']
145 self.log.debug('changed: {}'.format(', '.join(self.changed)))
146 if 'playlist' in self.changed:
147 self.foreach_plugin('callback_playlist')
148 if ('player' in self.changed
149 or 'options' in self.changed):
150 self.foreach_plugin('callback_player')
151 if 'database' in self.changed:
152 self.foreach_plugin('callback_player_database')
153 if 'skipped' in self.changed:
154 if self.player.state == 'play':
155 self.log.info('Playing: {}'.format(self.player.current))
157 self.foreach_plugin('callback_next_song')
158 if self.need_tracks():
162 # vim: ai ts=4 sw=4 sts=4 expandtab