~registry/hyberia/0.2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/usr/bin/env python
#
# Eiffel Forum License, version 2
#
# 1. Permission is hereby granted to use, copy, modify and/or
#    distribute this package, provided that:
#       * copyright notices are retained unchanged,
#       * any distribution of this package, whether modified or not,
#         includes this license text.
# 2. Permission is hereby also granted to distribute binary programs
#    which depend on this package. If the binary program depends on a
#    modified version of this package, you are encouraged to publicly
#    release the modified version of this package.
#
# THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE.
"""
this is the deamon module part of the Touei project.
please see http://elwillow.net/touei for more info.
"""

__author__ = "G-Anime"
__license__ = "Eiffel Version 2"
__version__ = "0.2"
__revision__ = "47"
__contributors__= "Mathieu Charron, Martin Samson"

import time, signal, datetime, os
import mkvutils

# Instanciate the logging
import logging
module_logger = logging.getLogger("touei.daemon")

class ToueiDaemon():
    """This class provide a way to keep the video database in memory and
    a fast way of checking witch video to play.
    """
    def __init__(self, playlist, player, config, mkv):
        # Instanciate the logger
        self.logger = logging.getLogger("touei.daemon.ToueiDaemon")
        self.logger.info("Creating instance")

        signal.signal (signal.SIGTERM, self._signalTerm)
        signal.signal (signal.SIGHUP, self._signalTerm)
        signal.signal (signal.SIGCONT, self._signalCont)
        self._isRunning = True
        self._Playlist = playlist
        self._Player = player
        self._Config = config
        self._MkvUtils = mkv
        self._CurrentVideo = self._Config.get("video","recovery")

    def stop(self):
        """Stop the loop
        """
        self.logger.debug("stop() called")
        self._isRunning = False

    def playerRunning(self):
        """Will check for the player state file deleted by toueid.
        """
        return os.path.exists(self._Config.get("core","tmp-location")+"/player_running")

    def setPlayerRunning(self):
        """Create the file for toueid and the player state (if we crash)
        """
        if not self.playerRunning():
            open(self._Config.get("core","tmp-location")+"/player_running", "w").close()

    def getCurTime(self):
        """Return the current time with the block format.
        """
        return datetime.datetime.now().strftime("%H%M")

    def secondsDelta(self, blockStart):
        """Return the number of seconds since the begining of the current block
        @param string blockStart
        """
        delta = datetime.datetime.now() - datetime.datetime.strptime(str(blockStart),"%Y%m%d%H%M")
        print delta
        self.logger.debug("BLOCK DELTA IS %d SECONDS" % (delta.seconds, ) )
        return delta.seconds

    def run(self):
        """Main daemon routine
        """
        self.logger.debug("Entering run loop")
        self.logger.debug("Loop sleep time is %d seconds" % (self._Config.getint("timing","loop_sleep"), ) )
        # This will containt a sq3.row instance
        CurrentVideo = {}
        # For logging purposes
        while(self._isRunning):
            self.logger.info("Entering Loop at %s" % (datetime.datetime.now().strftime("%H%M.%S"),))
            curTime = self.getCurTime()
            self.video = self._Playlist.get()
            self.logger.debug("Current Video: " + self._CurrentVideo)
            #self.logger.debug("Playlist Video: " + video['file'])
            if not self.video:
                # Nothing for current time, Play standby video
                self.logger.debug("No video for current block")
                if self._CurrentVideo == self._Config.get("video","standby"):
                    # Standby video is playing
                    self.logger.info("Standby video is playing, sleeping")
                else:
                    # Play the standby video
                    self.logger.info("Playing standby video")
                    self._CurrentVideo = self._Config.get("video","standby")
                    # Open the file is "soft" mode, aka append.
                    self._Player.openFile(self._CurrentVideo, True)

            elif self._CurrentVideo != self.video['file']:
                # We have a new video to play (apparently)
                self.logger.debug("Current video is different")
                currentVideo = self.video
                self._CurrentVideo = self.video['file']
                # Create the intro file
                introVideo = self._MkvUtils.generate_intro(os.path.split(self.video['file'])[1])
                self.logger.debug("Restoring: Intro video is " + introVideo)

                # Check if the video is alive
                if not self.playerRunning():
                    # Not running, we have to restore the video
                    self.logger.warn("Player was dead, restoring")
                    bDelta = self.secondsDelta(self.video['datetime_start'])
                    # Check if we want the intro video
                    if bDelta < self._Config.getint("timing", "loop_sleep"):
                        # Within the sleep timer
                        self.logger.info("Within the loop_sleep time, Playing block")
                        self._Player.openFile(introVideo)

                    # Send the video to player
                    self._Player.openFile(self._CurrentVideo, True)

                    # Check if we need to seek
                    if bDelta > self._Config.getint("timing","recovery_time")*2:
                        # We need to seek
                        self.logger.info("Over the twice recovery time, seeking")
                        # Send the seek commands
                        self._Player.seek(True, bDelta)
                    else:
                        # We are within the recovery time, don't seek
                        self.logger.info("Restoring: Wihin the recovery, doing nothing")
                    # Send the intro to player


                    # Send the outro to player
                    #self._Player.openFile(self._Config.get("video","outro"))
                    # Recreate the file
                    self.setPlayerRunning()
                else:
                    # Player is still alive, do nothing
                    self.logger.warn("Player is still alive, sleeping")

            else:
                # Nothing to do, video is playing
                # It could also mean we just went through a _signalCont()
                self.logger.debug("Still playing, sleeping")
            self.logger.debug("Loop ending")
            time.sleep(self._Config.getint("timing", "loop_sleep") )

    def _signalTerm(self,signal,frame):
        """Will exit the loop and let the application close.
        """
        self.logger.warn("SIGNTERM signal received, quitting")
        self._isRunning = False
        if self.playerRunning():
            os.remove(self._Config.get("core","tmp-location")+"/player_running")

    def _signalCont(self, signal, frame):
        """Signal from the TOUEID process telling the loop that mplayer have
        been restart. replaying the current video.
        """
        self.logger.debug("Received signal %s" % (signal, ))
        if signal == 18:
            # we restore the current video
            self.logger.warn("SIGCONT signal received, restoring video")
            # @TODO Add the seek feature when mplayer crash in the middle of a video

            # Close the socket et reopen it
            self._Player.closeSocket()
            self._Player.openSocket()

            # Force play it
            self._Player.openFile(self._CurrentVideo)
            # @TODO Add the seek to restore the video where is was

            # Get the delta
            bDelta = self.secondsDelta(self.video['datetime_start'])
            if bDelta > self._Config.getint("timing","recovery_time")*2:
                # We need to seek
                self.logger.info("Restoring: Over the twice recovery time, seeking")
                # Send the seek commands
                self._Player.seek(True, bDelta)
            else:
                # We are within the recovery time, don't seek
                self.logger.info("Restoring: Wihin the recovery, doing nothing")

        # REMOVED, simply kill touei_run and toueid will restart it and generate
        # The new stuff
        #elif signal == 25:
            ## We rebuild the playlist database
            #self.logger.warn("Signal 25 received, rebuilding video DB")
            #self._Playlist.load(self._Config.get("video", "location"))


if __name__ == "__main__":
    print "##### DEBUG ######"
    d = ToueiDaemon()
    d.run()