Merge branch 'master' of git+ssh://scm.schwerkraft.elitedvb.net/scmrepos/git/enigma2...
[enigma2-plugins.git] / autotimer / src / AutoPoller.py
1 from __future__ import print_function
2
3 # Core functionality
4 from enigma import eTimer, ePythonMessagePump
5
6 # Config
7 from Components.config import config
8
9 # Notifications
10 from Tools.FuzzyDate import FuzzyTime
11 from Tools.Notifications import AddPopup
12 from Screens.MessageBox import MessageBox
13
14 NOTIFICATIONID = 'AutoTimerConflictEncounteredNotification'
15 SIMILARNOTIFICATIONID = 'AutoTimerSimilarUsedNotification'
16
17 from threading import Thread, Semaphore
18 from collections import deque
19
20 from twisted.internet import reactor
21
22 class AutoPollerThread(Thread):
23         """Background thread where the EPG is parsed (unless initiated by the user)."""
24         def __init__(self):
25                 Thread.__init__(self)
26                 self.__semaphore = Semaphore(0)
27                 self.__queue = deque(maxlen=1)
28                 self.__pump = ePythonMessagePump()
29                 self.__pump_recv_msg_conn = self.__pump.recv_msg.connect(self.gotThreadMsg)
30                 self.__timer = eTimer()
31                 self.__timer_conn = self.__timer.timeout.connect(self.timeout)
32                 self.running = False
33
34         def timeout(self):
35                 self.__semaphore.release()
36
37         def gotThreadMsg(self, msg):
38                 """Create Notifications if there is anything to display."""
39                 ret = self.__queue.pop()
40                 conflicts = ret[4]
41                 if conflicts and config.plugins.autotimer.notifconflict.value:
42                         AddPopup(
43                                 _("%d conflict(s) encountered when trying to add new timers:\n%s") % (len(conflicts), '\n'.join([_("%s: %s at %s") % (x[4], x[0], FuzzyTime(x[2])) for x in conflicts])),
44                                 MessageBox.TYPE_INFO,
45                                 5,
46                                 NOTIFICATIONID
47                         )
48                 similars = ret[5]
49                 if similars and config.plugins.autotimer.notifsimilar.value:
50                         AddPopup(
51                                 _("%d conflict(s) solved with similar timer(s):\n%s") % (len(similars), '\n'.join([_("%s: %s at %s") % (x[4], x[0], FuzzyTime(x[2])) for x in similars])),
52                                 MessageBox.TYPE_INFO,
53                                 5,
54                                 SIMILARNOTIFICATIONID
55                         )
56
57         def start(self, initial=True):
58                 # NOTE: we wait for several minutes on initial launch to not delay enigma2 startup time
59                 if initial: delay = config.plugins.autotimer.delay.value*60
60                 else: delay = config.plugins.autotimer.interval.value*3600
61
62                 self.__timer.startLongTimer(delay)
63                 if not self.isAlive():
64                         Thread.start(self)
65
66         def pause(self):
67                 self.__timer.stop()
68
69         def stop(self):
70                 self.__timer.stop()
71                 self.running = False
72                 self.__semaphore.release()
73                 self.__pump_recv_msg_conn = None
74                 self.__timer_conn = None
75
76         def run(self):
77                 sem = self.__semaphore
78                 queue = self.__queue
79                 pump = self.__pump
80                 timer = self.__timer
81
82                 self.running = True
83                 while 1:
84                         sem.acquire()
85                         # NOTE: we have to check this here and not using the while to prevent the parser to be started on shutdown
86                         if not self.running: break
87                         
88                         if config.plugins.autotimer.skip_during_records.value:
89                                 try:
90                                         import NavigationInstance
91                                         if NavigationInstance.instance.RecordTimer.isRecording():
92                                                 print("[AutoTimer]: Skip check during running records")
93                                                 continue
94                                 except:
95                                         pass
96
97                         from plugin import autotimer
98                         # Ignore any program errors
99                         try:
100                                 queue.append(autotimer.parseEPG())
101                                 pump.send(0)
102                         except Exception:
103                                 # Dump error to stdout
104                                 import traceback, sys
105                                 traceback.print_exc(file=sys.stdout)
106                         #Keep that eTimer in the mainThread
107                         reactor.callFromThread(timer.startLongTimer, config.plugins.autotimer.interval.value*3600)
108
109 class AutoPoller:
110         """Manages actual thread which does the polling. Used for convenience."""
111
112         def __init__(self):
113                 self.thread = AutoPollerThread()
114
115         def start(self, initial=True):
116                 self.thread.start(initial=initial)
117
118         def pause(self):
119                 self.thread.pause()
120
121         def stop(self):
122                 self.thread.stop()
123                 # NOTE: while we don't need to join the thread, we should do so in case it's currently parsing
124                 self.thread.join()
125                 self.thread = None