]> kaliko git repositories - mpd-sima.git/blob - sima/core.py
Add handling of external plugins
[mpd-sima.git] / sima / core.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 """Core Object dealing with plugins and player client
4 """
5
6 __version__ = '0.12.0.b'
7 __author__ = 'kaliko jack'
8 __url__ = 'git://git.kaliko.me/sima.git'
9
10 import sys
11 import time
12
13 from logging import getLogger
14
15 from .client import PlayerClient, Track
16 from .client import PlayerError, PlayerUnHandledError
17 from .lib.simadb import SimaDB
18
19 class Sima(object):
20     """Main class, plugin and player management
21     """
22
23     def __init__(self, conf, dbfile):
24         self.config = conf
25         self.sdb = SimaDB(db_path=dbfile)
26         self.log = getLogger('sima')
27         self.plugins = list()
28         self.player = PlayerClient()  # Player client
29         try:
30             self.player.connect()
31         except (PlayerError, PlayerUnHandledError) as err:
32             self.log.error('Fails to connect player: {}'.format(err))
33             self.shutdown()
34         self.current_track = None
35
36     def register_plugin(self, plugin_class):
37         """Registers plubin in Sima instance..."""
38         self.plugins.append(plugin_class(self))
39
40     def foreach_plugin(self, method, *args, **kwds):
41         """Plugin's callbacks dispatcher"""
42         for plugin in self.plugins:
43             #self.log.debug('dispatching {0} to {1}'.format(method, plugin))
44             getattr(plugin, method)(*args, **kwds)
45
46     def reconnect_player(self):
47         """Trying to reconnect cycling through longer timeout
48         cycle : 5s 10s 1m 5m 20m 1h
49         """
50         sleepfor = [5, 10, 60, 300, 1200, 3600]
51         while True:
52             tmp = sleepfor.pop(0)
53             sleepfor.append(tmp)
54             self.log.info('Trying to reconnect in {:>4d} seconds'.format(tmp))
55             time.sleep(tmp)
56             try:
57                 self.player.connect()
58             except PlayerError:
59                 continue
60             except PlayerUnHandledError as err:
61                 #TODO: unhandled Player exceptions
62                 self.log.warning('Unhandled player exception: %s' % err)
63             self.log.info('Got reconnected')
64             break
65
66     def shutdown(self):
67         """General shutdown method
68         """
69         self.log.warning('Starting shutdown.')
70         self.player.disconnect()
71         self.foreach_plugin('shutdown')
72
73         self.log.info('The way is shut, it was made by those who are dead. '
74                       'And the dead keep it…')
75         self.log.info('bye...')
76         sys.exit(0)
77
78     def run(self):
79         """
80         """
81         self.current_track = Track()
82         while 42:
83             try:
84                 self.loop()
85             except PlayerUnHandledError as err:
86                 #TODO: unhandled Player exceptions
87                 self.log.warning('Unhandled player exception: {}'.format(err))
88                 del(self.player)
89                 self.player = PlayerClient()
90                 time.sleep(10)
91             except PlayerError as err:
92                 self.log.warning('Player error: %s' % err)
93                 self.reconnect_player()
94
95     def loop(self):
96         """Dispatching callbacks to plugins
97         """
98         # hanging here untill a monitored event is raised in the player
99         if getattr(self, 'changed', False): # first loop detection
100             self.changed = self.player.monitor()
101         else:
102             self.changed = ['playlist', 'player', 'skipped']
103         self.log.debug('changed: {}'.format(', '.join(self.changed)))
104         if 'playlist' in self.changed:
105             self.foreach_plugin('callback_playlist')
106         if 'player' in self.changed:
107             self.foreach_plugin('callback_player')
108         if 'skipped' in self.changed:
109             if self.player.state == 'play':
110                 self.log.info('Playing: {}'.format(self.player.current))
111                 self.foreach_plugin('callback_next_song')
112                 self.current_track = self.player.current
113
114
115 # VIM MODLINE
116 # vim: ai ts=4 sw=4 sts=4 expandtab