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'
12 from collections import deque
13 from logging import getLogger
15 from .client import PlayerClient
16 from .client import PlayerError, PlayerUnHandledError
17 from .lib.simadb import SimaDB
20 """Main class, plugin and player management
23 def __init__(self, conf):
26 self.sdb = SimaDB(db_path=conf.get('sima', 'db_file'))
27 self.log = getLogger('sima')
29 self.player = self.__get_player() # Player client
32 except (PlayerError, PlayerUnHandledError) as err:
33 self.log.error('Fails to connect player: {}'.format(err))
35 self.short_history = deque(maxlen=60)
37 def __get_player(self):
38 """Instanciate the player"""
39 host = self.config.get('MPD', 'host')
40 port = self.config.get('MPD', 'port')
41 pswd = self.config.get('MPD', 'password', fallback=None)
42 return PlayerClient(host, port, pswd)
44 def add_history(self):
45 self.short_history.appendleft(self.player.current)
47 def register_plugin(self, plugin_class):
48 """Registers plubin in Sima instance..."""
49 self.plugins.append(plugin_class(self))
51 def foreach_plugin(self, method, *args, **kwds):
52 """Plugin's callbacks dispatcher"""
53 for plugin in self.plugins:
54 #self.log.debug('dispatching {0} to {1}'.format(method, plugin))
55 getattr(plugin, method)(*args, **kwds)
57 def need_tracks(self):
59 self.log.debug('Queueing disabled!')
61 queue = self.player.queue
62 queue_trigger = self.config.getint('sima', 'queue_length')
63 self.log.debug('Currently {0} track(s) ahead. (target {1})'.format(
64 len(queue), queue_trigger))
65 if len(queue) < queue_trigger:
71 for plugin in self.plugins:
72 pl_callback = getattr(plugin, 'callback_need_track')()
74 to_add.extend(pl_callback)
76 self.log.warning('Queue plugins returned anything!')
77 for plugin in self.plugins:
78 self.log.info('calling fb for {}'.format(plugin))
79 pl_callback = getattr(plugin, 'callback_need_track_fb')()
81 to_add.extend(pl_callback)
83 self.player.add(track)
85 def reconnect_player(self):
86 """Trying to reconnect cycling through longer timeout
87 cycle : 5s 10s 1m 5m 20m 1h
89 sleepfor = [5, 10, 60, 300, 1200, 3600]
93 self.log.info('Trying to reconnect in {:>4d} seconds'.format(tmp))
99 except PlayerUnHandledError as err:
100 #TODO: unhandled Player exceptions
101 self.log.warning('Unhandled player exception: %s' % err)
102 self.log.info('Got reconnected')
106 """General shutdown method
108 self.log.warning('Starting shutdown.')
109 self.player.disconnect()
110 self.foreach_plugin('shutdown')
112 self.log.info('The way is shut, it was made by those who are dead. '
113 'And the dead keep it…')
114 self.log.info('bye...')
123 except PlayerUnHandledError as err:
124 #TODO: unhandled Player exceptions
125 self.log.warning('Unhandled player exception: {}'.format(err))
127 self.player = PlayerClient()
129 except PlayerError as err:
130 self.log.warning('Player error: %s' % err)
131 self.reconnect_player()
134 """Dispatching callbacks to plugins
136 # hanging here untill a monitored event is raised in the player
137 if getattr(self, 'changed', False): # first iteration exception
138 self.changed = self.player.monitor()
139 else: # first iteration goes through else
140 self.changed = ['playlist', 'player', 'skipped']
141 self.log.debug('changed: {}'.format(', '.join(self.changed)))
142 if 'playlist' in self.changed:
143 self.foreach_plugin('callback_playlist')
144 if ('player' in self.changed
145 or 'options' in self.changed):
146 self.foreach_plugin('callback_player')
147 if 'database' in self.changed:
148 self.foreach_plugin('callback_player_database')
149 if 'skipped' in self.changed:
150 if self.player.state == 'play':
151 self.log.info('Playing: {}'.format(self.player.current))
153 self.foreach_plugin('callback_next_song')
154 if self.need_tracks():
158 # vim: ai ts=4 sw=4 sts=4 expandtab