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 PlayerClient.database = self.sdb
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)
86 self.player.add(track)
88 def reconnect_player(self):
89 """Trying to reconnect cycling through longer timeout
90 cycle : 5s 10s 1m 5m 20m 1h
92 sleepfor = [5, 10, 60, 300, 1200, 3600]
96 self.log.info('Trying to reconnect in {:>4d} seconds'.format(tmp))
102 except PlayerUnHandledError as err:
103 #TODO: unhandled Player exceptions
104 self.log.warning('Unhandled player exception: %s' % err)
105 self.log.info('Got reconnected')
109 """General shutdown method
111 self.log.warning('Starting shutdown.')
112 self.player.disconnect()
113 self.foreach_plugin('shutdown')
115 self.log.info('The way is shut, it was made by those who are dead. '
116 'And the dead keep it…')
117 self.log.info('bye...')
125 except PlayerUnHandledError as err:
126 #TODO: unhandled Player exceptions
127 self.log.warning('Unhandled player exception: {}'.format(err))
129 self.player = PlayerClient()
131 except PlayerError as err:
132 self.log.warning('Player error: %s' % err)
133 self.reconnect_player()
136 """Dispatching callbacks to plugins
138 # hanging here untill a monitored event is raised in the player
139 if getattr(self, 'changed', False): # first iteration exception
140 self.changed = self.player.monitor()
141 else: # first iteration goes through else
142 self.changed = ['playlist', 'player', 'skipped']
143 self.log.debug('changed: {}'.format(', '.join(self.changed)))
144 if 'playlist' in self.changed:
145 self.foreach_plugin('callback_playlist')
146 if ('player' in self.changed
147 or 'options' in self.changed):
148 self.foreach_plugin('callback_player')
149 if 'database' in self.changed:
150 self.foreach_plugin('callback_player_database')
151 if 'skipped' in self.changed:
152 if self.player.state == 'play':
153 self.log.info('Playing: {}'.format(self.player.current))
155 self.foreach_plugin('callback_next_song')
156 if self.need_tracks():
160 # vim: ai ts=4 sw=4 sts=4 expandtab