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, 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 ################################################
54 <screen position="0,0" size="720,576" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >
55 <widget name="playState" position="55,55" size="16,16" alphatest="on" />
56 <eLabel position="78,54" size="180,144" />
57 <eLabel position="274,54" size="180,144" />
58 <eLabel position="470,54" size="180,144" />
59 <eLabel position="78,221" size="180,144" />
60 <eLabel position="274,221" size="180,144" />
61 <eLabel position="470,221" size="180,144" />
62 <eLabel position="78,388" size="180,144" />
63 <eLabel position="274,388" size="180,144" />
64 <eLabel position="470,388" size="180,144" />
65 <widget name="channel1" position="80,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
66 <widget name="channel2" position="276,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
67 <widget name="channel3" position="472,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
68 <widget name="channel4" position="80,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
69 <widget name="channel5" position="276,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
70 <widget name="channel6" position="472,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
71 <widget name="channel7" position="80,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
72 <widget name="channel8" position="276,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
73 <widget name="channel9" position="472,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
74 <widget name="window1" position="78,54" zPosition="1" size="180,144" />
75 <widget name="window2" position="274,54" zPosition="1" size="180,144" />
76 <widget name="window3" position="470,54" zPosition="1" size="180,144" />
77 <widget name="window4" position="78,221" zPosition="1" size="180,144" />
78 <widget name="window5" position="274,221" zPosition="1" size="180,144" />
79 <widget name="window6" position="470,221" zPosition="1" size="180,144" />
80 <widget name="window7" position="78,388" zPosition="1" size="180,144" />
81 <widget name="window8" position="274,388" zPosition="1" size="180,144" />
82 <widget name="window9" position="470,388" zPosition="1" size="180,144" />
83 <widget name="video1" position="78,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
84 <widget name="video2" position="274,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
85 <widget name="video3" position="470,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
86 <widget name="video4" position="78,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
87 <widget name="video5" position="274,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
88 <widget name="video6" position="470,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
89 <widget name="video7" position="78,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
90 <widget name="video8" position="274,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
91 <widget name="video9" position="470,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
92 <widget name="event1" position="78,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
93 <widget name="event2" position="274,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
94 <widget name="event3" position="470,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
95 <widget name="event4" position="78,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
96 <widget name="event5" position="274,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
97 <widget name="event6" position="470,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
98 <widget name="event7" position="78,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
99 <widget name="event8" position="274,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
100 <widget name="event9" position="470,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
101 <widget name="countdown" position="80,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
102 <widget name="count" position="472,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" />
105 def __init__(self, session, services):
106 Screen.__init__(self, session)
108 self.session = session
109 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
111 self.Console = Console()
112 self.serviceHandler = eServiceCenter.getInstance()
113 self.ref_list = services
114 self.window_refs = [None, None, None, None, None, None, None, None, None]
115 self.current_refidx = 0
116 self.current_window = 1
117 self.countdown = config.plugins.Mosaic.countdown.value
119 self.state = self.PLAY
121 self["playState"] = Pixmap()
122 for i in range(1, 10):
123 self["window" + str(i)] = Pixmap()
124 self["video" + str(i)] = VideoWindow(decoder = 0)
125 self["video" + str(i)].hide()
126 self["channel" + str(i)] = Label("")
127 self["event" + str(i)] = Label("")
128 self["event" + str(i)].hide()
129 self["video1"].decoder = 0
130 self["video1"].show()
131 self["countdown"] = Label()
132 self.updateCountdownLabel()
133 self["count"] = Label()
135 self["actions"] = NumberActionMap(["MosaicActions"],
138 "cancel": self.closeWithOldService,
140 "yellow": self.pause,
141 "channelup": self.countdownPlus,
142 "channeldown": self.countdownMinus,
143 "1": self.numberPressed,
144 "2": self.numberPressed,
145 "3": self.numberPressed,
146 "4": self.numberPressed,
147 "5": self.numberPressed,
148 "6": self.numberPressed,
149 "7": self.numberPressed,
150 "8": self.numberPressed,
151 "9": self.numberPressed
154 self.updateTimer = eTimer()
155 self.updateTimer.timeout.get().append(self.updateCountdown)
156 self.checkTimer = eTimer()
157 self.checkTimer.timeout.get().append(self.checkGrab)
158 self.checkTimer.start(500, 1)
161 # Start the first service in the bouquet and show the service-name
162 ref = self.ref_list[0]
163 self.window_refs[0] = ref
164 info = self.serviceHandler.info(ref)
165 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
166 event_name = self.getEventName(info, ref)
167 self["channel1"].setText(name)
168 self["event1"].setText(event_name)
169 self.session.nav.playService(ref)
170 self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
171 self["playState"].instance.setPixmap(playingIcon)
172 # Start updating the video-screenshots
173 self.updateTimer.start(1, 1)
175 def exit(self, callback=None):
176 self.deleteConsoleCallbacks()
179 def deleteConsoleCallbacks(self):
180 if self.Console.appContainers.has_key(self.consoleCmd):
181 del self.Console.appContainers[self.consoleCmd].dataAvail[:]
182 del self.Console.appContainers[self.consoleCmd].appClosed[:]
183 del self.Console.appContainers[self.consoleCmd]
184 del self.Console.extra_args[self.consoleCmd]
185 del self.Console.callbacks[self.consoleCmd]
187 def closeWithOldService(self):
188 self.session.nav.playService(self.oldService)
189 self.deleteConsoleCallbacks()
192 def numberPressed(self, number):
193 ref = self.window_refs[number-1]
195 self.session.nav.playService(ref)
196 self.deleteConsoleCallbacks()
200 if self.working == False and self.state == self.PAUSE:
201 self.state = self.PLAY
202 self.updateTimer.start(1000, 1)
203 self["playState"].instance.setPixmap(playingIcon)
206 if self.working == False and self.state == self.PLAY:
207 self.state = self.PAUSE
208 self.updateTimer.stop()
209 self["playState"].instance.setPixmap(pausedIcon)
211 def countdownPlus(self):
212 self.changeCountdown(1)
214 def countdownMinus(self):
215 self.changeCountdown(-1)
217 def changeCountdown(self, direction):
218 if self.working == False:
219 configNow = config.plugins.Mosaic.countdown.value
220 configNow += direction
222 if configNow < config_limits[0]:
223 configNow = config_limits[0]
224 elif configNow > config_limits[1]:
225 configNow = config_limits[1]
227 config.plugins.Mosaic.countdown.value = configNow
228 config.plugins.Mosaic.countdown.save()
230 self.updateCountdownLabel()
232 def makeNextScreenshot(self):
235 self.Console = Console()
236 self.consoleCmd = "%s -v -r 180 -l -j 100 %s" % (grab_binary, grab_picture)
237 self.Console.ePopen(self.consoleCmd, self.showNextScreenshot)
239 def showNextScreenshot(self, result, retval, extra_args):
241 # Show screenshot in the current window
242 pic = LoadPixmap(grab_picture)
243 self["window" + str(self.current_window)].instance.setPixmap(pic)
245 # Hide current video-window and show the running event-name
246 self["video" + str(self.current_window)].hide()
247 self["event" + str(self.current_window)].show()
250 self.current_refidx += 1
251 if self.current_refidx > (len(self.ref_list) -1):
252 self.current_refidx = 0
255 ref = self.ref_list[self.current_refidx]
256 info = self.serviceHandler.info(ref)
257 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
258 event_name = self.getEventName(info, ref)
259 self.session.nav.playService(ref)
261 # Get next window index
262 self.current_window += 1
263 if self.current_window > 9:
264 self.current_window = 1
267 self.window_refs[self.current_window-1] = ref
269 # Save the event-name and hide the label
270 self["event" + str(self.current_window)].hide()
271 self["event" + str(self.current_window)].setText(event_name)
273 # Show the new video-window
274 self["video" + str(self.current_window)].show()
275 self["video" + str(self.current_window)].decoder = 0
277 # Show the servicename
278 self["channel" + str(self.current_window)].setText(name)
279 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
283 self.updateTimer.start(1, 1)
285 print "[Mosaic] retval: %d result: %s" % (retval, result)
288 f = open(grab_errorlog, "w")
289 f.write("retval: %d\nresult: %s" % (retval, result))
294 self.session.openWithCallback(self.exit, MessageBox, _("Error while creating screenshot. You need grab version 0.8 or higher!"), MessageBox.TYPE_ERROR, timeout=5)
296 def updateCountdown(self, callback=None):
298 self.updateCountdownLabel()
299 if self.countdown == 0:
300 self.countdown = config.plugins.Mosaic.countdown.value
302 self.makeNextScreenshot()
304 self.updateTimer.start(1000, 1)
306 def updateCountdownLabel(self):
307 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
309 def getEventName(self, info, ref):
310 event = info.getEvent(ref)
311 if event is not None:
312 eventName = event.getEventName()
313 if eventName is None:
319 ################################################
320 # Most stuff stolen from the GraphMultiEPG
324 BouquetSelectorScreen = None
326 def getBouquetServices(bouquet):
328 Servicelist = eServiceCenter.getInstance().list(bouquet)
329 if Servicelist is not None:
331 service = Servicelist.getNext()
332 if not service.valid():
334 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
336 services.append(service)
339 def closeBouquetSelectorScreen(ret=None):
340 if BouquetSelectorScreen is not None:
341 BouquetSelectorScreen.close()
343 def openMosaic(bouquet):
344 if bouquet is not None:
345 services = getBouquetServices(bouquet)
347 Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
349 def main(session, servicelist, **kwargs):
353 Servicelist = servicelist
354 global BouquetSelectorScreen
356 bouquets = Servicelist.getBouquetList()
357 if bouquets is not None:
358 if len(bouquets) == 1:
359 openMosaic(bouquets[0][1])
360 elif len(bouquets) > 1:
361 BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
363 def Plugins(**kwargs):
364 return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)