1 # -*- coding: UTF-8 -*-
3 # needs the aio-screengrabber v0.8 by seddi
4 from Components.ActionMap import NumberActionMap
5 from Components.config import config, ConfigSubsection, ConfigInteger
6 from Components.Console import Console
7 from Components.Label import Label
8 from Components.Language import language
9 from Components.Pixmap import Pixmap
10 from Components.VideoWindow import VideoWindow
11 from enigma import eServiceCenter, eServiceReference, eTimer, loadPNG
12 from os import environ
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, SCOPE_LANGUAGE
18 from Tools.LoadPixmap import LoadPixmap
21 ################################################
23 grab_binary = "/usr/bin/grab"
24 grab_picture = "/tmp/mosaic.jpg"
25 grab_errorlog = "/tmp/mosaic.log"
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()
112 self.Console = Console()
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)
159 self.checkTimer.start(500, 1)
162 if fileExists(grab_binary):
163 # Start the first service in the bouquet and show the service-name
164 ref = self.ref_list[0]
165 self.window_refs[0] = ref
166 info = self.serviceHandler.info(ref)
167 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
168 event_name = self.getEventName(info, ref)
169 self["channel1"].setText(name)
170 self["event1"].setText(event_name)
171 self.session.nav.playService(ref)
172 self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
173 self["playState"].instance.setPixmap(playingIcon)
175 # Start updating the video-screenshots
176 self.updateTimer.start(1, 1)
178 self.session.openWithCallback(self.exit, MessageBox, _("%s does not exist!") % grab_binary, MessageBox.TYPE_ERROR, timeout=5)
180 def exit(self, callback=None):
181 self.deleteConsoleCallbacks()
184 def deleteConsoleCallbacks(self):
185 if self.Console.appContainers.has_key(self.consoleCmd):
186 del self.Console.appContainers[self.consoleCmd].dataAvail[:]
187 del self.Console.appContainers[self.consoleCmd].appClosed[:]
188 del self.Console.appContainers[self.consoleCmd]
189 del self.Console.extra_args[self.consoleCmd]
190 del self.Console.callbacks[self.consoleCmd]
192 def closeWithOldService(self):
193 self.session.nav.playService(self.oldService)
194 self.deleteConsoleCallbacks()
197 def numberPressed(self, number):
198 ref = self.window_refs[number-1]
200 self.session.nav.playService(ref)
201 self.deleteConsoleCallbacks()
205 if self.working == False and self.state == self.PAUSE:
206 self.state = self.PLAY
207 self.updateTimer.start(1000, 1)
208 self["playState"].instance.setPixmap(playingIcon)
211 if self.working == False and self.state == self.PLAY:
212 self.state = self.PAUSE
213 self.updateTimer.stop()
214 self["playState"].instance.setPixmap(pausedIcon)
216 def countdownPlus(self):
217 self.changeCountdown(1)
219 def countdownMinus(self):
220 self.changeCountdown(-1)
222 def changeCountdown(self, direction):
223 if self.working == False:
224 configNow = config.plugins.Mosaic.countdown.value
225 configNow += direction
227 if configNow < config_limits[0]:
228 configNow = config_limits[0]
229 elif configNow > config_limits[1]:
230 configNow = config_limits[1]
232 config.plugins.Mosaic.countdown.value = configNow
233 config.plugins.Mosaic.countdown.save()
235 self.updateCountdownLabel()
237 def makeNextScreenshot(self):
240 self.Console = Console()
241 self.consoleCmd = "%s -v -r 180 -l -j 100 %s" % (grab_binary, grab_picture)
242 self.Console.ePopen(self.consoleCmd, self.showNextScreenshot)
244 def showNextScreenshot(self, result, retval, extra_args):
246 # Show screenshot in the current window
247 pic = LoadPixmap(grab_picture)
248 self["window" + str(self.current_window)].instance.setPixmap(pic)
250 # Hide current video-window and show the running event-name
251 self["video" + str(self.current_window)].hide()
252 self["event" + str(self.current_window)].show()
255 self.current_refidx += 1
256 if self.current_refidx > (len(self.ref_list) -1):
257 self.current_refidx = 0
260 ref = self.ref_list[self.current_refidx]
261 info = self.serviceHandler.info(ref)
262 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
263 event_name = self.getEventName(info, ref)
264 self.session.nav.playService(ref)
266 # Get next window index
267 self.current_window += 1
268 if self.current_window > 9:
269 self.current_window = 1
272 self.window_refs[self.current_window-1] = ref
274 # Save the event-name and hide the label
275 self["event" + str(self.current_window)].hide()
276 self["event" + str(self.current_window)].setText(event_name)
278 # Show the new video-window
279 self["video" + str(self.current_window)].show()
280 self["video" + str(self.current_window)].decoder = 0
282 # Show the servicename
283 self["channel" + str(self.current_window)].setText(name)
284 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
288 self.updateTimer.start(1, 1)
290 print "[Mosaic] retval: %d result: %s" % (retval, result)
293 f = open(grab_errorlog, "w")
294 f.write("retval: %d\nresult: %s" % (retval, result))
299 self.session.openWithCallback(self.exit, MessageBox, _("Error while creating screenshot. You need grab version 0.8 or higher!"), MessageBox.TYPE_ERROR, timeout=5)
301 def updateCountdown(self, callback=None):
303 self.updateCountdownLabel()
304 if self.countdown == 0:
305 self.countdown = config.plugins.Mosaic.countdown.value
307 self.makeNextScreenshot()
309 self.updateTimer.start(1000, 1)
311 def updateCountdownLabel(self):
312 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
314 def getEventName(self, info, ref):
315 event = info.getEvent(ref)
316 if event is not None:
317 eventName = event.getEventName()
318 if eventName is None:
324 ################################################
325 # Most stuff stolen from the GraphMultiEPG
329 BouquetSelectorScreen = None
331 def getBouquetServices(bouquet):
333 Servicelist = eServiceCenter.getInstance().list(bouquet)
334 if Servicelist is not None:
336 service = Servicelist.getNext()
337 if not service.valid():
339 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
341 services.append(service)
344 def closeBouquetSelectorScreen(ret=None):
345 if BouquetSelectorScreen is not None:
346 BouquetSelectorScreen.close()
348 def openMosaic(bouquet):
349 if bouquet is not None:
350 services = getBouquetServices(bouquet)
352 Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
354 def main(session, servicelist, **kwargs):
358 Servicelist = servicelist
359 global BouquetSelectorScreen
361 bouquets = Servicelist.getBouquetList()
362 if bouquets is not None:
363 if len(bouquets) == 1:
364 self.openMosaic(bouquets[0][1])
365 elif len(bouquets) > 1:
366 BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
368 def Plugins(**kwargs):
369 return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)