Added mosaic plugin
[enigma2-plugins.git] / mosaic / src / plugin.py
1 ##
2 ## Mosaic
3 ## by AliAbdul
4 ## needs the binary 'grab' by seddi in /usr/bin
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.MessageBox import MessageBox
15 from Screens.Screen import Screen
16 from Tools.Directories import fileExists, resolveFilename, SCOPE_SKIN_IMAGE
17
18 ################################################
19
20 grab_binary = "/usr/bin/grab"
21 grab_picture = "/tmp/.mosaic.bmp"
22
23 config_limits = (3, 30)
24 config.plugins.Mosaic = ConfigSubsection()
25 config.plugins.Mosaic.countdown = ConfigInteger(default=5, limits=config_limits)
26
27 playingIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_play.png'))
28 pausedIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_pause.png'))
29
30 ################################################
31
32 class Mosaic(Screen):
33         PLAY = 0
34         PAUSE = 1
35
36         skin = """
37         <screen position="0,0" size="720,576" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >
38                 <widget name="playState" position="55,55" size="16,16" alphatest="on" />
39                 <eLabel position="78,54" size="180,144" />
40                 <eLabel position="274,54" size="180,144" />
41                 <eLabel position="470,54" size="180,144" />
42                 <eLabel position="78,221" size="180,144" />
43                 <eLabel position="274,221" size="180,144" />
44                 <eLabel position="470,221" size="180,144" />
45                 <eLabel position="78,388" size="180,144" />
46                 <eLabel position="274,388" size="180,144" />
47                 <eLabel position="470,388" size="180,144" />
48                 <widget name="label1" position="80,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
49                 <widget name="label2" position="276,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
50                 <widget name="label3" position="472,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
51                 <widget name="label4" position="80,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
52                 <widget name="label5" position="276,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
53                 <widget name="label6" position="472,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
54                 <widget name="label7" position="80,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
55                 <widget name="label8" position="276,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
56                 <widget name="label9" position="472,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
57                 <widget name="window1" position="78,54" zPosition="1" size="180,144" />
58                 <widget name="window2" position="274,54" zPosition="1" size="180,144" />
59                 <widget name="window3" position="470,54" zPosition="1" size="180,144" />
60                 <widget name="window4" position="78,221" zPosition="1" size="180,144" />
61                 <widget name="window5" position="274,221" zPosition="1" size="180,144" />
62                 <widget name="window6" position="470,221" zPosition="1" size="180,144" />
63                 <widget name="window7" position="78,388" zPosition="1" size="180,144" />
64                 <widget name="window8" position="274,388" zPosition="1" size="180,144" />
65                 <widget name="window9" position="470,388" zPosition="1" size="180,144" />
66                 <widget name="video1" position="78,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
67                 <widget name="video2" position="274,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
68                 <widget name="video3" position="470,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
69                 <widget name="video4" position="78,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
70                 <widget name="video5" position="274,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
71                 <widget name="video6" position="470,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
72                 <widget name="video7" position="78,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
73                 <widget name="video8" position="274,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
74                 <widget name="video9" position="470,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
75                 <widget name="event1" position="78,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
76                 <widget name="event2" position="274,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
77                 <widget name="event3" position="470,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
78                 <widget name="event4" position="78,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
79                 <widget name="event5" position="274,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
80                 <widget name="event6" position="470,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
81                 <widget name="event7" position="78,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
82                 <widget name="event8" position="274,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
83                 <widget name="event9" position="470,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
84                 <widget name="countdown" position="80,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
85                 <widget name="count" position="472,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" />
86         </screen>"""
87
88         def __init__(self, session, servicelist):
89                 Screen.__init__(self, session)
90                 
91                 self.session = session
92                 self.servicelist = servicelist
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 = []
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["label" + 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.get().append(self.showNextScreenshot)
144                 self.checkTimer.start(500, 1)
145
146         def checkGrab(self):
147                 if fileExists(grab_binary):
148                         self.firstRun()
149                 else:
150                         self.session.openWithCallback(self.exit, MessageBox, _("%s does not exist!") % grab_binary, MessageBox.TYPE_ERROR, timeout=5)
151
152         def exit(self, callback = None):
153                 self.close()
154
155         def closeWithOldService(self):
156                 self.session.nav.playService(self.oldService)
157                 self.close()
158
159         def numberPressed(self, number):
160                 sRef = self.window_refs[number-1]
161                 if sRef is not None:
162                         ref = eServiceReference(sRef)
163                         self.session.nav.playService(ref)
164                         self.close()
165
166         def play(self):
167                 if self.working == False and self.state == self.PAUSE:
168                         self.state = self.PLAY
169                         self.updateTimer.start(1000, 1)
170                         self["playState"].instance.setPixmap(playingIcon)
171
172         def pause(self):
173                 if self.working == False and self.state == self.PLAY:
174                         self.state = self.PAUSE
175                         self.updateTimer.stop()
176                         self["playState"].instance.setPixmap(pausedIcon)
177
178         def countdownPlus(self):
179                 self.changeCountdown(1)
180
181         def countdownMinus(self):
182                 self.changeCountdown(-1)
183
184         def changeCountdown(self, direction):
185                 if self.working == False:
186                         configNow = config.plugins.Mosaic.countdown.value
187                         configNow += direction
188                         
189                         if configNow < config_limits[0]:
190                                 configNow = config_limits[0]
191                         elif configNow > config_limits[1]:
192                                 configNow = config_limits[1]
193                         
194                         config.plugins.Mosaic.countdown.value = configNow
195                         config.plugins.Mosaic.countdown.save()
196                         
197                         self.updateCountdownLabel()
198
199         def firstRun(self):
200                 # Get the current bouquet
201                 bouquet = None
202                 bouquets = self.servicelist.getBouquetList()
203                 if bouquets is not None:
204                         if len(bouquets) == 1:
205                                 bouquet = bouquets[0][1]
206                         else:
207                                 # Multibouquet activated => get the root first
208                                 root = self.servicelist.getRoot()
209                                 idx = 0
210                                 for x in bouquets:
211                                         if x[1] == root:
212                                                 # Current bouquet
213                                                 bouquet = bouquets[idx][1]
214                                         else:
215                                                 idx += 1
216                 
217                 if bouquet is not None:
218                         # Get the channels from the current bouquet
219                         services = self.serviceHandler.list(bouquet)
220                         channels = services and services.getContent("SN", True)
221                         
222                         for channel in channels:
223                                 ref = channel[0]
224                                 if not ref.startswith("1:64:"): # Ignore marker
225                                         self.ref_list.append(ref)
226                         if len(self.ref_list) > 1:
227                                 # Start the first service in the bouquet and show the service-name
228                                 sRef = self.ref_list[0]
229                                 self.window_refs[0] = sRef
230                                 ref = eServiceReference(sRef)
231                                 info = self.serviceHandler.info(ref)
232                                 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
233                                 event_name = self.getEventName(info, ref)
234                                 self["label1"].setText(name)
235                                 self["event1"].setText(event_name)
236                                 self.session.nav.playService(ref)
237                                 self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
238                                 self["playState"].instance.setPixmap(playingIcon)
239                                 
240                                 # Start updating the video-screenshots
241                                 self.updateTimer.start(1, 1)
242                 else:
243                         log = "Error reading your channel-list!\n"
244                         log += "Bouquets:\n"
245                         log += str(bouquets)
246                         log += "\nContent:\n"
247                         for x in bouquets:
248                                 log += str(x[1])
249                                 log += "\n"
250                         
251                         try:
252                                 f = open("/tmp/mosaic.log", "w")
253                                 f.write(log)
254                                 f.close()
255                         except:
256                                 pass
257                         
258                         self.session.openWithCallback(self.exit, MessageBox, _("Error while reading the channel-list!\nPlease send the file /tmp/mosaic.log to:\naliabdul1978 at hotmail dot de."), MessageBox.TYPE_ERROR, timeout=5)
259
260         def makeNextScreenshot(self):
261                 # Grab video
262                 if self.container.execute("%s -v %s" % (grab_binary, grab_picture)):
263                         self.showNextScreenshot(-1)
264
265         def showNextScreenshot(self, callback):
266                 # Resize screenshot and show in the current window
267                 picture = loadPic(grab_picture, 180, 144, self.aspect, 1, 0, 1)
268                 self["window" + str(self.current_window)].instance.setPixmap(picture)
269                 
270                 # Hide current video-window and show the running event-name
271                 self["video" + str(self.current_window)].hide()
272                 self["event" + str(self.current_window)].show()
273                 
274                 # Get next ref
275                 self.current_refidx += 1
276                 if self.current_refidx > (len(self.ref_list) -1):
277                         self.current_refidx = 0
278                 
279                 # Play next ref
280                 sRef = self.ref_list[self.current_refidx]
281                 ref = eServiceReference(sRef)
282                 info = self.serviceHandler.info(ref)
283                 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
284                 event_name = self.getEventName(info, ref)
285                 self.session.nav.playService(ref)
286                 
287                 # Get next window index
288                 self.current_window += 1
289                 if self.current_window > 9:
290                         self.current_window = 1
291                 
292                 # Save the sRef
293                 self.window_refs[self.current_window-1] = sRef
294                 
295                 # Save the event-name and hide the label
296                 self["event" + str(self.current_window)].hide()
297                 self["event" + str(self.current_window)].setText(event_name)
298                 
299                 # Show the new video-window
300                 self["video" + str(self.current_window)].show()
301                 self["video" + str(self.current_window)].decoder = 0
302                 
303                 # Show the servicename
304                 self["label" + str(self.current_window)].setText(name)
305                 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
306                 
307                 # Restart timer
308                 self.working = False
309                 self.updateTimer.start(1, 1)
310
311         def updateCountdown(self, callback = None):
312                 self.countdown -= 1
313                 self.updateCountdownLabel()
314                 if self.countdown == 0:
315                         self.countdown = config.plugins.Mosaic.countdown.value
316                         self.working = True
317                         self.makeNextScreenshot()
318                 else:
319                         self.updateTimer.start(1000, 1)
320
321         def updateCountdownLabel(self):
322                 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
323
324         def getEventName(self, info, ref):
325                 event = info.getEvent(ref)
326                 if event is not None:
327                         eventName = event.getEventName()
328                         if eventName is None:
329                                 eventName = ""
330                 else:
331                         eventName = ""
332                 return eventName
333
334 ################################################
335
336 def main(session, servicelist, **kwargs):
337         session.open(Mosaic, servicelist)
338
339 def Plugins(**kwargs):
340         return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)