1 # -*- coding: UTF-8 -*-
3 from Components.ActionMap import NumberActionMap
4 from Components.config import config, ConfigSubsection, ConfigInteger
5 from Components.Console import Console
6 from Components.Label import Label
7 from Components.Language import language
8 from Components.Pixmap import Pixmap
9 from Components.VideoWindow import VideoWindow
10 from enigma import eServiceCenter, eServiceReference, eTimer, getDesktop, loadPNG
11 from os import environ
12 from Plugins.Plugin import PluginDescriptor
13 from Screens.ChannelSelection import BouquetSelector
14 from Screens.MessageBox import MessageBox
15 from Screens.Screen import Screen
16 from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE, SCOPE_LANGUAGE, SCOPE_PLUGINS
17 from Tools.LoadPixmap import LoadPixmap
20 ################################################
22 grab_binary = "/usr/bin/grab"
23 grab_picture = "/tmp/mosaic.jpg"
24 grab_errorlog = "/tmp/mosaic.log"
26 config_limits = (3, 30)
27 config.plugins.Mosaic = ConfigSubsection()
28 config.plugins.Mosaic.countdown = ConfigInteger(default=5, limits=config_limits)
30 playingIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_play.png'))
31 pausedIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_pause.png'))
33 ################################################
35 lang = language.getLanguage()
36 environ["LANGUAGE"] = lang[:2]
\r
37 gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
\r
38 gettext.textdomain("enigma2")
39 gettext.bindtextdomain("Mosaic", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/Mosaic/locale/"))
42 t = gettext.dgettext("Mosaic", txt)
\r
44 t = gettext.gettext(txt)
\r
47 ################################################
53 desktop = getDesktop(0)
56 height = size.height()
57 windowWidth = width / 4
58 windowHeight = height / 4
63 for i in range(1, 10):
64 positions.append([x, y])
66 x += ((width - 160) - (windowWidth * 3)) / 2
67 if (i == 3) or (i == 6):
68 y = y + windowHeight + 20
72 skin += """<screen position="0,0" size="%d,%d" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >""" % (width, height)
73 skin += """<widget name="playState" position="55,55" size="16,16" alphatest="on" />"""
74 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth, windowHeight)
75 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth, windowHeight)
76 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth, windowHeight)
77 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth, windowHeight)
78 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth, windowHeight)
79 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth, windowHeight)
80 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth, windowHeight)
81 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth, windowHeight)
82 skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth, windowHeight)
83 skin += """<widget name="channel1" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[0][0], positions[0][1]-18, windowWidth-4)
84 skin += """<widget name="channel2" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[1][0], positions[1][1]-18, windowWidth-4)
85 skin += """<widget name="channel3" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[2][0], positions[2][1]-18, windowWidth-4)
86 skin += """<widget name="channel4" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[3][0], positions[3][1]-18, windowWidth-4)
87 skin += """<widget name="channel5" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[4][0], positions[4][1]-18, windowWidth-4)
88 skin += """<widget name="channel6" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[5][0], positions[5][1]-18, windowWidth-4)
89 skin += """<widget name="channel7" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[6][0], positions[6][1]-18, windowWidth-4)
90 skin += """<widget name="channel8" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[7][0], positions[7][1]-18, windowWidth-4)
91 skin += """<widget name="channel9" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (positions[8][0], positions[8][1]-18, windowWidth-4)
92 skin += """<widget name="window1" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth, windowHeight)
93 skin += """<widget name="window2" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth, windowHeight)
94 skin += """<widget name="window3" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth, windowHeight)
95 skin += """<widget name="window4" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth, windowHeight)
96 skin += """<widget name="window5" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth, windowHeight)
97 skin += """<widget name="window6" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth, windowHeight)
98 skin += """<widget name="window7" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth, windowHeight)
99 skin += """<widget name="window8" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth, windowHeight)
100 skin += """<widget name="window9" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth, windowHeight)
101 skin += """<widget name="video1" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth, windowHeight)
102 skin += """<widget name="video2" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth, windowHeight)
103 skin += """<widget name="video3" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth, windowHeight)
104 skin += """<widget name="video4" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth, windowHeight)
105 skin += """<widget name="video5" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth, windowHeight)
106 skin += """<widget name="video6" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth, windowHeight)
107 skin += """<widget name="video7" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth, windowHeight)
108 skin += """<widget name="video8" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth, windowHeight)
109 skin += """<widget name="video9" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth, windowHeight)
110 skin += """<widget name="event1" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth)
111 skin += """<widget name="event2" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth)
112 skin += """<widget name="event3" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth)
113 skin += """<widget name="event4" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth)
114 skin += """<widget name="event5" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth)
115 skin += """<widget name="event6" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth)
116 skin += """<widget name="event7" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth)
117 skin += """<widget name="event8" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth)
118 skin += """<widget name="event9" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth)
120 skin += """<widget name="countdown" position="80,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (height-50, windowWidth)
121 skin += """<widget name="count" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" />
122 </screen>""" % (positions[2][0] ,height-50, windowWidth)
124 def __init__(self, session, services):
125 Screen.__init__(self, session)
127 self.session = session
128 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
130 self.Console = Console()
131 self.serviceHandler = eServiceCenter.getInstance()
132 self.ref_list = services
133 self.window_refs = [None, None, None, None, None, None, None, None, None]
134 self.current_refidx = 0
135 self.current_window = 1
136 self.countdown = config.plugins.Mosaic.countdown.value
138 self.state = self.PLAY
140 self["playState"] = Pixmap()
141 for i in range(1, 10):
142 self["window" + str(i)] = Pixmap()
143 self["video" + str(i)] = VideoWindow(decoder=0, fb_width=self.width, fb_height=self.height)
144 self["video" + str(i)].hide()
145 self["channel" + str(i)] = Label("")
146 self["event" + str(i)] = Label("")
147 self["event" + str(i)].hide()
148 self["video1"].decoder = 0
149 self["video1"].show()
150 self["countdown"] = Label()
151 self.updateCountdownLabel()
152 self["count"] = Label()
154 self["actions"] = NumberActionMap(["MosaicActions"],
157 "cancel": self.closeWithOldService,
159 "yellow": self.pause,
160 "channelup": self.countdownPlus,
161 "channeldown": self.countdownMinus,
162 "1": self.numberPressed,
163 "2": self.numberPressed,
164 "3": self.numberPressed,
165 "4": self.numberPressed,
166 "5": self.numberPressed,
167 "6": self.numberPressed,
168 "7": self.numberPressed,
169 "8": self.numberPressed,
170 "9": self.numberPressed
173 self.updateTimer = eTimer()
174 self.updateTimer.callback.append(self.updateCountdown)
175 self.checkTimer = eTimer()
176 self.checkTimer.callback.append(self.checkGrab)
177 self.checkTimer.start(500, 1)
180 # Start the first service in the bouquet and show the service-name
181 ref = self.ref_list[0]
182 self.window_refs[0] = ref
183 info = self.serviceHandler.info(ref)
184 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
185 event_name = self.getEventName(info, ref)
186 self["channel1"].setText(name)
187 self["event1"].setText(event_name)
188 self.session.nav.playService(ref)
189 self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
190 self["playState"].instance.setPixmap(playingIcon)
191 # Start updating the video-screenshots
192 self.updateTimer.start(1, 1)
194 def exit(self, callback=None):
195 self.deleteConsoleCallbacks()
198 def deleteConsoleCallbacks(self):
199 if self.Console.appContainers.has_key(self.consoleCmd):
200 del self.Console.appContainers[self.consoleCmd].dataAvail[:]
201 del self.Console.appContainers[self.consoleCmd].appClosed[:]
202 del self.Console.appContainers[self.consoleCmd]
203 del self.Console.extra_args[self.consoleCmd]
204 del self.Console.callbacks[self.consoleCmd]
206 def closeWithOldService(self):
207 self.session.nav.playService(self.oldService)
208 self.deleteConsoleCallbacks()
211 def numberPressed(self, number):
212 ref = self.window_refs[number-1]
214 self.session.nav.playService(ref)
215 self.deleteConsoleCallbacks()
219 if self.working == False and self.state == self.PAUSE:
220 self.state = self.PLAY
221 self.updateTimer.start(1000, 1)
222 self["playState"].instance.setPixmap(playingIcon)
225 if self.working == False and self.state == self.PLAY:
226 self.state = self.PAUSE
227 self.updateTimer.stop()
228 self["playState"].instance.setPixmap(pausedIcon)
230 def countdownPlus(self):
231 self.changeCountdown(1)
233 def countdownMinus(self):
234 self.changeCountdown(-1)
236 def changeCountdown(self, direction):
237 if self.working == False:
238 configNow = config.plugins.Mosaic.countdown.value
239 configNow += direction
241 if configNow < config_limits[0]:
242 configNow = config_limits[0]
243 elif configNow > config_limits[1]:
244 configNow = config_limits[1]
246 config.plugins.Mosaic.countdown.value = configNow
247 config.plugins.Mosaic.countdown.save()
249 self.updateCountdownLabel()
251 def makeNextScreenshot(self):
254 self.Console = Console()
255 self.consoleCmd = "%s -v -r %d -l -j 100 %s" % (grab_binary, self.windowWidth, grab_picture)
256 self.Console.ePopen(self.consoleCmd, self.showNextScreenshot)
258 def showNextScreenshot(self, result, retval, extra_args):
260 # Show screenshot in the current window
261 pic = LoadPixmap(grab_picture)
262 self["window" + str(self.current_window)].instance.setPixmap(pic)
264 # Hide current video-window and show the running event-name
265 self["video" + str(self.current_window)].hide()
266 self["event" + str(self.current_window)].show()
269 self.current_refidx += 1
270 if self.current_refidx > (len(self.ref_list) -1):
271 self.current_refidx = 0
274 ref = self.ref_list[self.current_refidx]
275 info = self.serviceHandler.info(ref)
276 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
277 event_name = self.getEventName(info, ref)
278 self.session.nav.playService(ref)
280 # Get next window index
281 self.current_window += 1
282 if self.current_window > 9:
283 self.current_window = 1
286 self.window_refs[self.current_window-1] = ref
288 # Save the event-name and hide the label
289 self["event" + str(self.current_window)].hide()
290 self["event" + str(self.current_window)].setText(event_name)
292 # Show the new video-window
293 self["video" + str(self.current_window)].show()
294 self["video" + str(self.current_window)].decoder = 0
296 # Show the servicename
297 self["channel" + str(self.current_window)].setText(name)
298 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
302 self.updateTimer.start(1, 1)
304 print "[Mosaic] retval: %d result: %s" % (retval, result)
307 f = open(grab_errorlog, "w")
308 f.write("retval: %d\nresult: %s" % (retval, result))
313 self.session.openWithCallback(self.exit, MessageBox, _("Error while creating screenshot. You need grab version 0.8 or higher!"), MessageBox.TYPE_ERROR, timeout=5)
315 def updateCountdown(self, callback=None):
317 self.updateCountdownLabel()
318 if self.countdown == 0:
319 self.countdown = config.plugins.Mosaic.countdown.value
321 self.makeNextScreenshot()
323 self.updateTimer.start(1000, 1)
325 def updateCountdownLabel(self):
326 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
328 def getEventName(self, info, ref):
329 event = info.getEvent(ref)
330 if event is not None:
331 eventName = event.getEventName()
332 if eventName is None:
338 ################################################
339 # Most stuff stolen from the GraphMultiEPG
343 BouquetSelectorScreen = None
345 def getBouquetServices(bouquet):
347 Servicelist = eServiceCenter.getInstance().list(bouquet)
348 if Servicelist is not None:
350 service = Servicelist.getNext()
351 if not service.valid():
353 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
355 services.append(service)
358 def closeBouquetSelectorScreen(ret=None):
359 if BouquetSelectorScreen is not None:
360 BouquetSelectorScreen.close()
362 def openMosaic(bouquet):
363 if bouquet is not None:
364 services = getBouquetServices(bouquet)
366 Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
368 def main(session, servicelist, **kwargs):
372 Servicelist = servicelist
373 global BouquetSelectorScreen
375 bouquets = Servicelist.getBouquetList()
376 if bouquets is not None:
377 if len(bouquets) == 1:
378 openMosaic(bouquets[0][1])
379 elif len(bouquets) > 1:
380 BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
382 def Plugins(**kwargs):
383 return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)