Changed e-mail addy
[enigma2-plugins.git] / mosaic / src / plugin.py
1 ##
2 ## Mosaic
3 ## by AliAbdul
4 ## needs the aio-screengrabber by seddi
5 ##
6 from Components.ActionMap import NumberActionMap
7 from Components.AVSwitch import AVSwitch
8 from Components.config import config, ConfigSubsection, ConfigInteger
9 from Components.Label import Label
10 from Components.Pixmap import Pixmap
11 from Components.VideoWindow import VideoWindow
12 from enigma import eConsoleAppContainer, eServiceCenter, eServiceReference, eTimer, loadPic, loadPNG
13 from Plugins.Plugin import PluginDescriptor
14 from Screens.ChannelSelection import BouquetSelector
15 from Screens.MessageBox import MessageBox
16 from Screens.Screen import Screen
17 from Tools.Directories import fileExists, resolveFilename, SCOPE_SKIN_IMAGE
18
19 ################################################
20
21 grab_binary = "/usr/bin/grab"
22 grab_picture = "/tmp/.mosaic.bmp"
23
24 config_limits = (3, 30)
25 config.plugins.Mosaic = ConfigSubsection()
26 config.plugins.Mosaic.countdown = ConfigInteger(default=5, limits=config_limits)
27
28 playingIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_play.png'))
29 pausedIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_pause.png'))
30
31 ################################################
32
33 class Mosaic(Screen):
34         PLAY = 0
35         PAUSE = 1
36
37         skin = """
38         <screen position="0,0" size="720,576" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >
39                 <widget name="playState" position="55,55" size="16,16" alphatest="on" />
40                 <eLabel position="78,54" size="180,144" />
41                 <eLabel position="274,54" size="180,144" />
42                 <eLabel position="470,54" size="180,144" />
43                 <eLabel position="78,221" size="180,144" />
44                 <eLabel position="274,221" size="180,144" />
45                 <eLabel position="470,221" size="180,144" />
46                 <eLabel position="78,388" size="180,144" />
47                 <eLabel position="274,388" size="180,144" />
48                 <eLabel position="470,388" size="180,144" />
49                 <widget name="channel1" position="80,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
50                 <widget name="channel2" position="276,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
51                 <widget name="channel3" position="472,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
52                 <widget name="channel4" position="80,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
53                 <widget name="channel5" position="276,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
54                 <widget name="channel6" position="472,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
55                 <widget name="channel7" position="80,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
56                 <widget name="channel8" position="276,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
57                 <widget name="channel9" position="472,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
58                 <widget name="window1" position="78,54" zPosition="1" size="180,144" />
59                 <widget name="window2" position="274,54" zPosition="1" size="180,144" />
60                 <widget name="window3" position="470,54" zPosition="1" size="180,144" />
61                 <widget name="window4" position="78,221" zPosition="1" size="180,144" />
62                 <widget name="window5" position="274,221" zPosition="1" size="180,144" />
63                 <widget name="window6" position="470,221" zPosition="1" size="180,144" />
64                 <widget name="window7" position="78,388" zPosition="1" size="180,144" />
65                 <widget name="window8" position="274,388" zPosition="1" size="180,144" />
66                 <widget name="window9" position="470,388" zPosition="1" size="180,144" />
67                 <widget name="video1" position="78,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
68                 <widget name="video2" position="274,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
69                 <widget name="video3" position="470,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
70                 <widget name="video4" position="78,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
71                 <widget name="video5" position="274,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
72                 <widget name="video6" position="470,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
73                 <widget name="video7" position="78,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
74                 <widget name="video8" position="274,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
75                 <widget name="video9" position="470,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
76                 <widget name="event1" position="78,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
77                 <widget name="event2" position="274,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
78                 <widget name="event3" position="470,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
79                 <widget name="event4" position="78,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
80                 <widget name="event5" position="274,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
81                 <widget name="event6" position="470,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
82                 <widget name="event7" position="78,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
83                 <widget name="event8" position="274,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
84                 <widget name="event9" position="470,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
85                 <widget name="countdown" position="80,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
86                 <widget name="count" position="472,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" />
87         </screen>"""
88
89         def __init__(self, session, services):
90                 Screen.__init__(self, session)
91                 
92                 self.session = session
93                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
94                 self.container = eConsoleAppContainer()
95                 self.aspect = AVSwitch().getAspectRatioSetting()
96                 self.serviceHandler = eServiceCenter.getInstance()
97                 self.ref_list = services
98                 self.window_refs = [None, None, None, None, None, None, None, None, None]
99                 self.current_refidx = 0
100                 self.current_window = 1
101                 self.countdown = config.plugins.Mosaic.countdown.value
102                 self.working = False
103                 self.state = self.PLAY
104                 
105                 self["playState"] = Pixmap()
106                 for i in range(1, 10):
107                         self["window" + str(i)] = Pixmap()
108                         self["video" + str(i)] = VideoWindow(decoder = 0)
109                         self["video" + str(i)].hide()
110                         self["channel" + str(i)] = Label("")
111                         self["event" + str(i)] = Label("")
112                         self["event" + str(i)].hide()
113                 self["video1"].decoder = 0
114                 self["video1"].show()
115                 self["countdown"] = Label()
116                 self.updateCountdownLabel()
117                 self["count"] = Label()
118                 
119                 self["actions"] = NumberActionMap(["MosaicActions"],
120                         {
121                                 "ok": self.close,
122                                 "cancel": self.closeWithOldService,
123                                 "green": self.play,
124                                 "yellow": self.pause,
125                                 "channelup": self.countdownPlus,
126                                 "channeldown": self.countdownMinus,
127                                 "1": self.numberPressed,
128                                 "2": self.numberPressed,
129                                 "3": self.numberPressed,
130                                 "4": self.numberPressed,
131                                 "5": self.numberPressed,
132                                 "6": self.numberPressed,
133                                 "7": self.numberPressed,
134                                 "8": self.numberPressed,
135                                 "9": self.numberPressed
136                         }, prio=-1)
137                 
138                 self.updateTimer = eTimer()
139                 self.updateTimer.timeout.get().append(self.updateCountdown)
140                 self.checkTimer = eTimer()
141                 self.checkTimer.timeout.get().append(self.checkGrab)
142                 
143                 self.container.appClosed.append(self.showNextScreenshot)
144                 self.checkTimer.start(500, 1)
145
146         def checkGrab(self):
147                 if fileExists(grab_binary):
148                         # Start the first service in the bouquet and show the service-name
149                         ref = self.ref_list[0]
150                         self.window_refs[0] = ref
151                         info = self.serviceHandler.info(ref)
152                         name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
153                         event_name = self.getEventName(info, ref)
154                         self["channel1"].setText(name)
155                         self["event1"].setText(event_name)
156                         self.session.nav.playService(ref)
157                         self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
158                         self["playState"].instance.setPixmap(playingIcon)
159                         
160                         # Start updating the video-screenshots
161                         self.updateTimer.start(1, 1)
162                 else:
163                         self.session.openWithCallback(self.exit, MessageBox, _("%s does not exist!") % grab_binary, MessageBox.TYPE_ERROR, timeout=5)
164
165         def exit(self, callback=None):
166                 self.close()
167
168         def closeWithOldService(self):
169                 self.session.nav.playService(self.oldService)
170                 self.close()
171
172         def numberPressed(self, number):
173                 ref = self.window_refs[number-1]
174                 if ref is not None:
175                         self.session.nav.playService(ref)
176                         self.close()
177
178         def play(self):
179                 if self.working == False and self.state == self.PAUSE:
180                         self.state = self.PLAY
181                         self.updateTimer.start(1000, 1)
182                         self["playState"].instance.setPixmap(playingIcon)
183
184         def pause(self):
185                 if self.working == False and self.state == self.PLAY:
186                         self.state = self.PAUSE
187                         self.updateTimer.stop()
188                         self["playState"].instance.setPixmap(pausedIcon)
189
190         def countdownPlus(self):
191                 self.changeCountdown(1)
192
193         def countdownMinus(self):
194                 self.changeCountdown(-1)
195
196         def changeCountdown(self, direction):
197                 if self.working == False:
198                         configNow = config.plugins.Mosaic.countdown.value
199                         configNow += direction
200                         
201                         if configNow < config_limits[0]:
202                                 configNow = config_limits[0]
203                         elif configNow > config_limits[1]:
204                                 configNow = config_limits[1]
205                         
206                         config.plugins.Mosaic.countdown.value = configNow
207                         config.plugins.Mosaic.countdown.save()
208                         
209                         self.updateCountdownLabel()
210
211         def makeNextScreenshot(self):
212                 # Grab video
213                 if self.container.execute("%s -v %s" % (grab_binary, grab_picture)):
214                         self.showNextScreenshot(-1)
215
216         def showNextScreenshot(self, callback):
217                 # Resize screenshot and show in the current window
218                 picture = loadPic(grab_picture, 180, 144, self.aspect, 1, 0, 1)
219                 self["window" + str(self.current_window)].instance.setPixmap(picture)
220                 
221                 # Hide current video-window and show the running event-name
222                 self["video" + str(self.current_window)].hide()
223                 self["event" + str(self.current_window)].show()
224                 
225                 # Get next ref
226                 self.current_refidx += 1
227                 if self.current_refidx > (len(self.ref_list) -1):
228                         self.current_refidx = 0
229                 
230                 # Play next ref
231                 ref = self.ref_list[self.current_refidx]
232                 info = self.serviceHandler.info(ref)
233                 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
234                 event_name = self.getEventName(info, ref)
235                 self.session.nav.playService(ref)
236                 
237                 # Get next window index
238                 self.current_window += 1
239                 if self.current_window > 9:
240                         self.current_window = 1
241                 
242                 # Save the ref
243                 self.window_refs[self.current_window-1] = ref
244                 
245                 # Save the event-name and hide the label
246                 self["event" + str(self.current_window)].hide()
247                 self["event" + str(self.current_window)].setText(event_name)
248                 
249                 # Show the new video-window
250                 self["video" + str(self.current_window)].show()
251                 self["video" + str(self.current_window)].decoder = 0
252                 
253                 # Show the servicename
254                 self["channel" + str(self.current_window)].setText(name)
255                 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
256                 
257                 # Restart timer
258                 self.working = False
259                 self.updateTimer.start(1, 1)
260
261         def updateCountdown(self, callback=None):
262                 self.countdown -= 1
263                 self.updateCountdownLabel()
264                 if self.countdown == 0:
265                         self.countdown = config.plugins.Mosaic.countdown.value
266                         self.working = True
267                         self.makeNextScreenshot()
268                 else:
269                         self.updateTimer.start(1000, 1)
270
271         def updateCountdownLabel(self):
272                 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
273
274         def getEventName(self, info, ref):
275                 event = info.getEvent(ref)
276                 if event is not None:
277                         eventName = event.getEventName()
278                         if eventName is None:
279                                 eventName = ""
280                 else:
281                         eventName = ""
282                 return eventName
283
284 ################################################
285 # Most stuff stolen from the GraphMultiEPG
286
287 Session = None
288 Servicelist = None
289 BouquetSelectorScreen = None
290
291 def getBouquetServices(bouquet):
292         services = []
293         Servicelist = eServiceCenter.getInstance().list(bouquet)
294         if Servicelist is not None:
295                 while True:
296                         service = Servicelist.getNext()
297                         if not service.valid():
298                                 break
299                         if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
300                                 continue
301                         services.append(service)
302         return services
303
304 def closeBouquetSelectorScreen(ret=None):
305         if BouquetSelectorScreen is not None:
306                 BouquetSelectorScreen.close()
307
308 def openMosaic(bouquet):
309         if bouquet is not None:
310                 services = getBouquetServices(bouquet)
311                 if len(services):
312                         Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
313
314 def main(session, servicelist, **kwargs):
315         global Session
316         Session = session
317         global Servicelist
318         Servicelist = servicelist
319         global BouquetSelectorScreen
320         
321         bouquets = Servicelist.getBouquetList()
322         if bouquets is not None:
323                 if len(bouquets) == 1:
324                         self.openMosaic(bouquets[0][1])
325                 elif len(bouquets) > 1:
326                         BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
327
328 def Plugins(**kwargs):
329         return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)