Mon, 16 Jan 2012 22:56:52 +0100
Import original vendor code for correction and improvement.
mosaic/control | file | annotate | diff | comparison | revisions | |
mosaic/plugin.py | file | annotate | diff | comparison | revisions |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mosaic/control Mon Jan 16 22:56:52 2012 +0100 1.3 @@ -0,0 +1,6 @@ 1.4 +Package: enigma2-plugin-extensions-mosaic 1.5 +Version: 0.1-r0 1.6 +Description: Shows you screenshots of the services in a selected bouquet 1.7 +Maintainer: Nabil Hanna <nabil1978@web.de> 1.8 +Homepage: http://www.lt-forums.org/ali 1.9 +Depends: enigma2 (>= 2.6git20090724), aio-grab (>= 0.8cvs20081209)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/mosaic/plugin.py Mon Jan 16 22:56:52 2012 +0100 2.3 @@ -0,0 +1,383 @@ 2.4 +# -*- coding: UTF-8 -*- 2.5 +# Mosaic by AliAbdul 2.6 +from Components.ActionMap import NumberActionMap 2.7 +from Components.config import config, ConfigSubsection, ConfigInteger 2.8 +from Components.Console import Console 2.9 +from Components.Label import Label 2.10 +from Components.Language import language 2.11 +from Components.Pixmap import Pixmap 2.12 +from Components.VideoWindow import VideoWindow 2.13 +from enigma import eServiceCenter, eServiceReference, eTimer, getDesktop, loadPNG 2.14 +from os import environ 2.15 +from Plugins.Plugin import PluginDescriptor 2.16 +from Screens.ChannelSelection import BouquetSelector 2.17 +from Screens.MessageBox import MessageBox 2.18 +from Screens.Screen import Screen 2.19 +from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE, SCOPE_LANGUAGE, SCOPE_PLUGINS 2.20 +from Tools.LoadPixmap import LoadPixmap 2.21 +import gettext 2.22 + 2.23 +################################################ 2.24 + 2.25 +grab_binary = "/usr/bin/grab" 2.26 +grab_picture = "/tmp/mosaic.jpg" 2.27 +grab_errorlog = "/tmp/mosaic.log" 2.28 + 2.29 +config_limits = (3, 30) 2.30 +config.plugins.Mosaic = ConfigSubsection() 2.31 +config.plugins.Mosaic.countdown = ConfigInteger(default=5, limits=config_limits) 2.32 + 2.33 +playingIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_play.png')) 2.34 +pausedIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_pause.png')) 2.35 + 2.36 +################################################ 2.37 + 2.38 +lang = language.getLanguage() 2.39 +environ["LANGUAGE"] = lang[:2] 2.40 +gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE)) 2.41 +gettext.textdomain("enigma2") 2.42 +gettext.bindtextdomain("Mosaic", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/Mosaic/locale/")) 2.43 + 2.44 +def _(txt): 2.45 + t = gettext.dgettext("Mosaic", txt) 2.46 + if t == txt: 2.47 + t = gettext.gettext(txt) 2.48 + return t 2.49 + 2.50 +################################################ 2.51 + 2.52 +class Mosaic(Screen): 2.53 + PLAY = 0 2.54 + PAUSE = 1 2.55 + 2.56 + desktop = getDesktop(0) 2.57 + size = desktop.size() 2.58 + width = size.width() 2.59 + height = size.height() 2.60 + windowWidth = width / 4 2.61 + windowHeight = height / 4 2.62 + 2.63 + positions = [] 2.64 + x = 80 2.65 + y = 50 2.66 + for i in range(1, 10): 2.67 + positions.append([x, y]) 2.68 + x += windowWidth 2.69 + x += ((width - 160) - (windowWidth * 3)) / 2 2.70 + if (i == 3) or (i == 6): 2.71 + y = y + windowHeight + 20 2.72 + x = 80 2.73 + 2.74 + skin = "" 2.75 + skin += """<screen position="0,0" size="%d,%d" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >""" % (width, height) 2.76 + skin += """<widget name="playState" position="55,55" size="16,16" alphatest="on" />""" 2.77 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth, windowHeight) 2.78 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth, windowHeight) 2.79 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth, windowHeight) 2.80 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth, windowHeight) 2.81 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth, windowHeight) 2.82 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth, windowHeight) 2.83 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth, windowHeight) 2.84 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth, windowHeight) 2.85 + skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth, windowHeight) 2.86 + 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) 2.87 + 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) 2.88 + 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) 2.89 + 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) 2.90 + 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) 2.91 + 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) 2.92 + 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) 2.93 + 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) 2.94 + 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) 2.95 + skin += """<widget name="window1" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth, windowHeight) 2.96 + skin += """<widget name="window2" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth, windowHeight) 2.97 + skin += """<widget name="window3" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth, windowHeight) 2.98 + skin += """<widget name="window4" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth, windowHeight) 2.99 + skin += """<widget name="window5" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth, windowHeight) 2.100 + skin += """<widget name="window6" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth, windowHeight) 2.101 + skin += """<widget name="window7" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth, windowHeight) 2.102 + skin += """<widget name="window8" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth, windowHeight) 2.103 + skin += """<widget name="window9" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth, windowHeight) 2.104 + skin += """<widget name="video1" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth, windowHeight) 2.105 + skin += """<widget name="video2" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth, windowHeight) 2.106 + skin += """<widget name="video3" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth, windowHeight) 2.107 + skin += """<widget name="video4" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth, windowHeight) 2.108 + skin += """<widget name="video5" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth, windowHeight) 2.109 + skin += """<widget name="video6" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth, windowHeight) 2.110 + skin += """<widget name="video7" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth, windowHeight) 2.111 + skin += """<widget name="video8" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth, windowHeight) 2.112 + skin += """<widget name="video9" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth, windowHeight) 2.113 + 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) 2.114 + 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) 2.115 + 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) 2.116 + 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) 2.117 + 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) 2.118 + 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) 2.119 + 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) 2.120 + 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) 2.121 + 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) 2.122 + 2.123 + skin += """<widget name="countdown" position="80,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />""" % (height-50, windowWidth) 2.124 + skin += """<widget name="count" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" /> 2.125 + </screen>""" % (positions[2][0] ,height-50, windowWidth) 2.126 + 2.127 + def __init__(self, session, services): 2.128 + Screen.__init__(self, session) 2.129 + 2.130 + self.session = session 2.131 + self.oldService = self.session.nav.getCurrentlyPlayingServiceReference() 2.132 + self.consoleCmd = "" 2.133 + self.Console = Console() 2.134 + self.serviceHandler = eServiceCenter.getInstance() 2.135 + self.ref_list = services 2.136 + self.window_refs = [None, None, None, None, None, None, None, None, None] 2.137 + self.current_refidx = 0 2.138 + self.current_window = 1 2.139 + self.countdown = config.plugins.Mosaic.countdown.value 2.140 + self.working = False 2.141 + self.state = self.PLAY 2.142 + 2.143 + self["playState"] = Pixmap() 2.144 + for i in range(1, 10): 2.145 + self["window" + str(i)] = Pixmap() 2.146 + self["video" + str(i)] = VideoWindow(decoder=0, fb_width=self.width, fb_height=self.height) 2.147 + self["video" + str(i)].hide() 2.148 + self["channel" + str(i)] = Label("") 2.149 + self["event" + str(i)] = Label("") 2.150 + self["event" + str(i)].hide() 2.151 + self["video1"].decoder = 0 2.152 + self["video1"].show() 2.153 + self["countdown"] = Label() 2.154 + self.updateCountdownLabel() 2.155 + self["count"] = Label() 2.156 + 2.157 + self["actions"] = NumberActionMap(["MosaicActions"], 2.158 + { 2.159 + "ok": self.exit, 2.160 + "cancel": self.closeWithOldService, 2.161 + "green": self.play, 2.162 + "yellow": self.pause, 2.163 + "channelup": self.countdownPlus, 2.164 + "channeldown": self.countdownMinus, 2.165 + "1": self.numberPressed, 2.166 + "2": self.numberPressed, 2.167 + "3": self.numberPressed, 2.168 + "4": self.numberPressed, 2.169 + "5": self.numberPressed, 2.170 + "6": self.numberPressed, 2.171 + "7": self.numberPressed, 2.172 + "8": self.numberPressed, 2.173 + "9": self.numberPressed 2.174 + }, prio=-1) 2.175 + 2.176 + self.updateTimer = eTimer() 2.177 + self.updateTimer.callback.append(self.updateCountdown) 2.178 + self.checkTimer = eTimer() 2.179 + self.checkTimer.callback.append(self.checkGrab) 2.180 + self.checkTimer.start(500, 1) 2.181 + 2.182 + def checkGrab(self): 2.183 + # Start the first service in the bouquet and show the service-name 2.184 + ref = self.ref_list[0] 2.185 + self.window_refs[0] = ref 2.186 + info = self.serviceHandler.info(ref) 2.187 + name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '') 2.188 + event_name = self.getEventName(info, ref) 2.189 + self["channel1"].setText(name) 2.190 + self["event1"].setText(event_name) 2.191 + self.session.nav.playService(ref) 2.192 + self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list))) 2.193 + self["playState"].instance.setPixmap(playingIcon) 2.194 + # Start updating the video-screenshots 2.195 + self.updateTimer.start(1, 1) 2.196 + 2.197 + def exit(self, callback=None): 2.198 + self.deleteConsoleCallbacks() 2.199 + self.close() 2.200 + 2.201 + def deleteConsoleCallbacks(self): 2.202 + if self.Console.appContainers.has_key(self.consoleCmd): 2.203 + del self.Console.appContainers[self.consoleCmd].dataAvail[:] 2.204 + del self.Console.appContainers[self.consoleCmd].appClosed[:] 2.205 + del self.Console.appContainers[self.consoleCmd] 2.206 + del self.Console.extra_args[self.consoleCmd] 2.207 + del self.Console.callbacks[self.consoleCmd] 2.208 + 2.209 + def closeWithOldService(self): 2.210 + self.session.nav.playService(self.oldService) 2.211 + self.deleteConsoleCallbacks() 2.212 + self.close() 2.213 + 2.214 + def numberPressed(self, number): 2.215 + ref = self.window_refs[number-1] 2.216 + if ref is not None: 2.217 + self.session.nav.playService(ref) 2.218 + self.deleteConsoleCallbacks() 2.219 + self.close() 2.220 + 2.221 + def play(self): 2.222 + if self.working == False and self.state == self.PAUSE: 2.223 + self.state = self.PLAY 2.224 + self.updateTimer.start(1000, 1) 2.225 + self["playState"].instance.setPixmap(playingIcon) 2.226 + 2.227 + def pause(self): 2.228 + if self.working == False and self.state == self.PLAY: 2.229 + self.state = self.PAUSE 2.230 + self.updateTimer.stop() 2.231 + self["playState"].instance.setPixmap(pausedIcon) 2.232 + 2.233 + def countdownPlus(self): 2.234 + self.changeCountdown(1) 2.235 + 2.236 + def countdownMinus(self): 2.237 + self.changeCountdown(-1) 2.238 + 2.239 + def changeCountdown(self, direction): 2.240 + if self.working == False: 2.241 + configNow = config.plugins.Mosaic.countdown.value 2.242 + configNow += direction 2.243 + 2.244 + if configNow < config_limits[0]: 2.245 + configNow = config_limits[0] 2.246 + elif configNow > config_limits[1]: 2.247 + configNow = config_limits[1] 2.248 + 2.249 + config.plugins.Mosaic.countdown.value = configNow 2.250 + config.plugins.Mosaic.countdown.save() 2.251 + 2.252 + self.updateCountdownLabel() 2.253 + 2.254 + def makeNextScreenshot(self): 2.255 + # Grab video 2.256 + if not self.Console: 2.257 + self.Console = Console() 2.258 + self.consoleCmd = "%s -v -r %d -l -j 100 %s" % (grab_binary, self.windowWidth, grab_picture) 2.259 + self.Console.ePopen(self.consoleCmd, self.showNextScreenshot) 2.260 + 2.261 + def showNextScreenshot(self, result, retval, extra_args): 2.262 + if retval == 0: 2.263 + # Show screenshot in the current window 2.264 + pic = LoadPixmap(grab_picture) 2.265 + self["window" + str(self.current_window)].instance.setPixmap(pic) 2.266 + 2.267 + # Hide current video-window and show the running event-name 2.268 + self["video" + str(self.current_window)].hide() 2.269 + self["event" + str(self.current_window)].show() 2.270 + 2.271 + # Get next ref 2.272 + self.current_refidx += 1 2.273 + if self.current_refidx > (len(self.ref_list) -1): 2.274 + self.current_refidx = 0 2.275 + 2.276 + # Play next ref 2.277 + ref = self.ref_list[self.current_refidx] 2.278 + info = self.serviceHandler.info(ref) 2.279 + name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '') 2.280 + event_name = self.getEventName(info, ref) 2.281 + self.session.nav.playService(ref) 2.282 + 2.283 + # Get next window index 2.284 + self.current_window += 1 2.285 + if self.current_window > 9: 2.286 + self.current_window = 1 2.287 + 2.288 + # Save the ref 2.289 + self.window_refs[self.current_window-1] = ref 2.290 + 2.291 + # Save the event-name and hide the label 2.292 + self["event" + str(self.current_window)].hide() 2.293 + self["event" + str(self.current_window)].setText(event_name) 2.294 + 2.295 + # Show the new video-window 2.296 + self["video" + str(self.current_window)].show() 2.297 + self["video" + str(self.current_window)].decoder = 0 2.298 + 2.299 + # Show the servicename 2.300 + self["channel" + str(self.current_window)].setText(name) 2.301 + self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list))) 2.302 + 2.303 + # Restart timer 2.304 + self.working = False 2.305 + self.updateTimer.start(1, 1) 2.306 + else: 2.307 + print "[Mosaic] retval: %d result: %s" % (retval, result) 2.308 + 2.309 + try: 2.310 + f = open(grab_errorlog, "w") 2.311 + f.write("retval: %d\nresult: %s" % (retval, result)) 2.312 + f.close() 2.313 + except: 2.314 + pass 2.315 + 2.316 + self.session.openWithCallback(self.exit, MessageBox, _("Error while creating screenshot. You need grab version 0.8 or higher!"), MessageBox.TYPE_ERROR, timeout=5) 2.317 + 2.318 + def updateCountdown(self, callback=None): 2.319 + self.countdown -= 1 2.320 + self.updateCountdownLabel() 2.321 + if self.countdown == 0: 2.322 + self.countdown = config.plugins.Mosaic.countdown.value 2.323 + self.working = True 2.324 + self.makeNextScreenshot() 2.325 + else: 2.326 + self.updateTimer.start(1000, 1) 2.327 + 2.328 + def updateCountdownLabel(self): 2.329 + self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value))) 2.330 + 2.331 + def getEventName(self, info, ref): 2.332 + event = info.getEvent(ref) 2.333 + if event is not None: 2.334 + eventName = event.getEventName() 2.335 + if eventName is None: 2.336 + eventName = "" 2.337 + else: 2.338 + eventName = "" 2.339 + return eventName 2.340 + 2.341 +################################################ 2.342 +# Most stuff stolen from the GraphMultiEPG 2.343 + 2.344 +Session = None 2.345 +Servicelist = None 2.346 +BouquetSelectorScreen = None 2.347 + 2.348 +def getBouquetServices(bouquet): 2.349 + services = [] 2.350 + Servicelist = eServiceCenter.getInstance().list(bouquet) 2.351 + if Servicelist is not None: 2.352 + while True: 2.353 + service = Servicelist.getNext() 2.354 + if not service.valid(): 2.355 + break 2.356 + if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): 2.357 + continue 2.358 + services.append(service) 2.359 + return services 2.360 + 2.361 +def closeBouquetSelectorScreen(ret=None): 2.362 + if BouquetSelectorScreen is not None: 2.363 + BouquetSelectorScreen.close() 2.364 + 2.365 +def openMosaic(bouquet): 2.366 + if bouquet is not None: 2.367 + services = getBouquetServices(bouquet) 2.368 + if len(services): 2.369 + Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services) 2.370 + 2.371 +def main(session, servicelist, **kwargs): 2.372 + global Session 2.373 + Session = session 2.374 + global Servicelist 2.375 + Servicelist = servicelist 2.376 + global BouquetSelectorScreen 2.377 + 2.378 + bouquets = Servicelist.getBouquetList() 2.379 + if bouquets is not None: 2.380 + if len(bouquets) == 1: 2.381 + openMosaic(bouquets[0][1]) 2.382 + elif len(bouquets) > 1: 2.383 + BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True) 2.384 + 2.385 +def Plugins(**kwargs): 2.386 + return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)