1 # -*- coding: utf-8 -*-
2 """Core Object dealing with plugins and player client
5 __version__ = '0.12.0pr1'
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
18 from .lib.daemon import Daemon
21 """Main class, plugin and player management
24 def __init__(self, conf):
26 Daemon.__init__(self, conf.get('daemon', 'pidfile'))
29 self.sdb = SimaDB(db_path=conf.get('sima', 'db_file'))
30 self.log = getLogger('sima')
32 self.player = self.__get_player() # Player client
35 except (PlayerError, PlayerUnHandledError) as err:
36 self.log.error('Fails to connect player: {}'.format(err))
38 self.short_history = deque(maxlen=60)
40 def __get_player(self):
41 """Instanciate the player"""
42 host = self.config.get('MPD', 'host')
43 port = self.config.get('MPD', 'port')
44 pswd = self.config.get('MPD', 'password', fallback=None)
45 return PlayerClient(host, port, pswd)
47 def add_history(self):
48 self.short_history.appendleft(self.player.current)
50 def register_plugin(self, plugin_class):
51 """Registers plubin in Sima instance..."""
52 self.plugins.append(plugin_class(self))
54 def foreach_plugin(self, method, *args, **kwds):
55 """Plugin's callbacks dispatcher"""
56 for plugin in self.plugins:
57 #self.log.debug('dispatching {0} to {1}'.format(method, plugin))
58 getattr(plugin, method)(*args, **kwds)
60 def need_tracks(self):
62 self.log.debug('Queueing disabled!')
64 queue = self.player.queue
65 queue_trigger = self.config.getint('sima', 'queue_length')
66 self.log.debug('Currently {0} track(s) ahead. (target {1})'.format(
67 len(queue), queue_trigger))
68 if len(queue) < queue_trigger:
74 for plugin in self.plugins:
75 pl_callback = getattr(plugin, 'callback_need_track')()
77 to_add.extend(pl_callback)
79 self.log.warning('Queue plugins returned nothing!')
80 for plugin in self.plugins:
81 pl_callback = getattr(plugin, 'callback_need_track_fb')()
83 to_add.extend(pl_callback)
85 self.player.add(track)
87 def reconnect_player(self):
88 """Trying to reconnect cycling through longer timeout
89 cycle : 5s 10s 1m 5m 20m 1h
91 sleepfor = [5, 10, 60, 300, 1200, 3600]
95 self.log.info('Trying to reconnect in {:>4d} seconds'.format(tmp))
101 except PlayerUnHandledError as err:
102 #TODO: unhandled Player exceptions
103 self.log.warning('Unhandled player exception: %s' % err)
104 self.log.info('Got reconnected')
108 """General shutdown method
110 self.log.warning('Starting shutdown.')
111 self.player.disconnect()
112 self.foreach_plugin('shutdown')
114 self.log.info('The way is shut, it was made by those who are dead. '
115 'And the dead keep it…')
116 self.log.info('bye...')
124 except PlayerUnHandledError as err:
125 #TODO: unhandled Player exceptions
126 self.log.warning('Unhandled player exception: {}'.format(err))
128 self.player = PlayerClient()
130 except PlayerError as err:
131 self.log.warning('Player error: %s' % err)
132 self.reconnect_player()
135 """Dispatching callbacks to plugins
137 # hanging here untill a monitored event is raised in the player
138 if getattr(self, 'changed', False): # first iteration exception
139 self.changed = self.player.monitor()
140 else: # first iteration goes through else
141 self.changed = ['playlist', 'player', 'skipped']
142 self.log.debug('changed: {}'.format(', '.join(self.changed)))
143 if 'playlist' in self.changed:
144 self.foreach_plugin('callback_playlist')
145 if ('player' in self.changed
146 or 'options' in self.changed):
147 self.foreach_plugin('callback_player')
148 if 'database' in self.changed:
149 self.foreach_plugin('callback_player_database')
150 if 'skipped' in self.changed:
151 if self.player.state == 'play':
152 self.log.info('Playing: {}'.format(self.player.current))
154 self.foreach_plugin('callback_next_song')
155 if self.need_tracks():
159 # vim: ai ts=4 sw=4 sts=4 expandtab