Mon, 16 Jan 2012 23:08:14 +0100
Inconclusively complete possibly missing fields. This change introduces
inconsistencies difficult to correct given incomplete documentation of
IPKG and OPKG packaging standards.
1 # -*- coding: UTF-8 -*-
2 # Mosaic by AliAbdul
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
18 import gettext
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]
37 gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
38 gettext.textdomain("enigma2")
39 gettext.bindtextdomain("Mosaic", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/Mosaic/locale/"))
41 def _(txt):
42 t = gettext.dgettext("Mosaic", txt)
43 if t == txt:
44 t = gettext.gettext(txt)
45 return t
47 ################################################
49 class Mosaic(Screen):
50 PLAY = 0
51 PAUSE = 1
53 desktop = getDesktop(0)
54 size = desktop.size()
55 width = size.width()
56 height = size.height()
57 windowWidth = width / 4
58 windowHeight = height / 4
60 positions = []
61 x = 80
62 y = 40
63 for i in range(1, 10):
64 positions.append([x, y])
65 x += windowWidth
66 x += ((width - 160) - (windowWidth * 3)) / 2
67 if (i == 3) or (i == 6):
68 y = y + windowHeight + 40
69 x = 80
71 skin = ""
72 skin += """<screen position="0,0" size="%d,%d" title="Mosaic" flags="wfNoBorder" backgroundColor="#000000" >""" % (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)
84 skin += """<widget name="channel1" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[0][0]-2, positions[0][1]-18, windowWidth-4)
85 skin += """<widget name="channel2" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[1][0]-2, positions[1][1]-18, windowWidth-4)
86 skin += """<widget name="channel3" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[2][0]-2, positions[2][1]-18, windowWidth-4)
87 skin += """<widget name="channel4" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[3][0]-2, positions[3][1]-18, windowWidth-4)
88 skin += """<widget name="channel5" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[4][0]-2, positions[4][1]-18, windowWidth-4)
89 skin += """<widget name="channel6" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[5][0]-2, positions[5][1]-18, windowWidth-4)
90 skin += """<widget name="channel7" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[6][0]-2, positions[6][1]-18, windowWidth-4)
91 skin += """<widget name="channel8" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[7][0]-2, positions[7][1]-18, windowWidth-4)
92 skin += """<widget name="channel9" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[8][0]-2, positions[8][1]-18, windowWidth-4)
94 skin += """<widget name="window1" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[0][0]-2, positions[0][1]+1, windowWidth, windowHeight)
95 skin += """<widget name="window2" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[1][0]-2, positions[1][1]+1, windowWidth, windowHeight)
96 skin += """<widget name="window3" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[2][0]-2, positions[2][1]+1, windowWidth, windowHeight)
97 skin += """<widget name="window4" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[3][0]-2, positions[3][1]+1, windowWidth, windowHeight)
98 skin += """<widget name="window5" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[4][0]-2, positions[4][1]+1, windowWidth, windowHeight)
99 skin += """<widget name="window6" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[5][0]-2, positions[5][1]+1, windowWidth, windowHeight)
100 skin += """<widget name="window7" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[6][0]-2, positions[6][1]+1, windowWidth, windowHeight)
101 skin += """<widget name="window8" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[7][0]-2, positions[7][1]+1, windowWidth, windowHeight)
102 skin += """<widget name="window9" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[8][0]-2, positions[8][1]+1, windowWidth, windowHeight)
104 # Playing video moving pictures
105 skin += """<widget name="video1" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[0][0]-2, positions[0][1]+1, windowWidth, windowHeight)
106 skin += """<widget name="video2" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[1][0]-2, positions[1][1]+1, windowWidth, windowHeight)
107 skin += """<widget name="video3" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[2][0]-2, positions[2][1]+1, windowWidth, windowHeight)
108 skin += """<widget name="video4" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[3][0]-2, positions[3][1]+1, windowWidth, windowHeight)
109 skin += """<widget name="video5" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[4][0]-2, positions[4][1]+1, windowWidth, windowHeight)
110 skin += """<widget name="video6" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[5][0]-2, positions[5][1]+1, windowWidth, windowHeight)
111 skin += """<widget name="video7" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[6][0]-2, positions[6][1]+1, windowWidth, windowHeight)
112 skin += """<widget name="video8" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[7][0]-2, positions[7][1]+1, windowWidth, windowHeight)
113 skin += """<widget name="video9" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[8][0]-2, positions[8][1]+1, windowWidth, windowHeight)
115 # Zweite Zeile Sendung
116 skin += """<widget name="event1" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth)
117 skin += """<widget name="event2" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth)
118 skin += """<widget name="event3" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth)
119 skin += """<widget name="event4" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth)
120 skin += """<widget name="event5" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth)
121 skin += """<widget name="event6" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth)
122 skin += """<widget name="event7" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth)
123 skin += """<widget name="event8" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth)
124 skin += """<widget name="event9" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth)
126 skin += """<widget name="countdown" position="80,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#448866" />""" % (height-40, windowWidth)
127 skin += """<widget name="count" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#886644" halign="right" />
128 </screen>""" % (positions[2][0] ,height-40, windowWidth)
130 def __init__(self, session, services):
131 Screen.__init__(self, session)
133 self.session = session
134 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
135 self.consoleCmd = ""
136 self.Console = Console()
137 self.serviceHandler = eServiceCenter.getInstance()
138 self.ref_list = services
139 self.window_refs = [None, None, None, None, None, None, None, None, None]
140 self.current_refidx = 0
141 self.current_window = 1
142 self.countdown = config.plugins.Mosaic.countdown.value
143 self.working = False
144 self.state = self.PLAY
146 self["playState"] = Pixmap()
147 for i in range(1, 10):
148 self["window" + str(i)] = Pixmap()
149 self["video" + str(i)] = VideoWindow(decoder=0, fb_width=self.width, fb_height=self.height)
150 self["video" + str(i)].hide()
151 self["channel" + str(i)] = Label("")
152 self["event" + str(i)] = Label("")
153 self["event" + str(i)].hide()
154 self["video1"].decoder = 0
155 self["video1"].show()
156 self["countdown"] = Label()
157 self.updateCountdownLabel()
158 self["count"] = Label()
160 self["actions"] = NumberActionMap(["MosaicActions"],
161 {
162 "ok": self.exit,
163 "cancel": self.closeWithOldService,
164 "green": self.play,
165 "yellow": self.pause,
166 "channelup": self.countdownPlus,
167 "channeldown": self.countdownMinus,
168 "1": self.numberPressed,
169 "2": self.numberPressed,
170 "3": self.numberPressed,
171 "4": self.numberPressed,
172 "5": self.numberPressed,
173 "6": self.numberPressed,
174 "7": self.numberPressed,
175 "8": self.numberPressed,
176 "9": self.numberPressed
177 }, prio=-1)
179 self.updateTimer = eTimer()
180 self.updateTimer.callback.append(self.updateCountdown)
181 self.checkTimer = eTimer()
182 self.checkTimer.callback.append(self.checkGrab)
183 self.checkTimer.start(500, 1)
185 def checkGrab(self):
186 # Start the first service in the bouquet and show the service-name
187 ref = self.ref_list[0]
188 self.window_refs[0] = ref
189 info = self.serviceHandler.info(ref)
190 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
191 event_name = self.getEventName(info, ref)
192 self["channel1"].setText(name)
193 self["event1"].setText(event_name)
194 self.session.nav.playService(ref)
195 self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
196 self["playState"].instance.setPixmap(playingIcon)
197 # Start updating the video-screenshots
198 self.updateTimer.start(1, 1)
200 def exit(self, callback=None):
201 self.deleteConsoleCallbacks()
202 self.close()
204 def deleteConsoleCallbacks(self):
205 if self.Console.appContainers.has_key(self.consoleCmd):
206 del self.Console.appContainers[self.consoleCmd].dataAvail[:]
207 del self.Console.appContainers[self.consoleCmd].appClosed[:]
208 del self.Console.appContainers[self.consoleCmd]
209 del self.Console.extra_args[self.consoleCmd]
210 del self.Console.callbacks[self.consoleCmd]
212 def closeWithOldService(self):
213 self.session.nav.playService(self.oldService)
214 self.deleteConsoleCallbacks()
215 self.close()
217 def numberPressed(self, number):
218 ref = self.window_refs[number-1]
219 if ref is not None:
220 self.session.nav.playService(ref)
221 self.deleteConsoleCallbacks()
222 self.close()
224 def play(self):
225 if self.working == False and self.state == self.PAUSE:
226 self.state = self.PLAY
227 self.updateTimer.start(1000, 1)
228 self["playState"].instance.setPixmap(playingIcon)
230 def pause(self):
231 if self.working == False and self.state == self.PLAY:
232 self.state = self.PAUSE
233 self.updateTimer.stop()
234 self["playState"].instance.setPixmap(pausedIcon)
236 def countdownPlus(self):
237 self.changeCountdown(1)
239 def countdownMinus(self):
240 self.changeCountdown(-1)
242 def changeCountdown(self, direction):
243 if self.working == False:
244 configNow = config.plugins.Mosaic.countdown.value
245 configNow += direction
247 if configNow < config_limits[0]:
248 configNow = config_limits[0]
249 elif configNow > config_limits[1]:
250 configNow = config_limits[1]
252 config.plugins.Mosaic.countdown.value = configNow
253 config.plugins.Mosaic.countdown.save()
255 self.updateCountdownLabel()
257 def makeNextScreenshot(self):
258 # Grab video
259 if not self.Console:
260 self.Console = Console()
261 self.consoleCmd = "%s -v -r %d -j 100 %s" % (grab_binary, self.windowWidth, grab_picture)
262 self.Console.ePopen(self.consoleCmd, self.showNextScreenshot)
264 def showNextScreenshot(self, result, retval, extra_args):
265 if retval == 0:
266 # Show screenshot in the current window
267 pic = LoadPixmap(grab_picture)
268 self["window" + str(self.current_window)].instance.setPixmap(pic)
270 # Hide current video-window and show the running event-name
271 self["video" + str(self.current_window)].hide()
272 self["event" + str(self.current_window)].show()
274 # Get next ref
275 self.current_refidx += 1
276 if self.current_refidx > (len(self.ref_list) -1):
277 self.current_refidx = 0
279 # Play next ref
280 ref = self.ref_list[self.current_refidx]
281 info = self.serviceHandler.info(ref)
282 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
283 event_name = self.getEventName(info, ref)
284 self.session.nav.playService(ref)
286 # Get next window index
287 self.current_window += 1
288 if self.current_window > 9:
289 self.current_window = 1
291 # Save the ref
292 self.window_refs[self.current_window-1] = ref
294 # Save the event-name and hide the label
295 self["event" + str(self.current_window)].hide()
296 self["event" + str(self.current_window)].setText(event_name)
298 # Show the new video-window
299 self["video" + str(self.current_window)].show()
300 self["video" + str(self.current_window)].decoder = 0
302 # Show the servicename
303 self["channel" + str(self.current_window)].setText(name)
304 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
306 # Restart timer
307 self.working = False
308 self.updateTimer.start(1, 1)
309 else:
310 print "[Mosaic] retval: %d result: %s" % (retval, result)
312 try:
313 f = open(grab_errorlog, "w")
314 f.write("retval: %d\nresult: %s" % (retval, result))
315 f.close()
316 except:
317 pass
319 self.session.openWithCallback(self.exit, MessageBox, _("Error while creating screenshot. You need grab version 0.8 or higher!"), MessageBox.TYPE_ERROR, timeout=5)
321 def updateCountdown(self, callback=None):
322 self.countdown -= 1
323 self.updateCountdownLabel()
324 if self.countdown == 0:
325 self.countdown = config.plugins.Mosaic.countdown.value
326 self.working = True
327 self.makeNextScreenshot()
328 else:
329 self.updateTimer.start(1000, 1)
331 def updateCountdownLabel(self):
332 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
334 def getEventName(self, info, ref):
335 event = info.getEvent(ref)
336 if event is not None:
337 eventName = event.getEventName()
338 if eventName is None:
339 eventName = ""
340 else:
341 eventName = ""
342 return eventName
344 ################################################
345 # Most stuff stolen from the GraphMultiEPG
347 Session = None
348 Servicelist = None
349 BouquetSelectorScreen = None
351 def getBouquetServices(bouquet):
352 services = []
353 Servicelist = eServiceCenter.getInstance().list(bouquet)
354 if Servicelist is not None:
355 while True:
356 service = Servicelist.getNext()
357 if not service.valid():
358 break
359 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
360 continue
361 services.append(service)
362 return services
364 def closeBouquetSelectorScreen(ret=None):
365 if BouquetSelectorScreen is not None:
366 BouquetSelectorScreen.close()
368 def openMosaic(bouquet):
369 if bouquet is not None:
370 services = getBouquetServices(bouquet)
371 if len(services):
372 Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
374 def main(session, servicelist, **kwargs):
375 global Session
376 Session = session
377 global Servicelist
378 Servicelist = servicelist
379 global BouquetSelectorScreen
381 bouquets = Servicelist.getBouquetList()
382 if bouquets is not None:
383 if len(bouquets) == 1:
384 openMosaic(bouquets[0][1])
385 elif len(bouquets) > 1:
386 BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
388 def Plugins(**kwargs):
389 return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)