4 ## needs the aio-screengrabber by seddi
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.Language import language
11 from Components.Pixmap import Pixmap
12 from Components.VideoWindow import VideoWindow
13 from enigma import eConsoleAppContainer, eServiceCenter, eServiceReference, eTimer, loadPic, loadPNG
14 from os import environ
15 from Plugins.Plugin import PluginDescriptor
16 from Screens.ChannelSelection import BouquetSelector
17 from Screens.MessageBox import MessageBox
18 from Screens.Screen import Screen
19 from Tools.Directories import fileExists, resolveFilename, SCOPE_SKIN_IMAGE, SCOPE_LANGUAGE
22 ################################################
24 grab_binary = "/usr/bin/grab"
25 grab_picture = "/tmp/.mosaic.bmp"
27 config_limits = (3, 30)
28 config.plugins.Mosaic = ConfigSubsection()
29 config.plugins.Mosaic.countdown = ConfigInteger(default=5, limits=config_limits)
31 playingIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_play.png'))
32 pausedIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_pause.png'))
34 ################################################
36 lang = language.getLanguage()
37 environ["LANGUAGE"] = lang[:2]
\r
38 gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
\r
39 gettext.textdomain("enigma2")
\r
40 gettext.bindtextdomain("Mosaic", resolveFilename(SCOPE_LANGUAGE))
43 t = gettext.dgettext("Mosaic", txt)
\r
45 t = gettext.gettext(txt)
\r
48 ################################################
55 <screen position="0,0" size="720,576" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >
56 <widget name="playState" position="55,55" size="16,16" alphatest="on" />
57 <eLabel position="78,54" size="180,144" />
58 <eLabel position="274,54" size="180,144" />
59 <eLabel position="470,54" size="180,144" />
60 <eLabel position="78,221" size="180,144" />
61 <eLabel position="274,221" size="180,144" />
62 <eLabel position="470,221" size="180,144" />
63 <eLabel position="78,388" size="180,144" />
64 <eLabel position="274,388" size="180,144" />
65 <eLabel position="470,388" size="180,144" />
66 <widget name="channel1" position="80,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
67 <widget name="channel2" position="276,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
68 <widget name="channel3" position="472,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
69 <widget name="channel4" position="80,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
70 <widget name="channel5" position="276,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
71 <widget name="channel6" position="472,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
72 <widget name="channel7" position="80,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
73 <widget name="channel8" position="276,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
74 <widget name="channel9" position="472,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
75 <widget name="window1" position="78,54" zPosition="1" size="180,144" />
76 <widget name="window2" position="274,54" zPosition="1" size="180,144" />
77 <widget name="window3" position="470,54" zPosition="1" size="180,144" />
78 <widget name="window4" position="78,221" zPosition="1" size="180,144" />
79 <widget name="window5" position="274,221" zPosition="1" size="180,144" />
80 <widget name="window6" position="470,221" zPosition="1" size="180,144" />
81 <widget name="window7" position="78,388" zPosition="1" size="180,144" />
82 <widget name="window8" position="274,388" zPosition="1" size="180,144" />
83 <widget name="window9" position="470,388" zPosition="1" size="180,144" />
84 <widget name="video1" position="78,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
85 <widget name="video2" position="274,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
86 <widget name="video3" position="470,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
87 <widget name="video4" position="78,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
88 <widget name="video5" position="274,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
89 <widget name="video6" position="470,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
90 <widget name="video7" position="78,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
91 <widget name="video8" position="274,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
92 <widget name="video9" position="470,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
93 <widget name="event1" position="78,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
94 <widget name="event2" position="274,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
95 <widget name="event3" position="470,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
96 <widget name="event4" position="78,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
97 <widget name="event5" position="274,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
98 <widget name="event6" position="470,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
99 <widget name="event7" position="78,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
100 <widget name="event8" position="274,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
101 <widget name="event9" position="470,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
102 <widget name="countdown" position="80,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
103 <widget name="count" position="472,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" />
106 def __init__(self, session, services):
107 Screen.__init__(self, session)
109 self.session = session
110 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
111 self.container = eConsoleAppContainer()
112 self.aspect = AVSwitch().getAspectRatioSetting()
113 self.serviceHandler = eServiceCenter.getInstance()
114 self.ref_list = services
115 self.window_refs = [None, None, None, None, None, None, None, None, None]
116 self.current_refidx = 0
117 self.current_window = 1
118 self.countdown = config.plugins.Mosaic.countdown.value
120 self.state = self.PLAY
122 self["playState"] = Pixmap()
123 for i in range(1, 10):
124 self["window" + str(i)] = Pixmap()
125 self["video" + str(i)] = VideoWindow(decoder = 0)
126 self["video" + str(i)].hide()
127 self["channel" + str(i)] = Label("")
128 self["event" + str(i)] = Label("")
129 self["event" + str(i)].hide()
130 self["video1"].decoder = 0
131 self["video1"].show()
132 self["countdown"] = Label()
133 self.updateCountdownLabel()
134 self["count"] = Label()
136 self["actions"] = NumberActionMap(["MosaicActions"],
139 "cancel": self.closeWithOldService,
141 "yellow": self.pause,
142 "channelup": self.countdownPlus,
143 "channeldown": self.countdownMinus,
144 "1": self.numberPressed,
145 "2": self.numberPressed,
146 "3": self.numberPressed,
147 "4": self.numberPressed,
148 "5": self.numberPressed,
149 "6": self.numberPressed,
150 "7": self.numberPressed,
151 "8": self.numberPressed,
152 "9": self.numberPressed
155 self.updateTimer = eTimer()
156 self.updateTimer.timeout.get().append(self.updateCountdown)
157 self.checkTimer = eTimer()
158 self.checkTimer.timeout.get().append(self.checkGrab)
160 self.container.appClosed.append(self.showNextScreenshot)
161 self.checkTimer.start(500, 1)
164 if fileExists(grab_binary):
165 # Start the first service in the bouquet and show the service-name
166 ref = self.ref_list[0]
167 self.window_refs[0] = ref
168 info = self.serviceHandler.info(ref)
169 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
170 event_name = self.getEventName(info, ref)
171 self["channel1"].setText(name)
172 self["event1"].setText(event_name)
173 self.session.nav.playService(ref)
174 self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
175 self["playState"].instance.setPixmap(playingIcon)
177 # Start updating the video-screenshots
178 self.updateTimer.start(1, 1)
180 self.session.openWithCallback(self.exit, MessageBox, _("%s does not exist!") % grab_binary, MessageBox.TYPE_ERROR, timeout=5)
182 def exit(self, callback=None):
185 def closeWithOldService(self):
186 self.session.nav.playService(self.oldService)
189 def numberPressed(self, number):
190 ref = self.window_refs[number-1]
192 self.session.nav.playService(ref)
196 if self.working == False and self.state == self.PAUSE:
197 self.state = self.PLAY
198 self.updateTimer.start(1000, 1)
199 self["playState"].instance.setPixmap(playingIcon)
202 if self.working == False and self.state == self.PLAY:
203 self.state = self.PAUSE
204 self.updateTimer.stop()
205 self["playState"].instance.setPixmap(pausedIcon)
207 def countdownPlus(self):
208 self.changeCountdown(1)
210 def countdownMinus(self):
211 self.changeCountdown(-1)
213 def changeCountdown(self, direction):
214 if self.working == False:
215 configNow = config.plugins.Mosaic.countdown.value
216 configNow += direction
218 if configNow < config_limits[0]:
219 configNow = config_limits[0]
220 elif configNow > config_limits[1]:
221 configNow = config_limits[1]
223 config.plugins.Mosaic.countdown.value = configNow
224 config.plugins.Mosaic.countdown.save()
226 self.updateCountdownLabel()
228 def makeNextScreenshot(self):
230 if self.container.execute("%s -v %s" % (grab_binary, grab_picture)):
231 self.showNextScreenshot(-1)
233 def showNextScreenshot(self, callback):
234 # Resize screenshot and show in the current window
235 picture = loadPic(grab_picture, 180, 144, self.aspect, 1, 0, 1)
236 self["window" + str(self.current_window)].instance.setPixmap(picture)
238 # Hide current video-window and show the running event-name
239 self["video" + str(self.current_window)].hide()
240 self["event" + str(self.current_window)].show()
243 self.current_refidx += 1
244 if self.current_refidx > (len(self.ref_list) -1):
245 self.current_refidx = 0
248 ref = self.ref_list[self.current_refidx]
249 info = self.serviceHandler.info(ref)
250 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
251 event_name = self.getEventName(info, ref)
252 self.session.nav.playService(ref)
254 # Get next window index
255 self.current_window += 1
256 if self.current_window > 9:
257 self.current_window = 1
260 self.window_refs[self.current_window-1] = ref
262 # Save the event-name and hide the label
263 self["event" + str(self.current_window)].hide()
264 self["event" + str(self.current_window)].setText(event_name)
266 # Show the new video-window
267 self["video" + str(self.current_window)].show()
268 self["video" + str(self.current_window)].decoder = 0
270 # Show the servicename
271 self["channel" + str(self.current_window)].setText(name)
272 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
276 self.updateTimer.start(1, 1)
278 def updateCountdown(self, callback=None):
280 self.updateCountdownLabel()
281 if self.countdown == 0:
282 self.countdown = config.plugins.Mosaic.countdown.value
284 self.makeNextScreenshot()
286 self.updateTimer.start(1000, 1)
288 def updateCountdownLabel(self):
289 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
291 def getEventName(self, info, ref):
292 event = info.getEvent(ref)
293 if event is not None:
294 eventName = event.getEventName()
295 if eventName is None:
301 ################################################
302 # Most stuff stolen from the GraphMultiEPG
306 BouquetSelectorScreen = None
308 def getBouquetServices(bouquet):
310 Servicelist = eServiceCenter.getInstance().list(bouquet)
311 if Servicelist is not None:
313 service = Servicelist.getNext()
314 if not service.valid():
316 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
318 services.append(service)
321 def closeBouquetSelectorScreen(ret=None):
322 if BouquetSelectorScreen is not None:
323 BouquetSelectorScreen.close()
325 def openMosaic(bouquet):
326 if bouquet is not None:
327 services = getBouquetServices(bouquet)
329 Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
331 def main(session, servicelist, **kwargs):
335 Servicelist = servicelist
336 global BouquetSelectorScreen
338 bouquets = Servicelist.getBouquetList()
339 if bouquets is not None:
340 if len(bouquets) == 1:
341 self.openMosaic(bouquets[0][1])
342 elif len(bouquets) > 1:
343 BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
345 def Plugins(**kwargs):
346 return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)